| # Copyright © 2021 Collabora, Ltd. |
| # Author: Antonio Caggiano <antonio.caggiano@collabora.com> |
| |
| # 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 <util/macros.h> |
| """)) |
| |
| 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() |