[igt-dev] [PATCH i-g-t 2/2] lib/i915/perf: break generated code in separate files

Lionel Landwerlin lionel.g.landwerlin at intel.com
Tue Mar 10 16:29:46 UTC 2020


Initially all the generated code was per generation. Eventually we
grouped it into a single file to reuse as much as possible equation
code (this reduce binary size by a factor). So many equations are just
the same from generation to generation.

But this generated file is 200k lines long...

This change puts all the metrics into a single file and then breaks
down the metric sets per generation.

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
---
 lib/i915/perf-configs/perf-codegen.py | 311 +++++++++++++++++---------
 lib/i915/perf.c                       |  18 +-
 lib/meson.build                       |  21 +-
 3 files changed, 241 insertions(+), 109 deletions(-)

diff --git a/lib/i915/perf-configs/perf-codegen.py b/lib/i915/perf-configs/perf-codegen.py
index ac3ad683..e001fc84 100755
--- a/lib/i915/perf-configs/perf-codegen.py
+++ b/lib/i915/perf-configs/perf-codegen.py
@@ -252,33 +252,51 @@ def data_type_to_ctype(ret_type):
 
 
 def output_counter_read(gen, set, counter):
+    if counter.read_hash in hashed_funcs:
+        return
+
     c("\n")
     c("/* {0} :: {1} */".format(set.name, counter.get('name')))
 
+    ret_type = counter.get('data_type')
+    ret_ctype = data_type_to_ctype(ret_type)
+    read_eq = counter.get('equation')
+
+    c(ret_ctype)
+    c(counter.read_sym + "(const struct intel_perf *perf,\n")
+    c.indent(len(counter.read_sym) + 1)
+    c("const struct intel_perf_metric_set *metric_set,\n")
+    c("uint64_t *accumulator)\n")
+    c.outdent(len(counter.read_sym) + 1)
+
+    c("{")
+    c.indent(4)
+
+    output_rpn_equation_code(set, counter, read_eq)
+
+    c.outdent(4)
+    c("}")
+
+    hashed_funcs[counter.read_hash] = counter.read_sym
+
+
+def output_counter_read_definition(gen, set, counter):
     if counter.read_hash in hashed_funcs:
-        c("#define %s \\" % counter.read_sym)
-        c.indent(4)
-        c("%s" % hashed_funcs[counter.read_hash])
-        c.outdent(4)
+        h("#define %s \\" % counter.read_sym)
+        h.indent(4)
+        h("%s" % hashed_funcs[counter.read_hash])
+        h.outdent(4)
     else:
         ret_type = counter.get('data_type')
         ret_ctype = data_type_to_ctype(ret_type)
         read_eq = counter.get('equation')
 
-        c("static " + ret_ctype)
-        c(counter.read_sym + "(const struct intel_perf *perf,\n")
-        c.indent(len(counter.read_sym) + 1)
-        c("const struct intel_perf_metric_set *metric_set,\n")
-        c("uint64_t *accumulator)\n")
-        c.outdent(len(counter.read_sym) + 1)
-
-        c("{")
-        c.indent(4)
-
-        output_rpn_equation_code(set, counter, read_eq)
-
-        c.outdent(4)
-        c("}")
+        h(ret_ctype)
+        h(counter.read_sym + "(const struct intel_perf *perf,\n")
+        h.indent(len(counter.read_sym) + 1)
+        h("const struct intel_perf_metric_set *metric_set,\n")
+        h("uint64_t *accumulator);\n")
+        h.outdent(len(counter.read_sym) + 1)
 
         hashed_funcs[counter.read_hash] = counter.read_sym
 
@@ -289,33 +307,57 @@ def output_counter_max(gen, set, counter):
     if not max_eq or max_eq == "100":
         return
 
+    if counter.max_hash in hashed_funcs:
+        return
+
     c("\n")
     c("/* {0} :: {1} */".format(set.name, counter.get('name')))
 
+    ret_type = counter.get('data_type')
+    ret_ctype = data_type_to_ctype(ret_type)
+
+    c(ret_ctype)
+    c(counter.max_sym + "(const struct intel_perf *perf,\n")
+    c.indent(len(counter.max_sym) + 1)
+    c("const struct intel_perf_metric_set *metric_set,\n")
+    c("uint64_t *accumulator)\n")
+    c.outdent(len(counter.max_sym) + 1)
+
+    c("{")
+    c.indent(4)
+
+    output_rpn_equation_code(set, counter, max_eq)
+
+    c.outdent(4)
+    c("}")
+
+    hashed_funcs[counter.max_hash] = counter.max_sym
+
+
+def output_counter_max_definition(gen, set, counter):
+    max_eq = counter.get('max_equation')
+
+    if not max_eq or max_eq == "100":
+        return
+
     if counter.max_hash in hashed_funcs:
-        c("#define %s \\" % counter.max_sym)
-        c.indent(4)
-        c("%s" % hashed_funcs[counter.max_hash])
-        c.outdent(4)
+        h("#define %s \\" % counter.max_sym)
+        h.indent(4)
+        h("%s" % hashed_funcs[counter.max_hash])
+        h.outdent(4)
+        h("\n")
     else:
         ret_type = counter.get('data_type')
         ret_ctype = data_type_to_ctype(ret_type)
 
