1# Copyright © 2021 Collabora, Ltd. 2# Author: Antonio Caggiano <antonio.caggiano@collabora.com> 3 4# Permission is hereby granted, free of charge, to any person obtaining a copy 5# of this software and associated documentation files (the "Software"), to deal 6# in the Software without restriction, including without limitation the rights 7# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8# copies of the Software, and to permit persons to whom the Software is 9# furnished to do so, subject to the following conditions: 10 11# The above copyright notice and this permission notice shall be included in 12# all copies or substantial portions of the Software. 13 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20# THE SOFTWARE. 21 22import argparse 23import textwrap 24import os 25 26import xml.etree.ElementTree as et 27 28 29class SourceFile: 30 def __init__(self, filename): 31 self.file = open(filename, 'w') 32 self._indent = 0 33 34 def write(self, *args): 35 code = ' '.join(map(str,args)) 36 for line in code.splitlines(): 37 text = ''.rjust(self._indent) + line 38 self.file.write(text.rstrip() + "\n") 39 40 def indent(self, n): 41 self._indent += n 42 43 def outdent(self, n): 44 self._indent -= n 45 46 47class Counter: 48 # category Category owning the counter 49 # xml XML representation of itself 50 def __init__(self, category, xml): 51 self.category = category 52 self.xml = xml 53 self.name = self.xml.get("name") 54 self.desc = self.xml.get("description") 55 self.units = self.xml.get("units") 56 self.offset = int(self.xml.get("offset")) 57 self.underscore_name = self.xml.get("counter").lower() 58 59 60class Category: 61 # product Product owning the gategory 62 # xml XML representation of itself 63 def __init__(self, product, xml): 64 self.product = product 65 self.xml = xml 66 self.name = self.xml.get("name") 67 self.underscore_name = self.name.lower().replace(' ', '_') 68 69 xml_counters = self.xml.findall("event") 70 self.counters = [] 71 for xml_counter in xml_counters: 72 self.counters.append(Counter(self, xml_counter)) 73 74 75# Wraps an entire *.xml file. 76class Product: 77 def __init__(self, filename): 78 self.filename = filename 79 self.xml = et.parse(self.filename) 80 self.id = self.xml.getroot().get('id').lower() 81 self.categories = [] 82 83 for xml_cat in self.xml.findall(".//category"): 84 self.categories.append(Category(self, xml_cat)) 85 86 87def main(): 88 parser = argparse.ArgumentParser() 89 parser.add_argument("--header", help="Header file to write", required=True) 90 parser.add_argument("--code", help="C file to write", required=True) 91 parser.add_argument("xml_files", nargs='+', help="List of xml metrics files to process") 92 93 args = parser.parse_args() 94 95 c = SourceFile(args.code) 96 h = SourceFile(args.header) 97 98 prods = [] 99 for xml_file in args.xml_files: 100 prods.append(Product(xml_file)) 101 102 tab_size = 3 103 104 copyright = textwrap.dedent("""\ 105 /* Autogenerated file, DO NOT EDIT manually! generated by {} 106 * 107 * Copyright © 2021 Arm Limited 108 * Copyright © 2021 Collabora Ltd. 109 * 110 * Permission is hereby granted, free of charge, to any person obtaining a 111 * copy of this software and associated documentation files (the "Software"), 112 * to deal in the Software without restriction, including without limitation 113 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 114 * and/or sell copies of the Software, and to permit persons to whom the 115 * Software is furnished to do so, subject to the following conditions: 116 * 117 * The above copyright notice and this permission notice (including the next 118 * paragraph) shall be included in all copies or substantial portions of the 119 * Software. 120 * 121 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 122 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 123 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 124 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 125 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 126 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 127 * DEALINGS IN THE SOFTWARE. 128 */ 129 130 """).format(os.path.basename(__file__)) 131 132 h.write(copyright) 133 h.write(textwrap.dedent("""\ 134 #ifndef PAN_PERF_METRICS_H 135 #define PAN_PERF_METRICS_H 136 137 #include "perf/pan_perf.h" 138 139 """)) 140 141 c.write(copyright) 142 c.write("#include \"" + os.path.basename(args.header) + "\"") 143 c.write(textwrap.dedent("""\ 144 145 #include <util/macros.h> 146 """)) 147 148 for prod in prods: 149 h.write("extern const struct panfrost_perf_config panfrost_perf_config_%s;\n" % prod.id) 150 151 for prod in prods: 152 c.write(textwrap.dedent(""" 153 static void UNUSED 154 static_asserts_%s(void) 155 { 156 """ % prod.id)) 157 c.indent(tab_size) 158 159 n_categories = len(prod.categories) 160 c.write("STATIC_ASSERT(%u <= PAN_PERF_MAX_CATEGORIES);" % n_categories) 161 n_counters = 0 162 for category in prod.categories: 163 category_counters_count = len(category.counters) 164 c.write("STATIC_ASSERT(%u <= PAN_PERF_MAX_COUNTERS);" % category_counters_count) 165 n_counters += category_counters_count 166 167 c.outdent(tab_size) 168 c.write("}\n") 169 170 171 current_struct_name = "panfrost_perf_config_%s" % prod.id 172 c.write("\nconst struct panfrost_perf_config %s = {" % current_struct_name) 173 c.indent(tab_size) 174 175 c.write(".n_categories = %u," % len(prod.categories)) 176 177 c.write(".categories = {") 178 c.indent(tab_size) 179 180 counter_id = 0 181 182 for i in range(0, len(prod.categories)): 183 category = prod.categories[i] 184 185 c.write("{") 186 c.indent(tab_size) 187 c.write(".name = \"%s\"," % (category.name)) 188 c.write(".n_counters = %u," % (len(category.counters))) 189 c.write(".counters = {") 190 c.indent(tab_size) 191 192 for j in range(0, len(category.counters)): 193 counter = category.counters[j] 194 195 assert counter_id < n_counters 196 c.write("{") 197 c.indent(tab_size) 198 199 c.write(".name = \"%s\"," % (counter.name)) 200 c.write(".desc = \"%s\"," % (counter.desc.replace("\\", "\\\\"))) 201 c.write(".symbol_name = \"%s\"," % (counter.underscore_name)) 202 c.write(".units = PAN_PERF_COUNTER_UNITS_%s," % (counter.units.upper())) 203 c.write(".offset = %u," % (counter.offset)) 204 c.write(".category = &%s.categories[%u]," % (current_struct_name, i)) 205 206 c.outdent(tab_size) 207 c.write("}, // counter") 208 209 counter_id += 1 210 211 c.outdent(tab_size) 212 c.write("}, // counters") 213 214 c.outdent(tab_size) 215 c.write("}, // category") 216 217 c.outdent(tab_size) 218 c.write("}, // categories") 219 220 c.outdent(tab_size) 221 c.write("}; // %s\n" % current_struct_name) 222 223 h.write("\n#endif // PAN_PERF_METRICS_H") 224 225 226if __name__ == '__main__': 227 main() 228