# Copyright © 2021 Collabora, Ltd. # Author: Antonio Caggiano # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import argparse import textwrap import os import xml.etree.ElementTree as et class SourceFile: def __init__(self, filename): self.file = open(filename, 'w') self._indent = 0 def write(self, *args): code = ' '.join(map(str,args)) for line in code.splitlines(): text = ''.rjust(self._indent) + line self.file.write(text.rstrip() + "\n") def indent(self, n): self._indent += n def outdent(self, n): self._indent -= n class Counter: # category Category owning the counter # xml XML representation of itself def __init__(self, category, xml): self.category = category self.xml = xml self.name = self.xml.get("name") self.desc = self.xml.get("description") self.units = self.xml.get("units") self.offset = int(self.xml.get("offset")) self.underscore_name = self.xml.get("counter").lower() class Category: # product Product owning the gategory # xml XML representation of itself def __init__(self, product, xml): self.product = product self.xml = xml self.name = self.xml.get("name") self.underscore_name = self.name.lower().replace(' ', '_') xml_counters = self.xml.findall("event") self.counters = [] for xml_counter in xml_counters: self.counters.append(Counter(self, xml_counter)) # Wraps an entire *.xml file. class Product: def __init__(self, filename): self.filename = filename self.xml = et.parse(self.filename) self.name = self.xml.getroot().get('id') self.id = self.name.lower() self.categories = [] for xml_cat in self.xml.findall(".//category"): self.categories.append(Category(self, xml_cat)) def main(): parser = argparse.ArgumentParser() parser.add_argument("--header", help="Header file to write", required=True) parser.add_argument("--code", help="C file to write", required=True) parser.add_argument("xml_files", nargs='+', help="List of xml metrics files to process") args = parser.parse_args() c = SourceFile(args.code) h = SourceFile(args.header) prods = [] for xml_file in args.xml_files: prods.append(Product(xml_file)) tab_size = 3 copyright = textwrap.dedent("""\ /* Autogenerated file, DO NOT EDIT manually! generated by {} * * Copyright © 2021 Arm Limited * Copyright © 2021 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ """).format(os.path.basename(__file__)) h.write(copyright) h.write(textwrap.dedent("""\ #ifndef PAN_PERF_METRICS_H #define PAN_PERF_METRICS_H #include "perf/pan_perf.h" """)) c.write(copyright) c.write("#include \"" + os.path.basename(args.header) + "\"") c.write(textwrap.dedent("""\ #include """)) for prod in prods: c.write(textwrap.dedent(""" static void UNUSED static_asserts_%s(void) { """ % prod.id)) c.indent(tab_size) n_categories = len(prod.categories) c.write("STATIC_ASSERT(%u <= PAN_PERF_MAX_CATEGORIES);" % n_categories) n_counters = 0 for category in prod.categories: category_counters_count = len(category.counters) c.write("STATIC_ASSERT(%u <= PAN_PERF_MAX_COUNTERS);" % category_counters_count) n_counters += category_counters_count c.outdent(tab_size) c.write("}\n") current_struct_name = "panfrost_perf_config_%s" % prod.id c.write("\nconst struct panfrost_perf_config %s = {" % current_struct_name) c.indent(tab_size) c.write(".name = \"%s\"," % prod.name) c.write(".n_categories = %u," % len(prod.categories)) c.write(".categories = {") c.indent(tab_size) counter_id = 0 for i in range(0, len(prod.categories)): category = prod.categories[i] c.write("{") c.indent(tab_size) c.write(".name = \"%s\"," % (category.name)) c.write(".n_counters = %u," % (len(category.counters))) c.write(".counters = {") c.indent(tab_size) for j in range(0, len(category.counters)): counter = category.counters[j] assert counter_id < n_counters c.write("{") c.indent(tab_size) c.write(".name = \"%s\"," % (counter.name)) c.write(".desc = \"%s\"," % (counter.desc.replace("\\", "\\\\"))) c.write(".symbol_name = \"%s\"," % (counter.underscore_name)) c.write(".units = PAN_PERF_COUNTER_UNITS_%s," % (counter.units.upper())) c.write(".offset = %u," % (counter.offset)) c.write(".category_index = %u," % i) c.outdent(tab_size) c.write("}, // counter") counter_id += 1 c.outdent(tab_size) c.write("}, // counters") c.outdent(tab_size) c.write("}, // category") c.outdent(tab_size) c.write("}, // categories") c.outdent(tab_size) c.write("}; // %s\n" % current_struct_name) h.write("extern const struct panfrost_perf_config * panfrost_perf_configs[%u];\n" % len(prods)) c.write("\nconst struct panfrost_perf_config * panfrost_perf_configs[] = {") c.indent(tab_size) for prod in prods: c.write("&panfrost_perf_config_%s," % prod.id) c.outdent(tab_size) c.write("};") h.write("\n#endif // PAN_PERF_METRICS_H") if __name__ == '__main__': main()