-        c("static " + ret_ctype)
+        h(ret_ctype)
 
-        c(counter.max_sym + "(const struct intel_perf *perf,\n")
-        c.indent(len(counter.max_sym) + 1)
-        c("const struct intel_perf_metric_set *metric_set,\n")
-        c("uint64_t *accumulator)\n")
-        c.outdent(len(counter.max_sym) + 1)
-
-        c("{")
-        c.indent(4)
-
-        output_rpn_equation_code(set, counter, max_eq)
-
-        c.outdent(4)
-        c("}")
+        h(counter.max_sym + "(const struct intel_perf *perf,")
+        h.indent(len(counter.max_sym) + 1)
+        h("const struct intel_perf_metric_set *metric_set,")
+        h("uint64_t *accumulator);")
+        h.outdent(len(counter.max_sym) + 1)
+        h("\n")
 
         hashed_funcs[counter.max_hash] = counter.max_sym
 
@@ -524,65 +566,13 @@ class Gen:
             self.sets.append(Set(self, xml_set))
 
 
-def main():
-    global c
-    global h
-    global xml_equations
+def generate_equations(args, gens):
+    global hashed_funcs
 
-    parser = argparse.ArgumentParser()
-    parser.add_argument("--header", help="Header file to write")
-    parser.add_argument("--code", help="C file to write")
-    parser.add_argument("xml_files", nargs='+', help="List of xml metrics files to process")
-
-    args = parser.parse_args()
-
-    # Note: either arg may == None
-    h = codegen.Codegen(args.header)
-    c = codegen.Codegen(args.code)
-
-    gens = []
-    for xml_file in args.xml_files:
-        gens.append(Gen(xml_file))
-
-    copyright = textwrap.dedent("""\
-        /* Autogenerated file, DO NOT EDIT manually! generated by {}
-         *
-         * Copyright (c) 2018 Intel Corporation
-         *
-         * 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(copyright)
-    c(copyright)
-    c(textwrap.dedent("""\
-        #include <stddef.h>
-        #include <stdint.h>
-        #include <stdbool.h>
-        #include <assert.h>
-
-        """))
-
-    c("#include \"" + os.path.basename(args.header) + "\"")
+    header_file = os.path.basename(args.header)
+    header_define = header_file.replace('.', '_').upper()
 
+    hashed_funcs = {}
     c(textwrap.dedent("""\
         #include <stdlib.h>
         #include <string.h>
@@ -590,11 +580,12 @@ def main():
         #include <i915_drm.h>
 
         #include "i915/perf.h"
+        #include "%s"
 
         #define MIN(x, y) (((x) < (y)) ? (x) : (y))
         #define MAX(a, b) (((a) > (b)) ? (a) : (b))
 
-        static double
+        double
         percentage_max_callback_float(const struct intel_perf *perf,
                                       const struct intel_perf_metric_set *metric_set,
                                       uint64_t *accumulator)
@@ -602,7 +593,7 @@ def main():
            return 100;
         }
 
-        static uint64_t
+        uint64_t
         percentage_max_callback_uint64(const struct intel_perf *perf,
                                        const struct intel_perf_metric_set *metric_set,
                                        uint64_t *accumulator)
@@ -610,7 +601,7 @@ def main():
            return 100;
         }
 
-        """))
+        """ % os.path.basename(args.header)))
 
     # Print out all equation functions.
     for gen in gens:
@@ -619,6 +610,60 @@ def main():
                 output_counter_read(gen, set, counter)
                 output_counter_max(gen, set, counter)
 
+    hashed_funcs = {}
+    h(textwrap.dedent("""\
+        #ifndef __%s__
+        #define __%s__
+
+        #include <stddef.h>
+        #include <stdint.h>
+        #include <stdbool.h>
+
+        struct intel_perf;
+        struct intel_perf_metric_set;
+
+        double
+        percentage_max_callback_float(const struct intel_perf *perf,
+                                      const struct intel_perf_metric_set *metric_set,
+                                      uint64_t *accumulator);
+        uint64_t
+        percentage_max_callback_uint64(const struct intel_perf *perf,
+                                       const struct intel_perf_metric_set *metric_set,
+                                       uint64_t *accumulator);
+
+        """ % (header_define, header_define)))
+
+    # Print out all equation functions.
+    for gen in gens:
+        for set in gen.sets:
+            for counter in set.counters:
+                output_counter_read_definition(gen, set, counter)
+                output_counter_max_definition(gen, set, counter)
+
+    h(textwrap.dedent("""\
+
+        #endif /* __%s__ */
+        """ % header_define))
+
+
+def generate_metric_sets(args, gens):
+    header_file = os.path.basename(args.header)
+    header_define = header_file.replace('.', '_').upper()
+
+    c(textwrap.dedent("""\
+        #include <stddef.h>
+        #include <stdint.h>
+        #include <stdlib.h>
+        #include <stdbool.h>
+        #include <assert.h>
+
+        #include "i915_drm.h"
+
+        """))
+
+    c("#include \"{0}\"".format(os.path.basename(args.header)))
+    c("#include \"{0}\"".format(os.path.basename(args.equation_include)))
+
     # Print out all set registration functions for each set in each
     # generation.
     for gen in gens:
