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.name = self.xml.getroot().get('id') 81 self.id = self.name.lower() 82 self.categories = [] 83 84 for xml_cat in self.xml.findall(".//category"): 85 self.categories.append(Category(self, xml_cat)) 86 87 88def main(): 89 parser = argparse.ArgumentParser() 90 parser.add_argument("--header", help="Header file to write", required=True) 91 parser.add_argument("--code", help="C file to write", required=True) 92 parser.add_argument("xml_files", nargs='+', help="List of xml metrics files to process") 93 94 args = parser.parse_args() 95 96 c = SourceFile(args.code) 97 h = SourceFile(args.header) 98 99 prods = [] 100 for xml_file in args.xml_files: 101 prods.append(Product(xml_file)) 102 103 tab_size = 3 104 105 copyright = textwrap.dedent("""\ 106 /* Autogenerated file, DO NOT EDIT manually! generated by {} 107 * 108 * Copyright © 2021 Arm Limited 109 * Copyright © 2021 Collabora Ltd. 110 * 111 * Permission is hereby granted, free of charge, to any person obtaining a 112 * copy of this software and associated documentation files (the "Software"), 113 * to deal in the Software without restriction, including without limitation 114 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 115 * and/or sell copies of the Software, and to permit persons to whom the 116 * Software is furnished to do so, subject to the following conditions: 117 * 118 * The above copyright notice and this permission notice (including the next 119 * paragraph) shall be included in all copies or substantial portions of the 120 * Software. 121 * 122 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 123 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 124 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 125 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 126 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 127 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 128 * DEALINGS IN THE SOFTWARE. 129 */ 130 131 """).format(os.path.basename(__file__)) 132 133 h.write(copyright) 134 h.write(textwrap.dedent("""\ 135 #ifndef PAN_PERF_METRICS_H 136 #define PAN_PERF_METRICS_H 137 138 #include "perf/pan_perf.h" 139 140 """)) 141 142 c.write(copyright) 143 c.write("#include \"" + os.path.basename(args.header) + "\"") 144 c.write(textwrap.dedent("""\ 145 146 #include <util/macros.h> 147 """)) 148 149 for prod in prods: 150 c.write(textwrap.dedent(""" 151 static void UNUSED 152 static_asserts_%s(void) 153 { 154 """ % prod.id)) 155 c.indent(tab_size) 156 157 n_categories = len(prod.categories) 158 c.write("STATIC_ASSERT(%u <= PAN_PERF_MAX_CATEGORIES);" % n_categories) 159 n_counters = 0 160 for category in prod.categories: 161 category_counters_count = len(category.counters) 162 c.write("STATIC_ASSERT(%u <= PAN_PERF_MAX_COUNTERS);" % category_counters_count) 163 n_counters += category_counters_count 164 165 c.outdent(tab_size) 166 c.write("}\n") 167 168 169 current_struct_name = "panfrost_perf_config_%s" % prod.id 170 c.write("\nconst struct panfrost_perf_config %s = {" % current_struct_name) 171 c.indent(tab_size) 172 173 c.write(".name = \"%s\"," % prod.name) 174 c.write(".n_categories = %u," % len(prod.categories)) 175 176 c.write(".categories = {") 177 c.indent(tab_size) 178 179 counter_id = 0 180 181 for i in range(0, len(prod.categories)): 182 category = prod.categories[i] 183 184 c.write("{") 185 c.indent(tab_size) 186 c.write(".name = \"%s\"," % (category.name)) 187 c.write(".n_counters = %u," % (len(category.counters))) 188 c.write(".counters = {") 189 c.indent(tab_size) 190 191 for j in range(0, len(category.counters)): 192 counter = category.counters[j] 193 194 assert counter_id < n_counters 195 c.write("{") 196 c.indent(tab_size) 197 198 c.write(".name = \"%s\"," % (counter.name)) 199 c.write(".desc = \"%s\"," % (counter.desc.replace("\\", "\\\\"))) 200 c.write(".symbol_name = \"%s\"," % (counter.underscore_name)) 201 c.write(".units = PAN_PERF_COUNTER_UNITS_%s," % (counter.units.upper())) 202 c.write(".offset = %u," % (counter.offset)) 203 c.write(".category_index = %u," % i) 204 205 c.outdent(tab_size) 206 c.write("}, // counter") 207 208 counter_id += 1 209 210 c.outdent(tab_size) 211 c.write("}, // counters") 212 213 c.outdent(tab_size) 214 c.write("}, // category") 215 216 c.outdent(tab_size) 217 c.write("}, // categories") 218 219 c.outdent(tab_size) 220 c.write("}; // %s\n" % current_struct_name) 221 222 h.write("extern const struct panfrost_perf_config * panfrost_perf_configs[%u];\n" % len(prods)) 223 224 c.write("\nconst struct panfrost_perf_config * panfrost_perf_configs[] = {") 225 c.indent(tab_size) 226 for prod in prods: 227 c.write("&panfrost_perf_config_%s," % prod.id) 228 c.outdent(tab_size) 229 c.write("};") 230 231 h.write("\n#endif // PAN_PERF_METRICS_H") 232 233 234if __name__ == '__main__': 235 main() 236