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