@@ -679,15 +724,12 @@ def main():
             c("}\n")
 
     h(textwrap.dedent("""\
-        #pragma once
+        #ifndef %s
+        #define %s
 
         #include "i915/perf.h"
 
-        #ifdef __cplusplus
-        extern "C" {
-        #endif
-
-        """))
+        """ % (header_define, header_define)))
 
     # Print out all set registration functions for each generation.
     for gen in gens:
@@ -705,11 +747,68 @@ def main():
         c("}")
 
     h(textwrap.dedent("""\
-        #ifdef __cplusplus
-        } /* extern C */
-        #endif
+        #endif /* %s */
+        """ % header_define))
+
+
+def main():
+    global c
+    global h
+    global xml_equations
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--header", help="Header file to write")
+    parser.add_argument("--code", help="C file to write")
+    parser.add_argument("--equations", help="Output equations", action="store_true")
+    parser.add_argument("--metric_sets", help="Output metric sets", action="store_true")
+    parser.add_argument("--equation-include", help="Equation header file")
+    parser.add_argument("xml_files", nargs='+', help="List of xml metrics files to process")
+
+    args = parser.parse_args()
+
+    # Note: either arg may == None
+    h = codegen.Codegen(args.header)
+    c = codegen.Codegen(args.code)
+
+    gens = []
+    for xml_file in args.xml_files:
+        gens.append(Gen(xml_file))
+
+    copyright = textwrap.dedent("""\
+        /* Autogenerated file, DO NOT EDIT manually! generated by {}
+         *
+         * Copyright (c) 2018 Intel Corporation
+         *
+         * 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(copyright)
+    c(copyright)
+
+    if args.equations:
+        generate_equations(args, gens)
+    if args.metric_sets:
+        generate_metric_sets(args, gens)
 
-        """))
 
 
 if __name__ == '__main__':
diff --git a/lib/i915/perf.c b/lib/i915/perf.c
index babfe633..8d3e188a 100644
--- a/lib/i915/perf.c
+++ b/lib/i915/perf.c
@@ -37,7 +37,23 @@
 
 #include "intel_chipset.h"
 #include "perf.h"
-#include "i915_perf_metrics.h"
+
+#include "i915_perf_metrics_hsw.h"
+#include "i915_perf_metrics_bdw.h"
+#include "i915_perf_metrics_chv.h"
+#include "i915_perf_metrics_sklgt2.h"
+#include "i915_perf_metrics_sklgt3.h"
+#include "i915_perf_metrics_sklgt4.h"
+#include "i915_perf_metrics_kblgt2.h"
+#include "i915_perf_metrics_kblgt3.h"
+#include "i915_perf_metrics_cflgt2.h"
+#include "i915_perf_metrics_cflgt3.h"
+#include "i915_perf_metrics_bxt.h"
+#include "i915_perf_metrics_glk.h"
+#include "i915_perf_metrics_cnl.h"
+#include "i915_perf_metrics_icl.h"
+#include "i915_perf_metrics_ehl.h"
+#include "i915_perf_metrics_tgl.h"
 
 static int
 perf_ioctl(int fd, unsigned long request, void *arg)
diff --git a/lib/meson.build b/lib/meson.build
index 8112bec4..f3649615 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -195,16 +195,33 @@ foreach hw : i915_perf_hardware
 endforeach
 
 i915_perf_files += custom_target(
-  'i915-perf-metrics',
+  'i915-perf-equations',
   input : i915_xml_files,
-  output : [ 'i915_perf_metrics.c', 'i915_perf_metrics.h' ],
+  output : [ 'i915_perf_equations.c', 'i915_perf_equations.h' ],
   command : [
     find_program('i915/perf-configs/perf-codegen.py'),
     '--code', '@OUTPUT0@',
     '--header', '@OUTPUT1@',
+    '--equations',
     '@INPUT@',
   ])
 
+foreach hw : i915_perf_hardware
+  i915_perf_files += custom_target(
+    'i915-perf-metrics- at 0@'.format(hw),
+    input : 'i915/perf-configs/oa- at 0@.xml'.format(hw),
+    output : [ 'i915_perf_metrics_ at 0@.c'.format(hw),
+               'i915_perf_metrics_ at 0@.h'.format(hw), ],
+    command : [
+      find_program('i915/perf-configs/perf-codegen.py'),
+      '--code', '@OUTPUT0@',
+      '--header', '@OUTPUT1@',
+      '--metric_sets',
+      '--equation-include', 'i915_perf_equations.h',
+      '@INPUT@',
+    ])
+endforeach
+
 lib_igt_i915_perf_build = shared_library(
   'i915_perf',
   i915_perf_files,
-- 
2.25.1



More information about the igt-dev mailing list