17ec681f3Smrg#
27ec681f3Smrg# Copyright (C) 2020 Google, Inc.
37ec681f3Smrg#
47ec681f3Smrg# Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg# copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg# to deal in the Software without restriction, including without limitation
77ec681f3Smrg# the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg# and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg# Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg#
117ec681f3Smrg# The above copyright notice and this permission notice (including the next
127ec681f3Smrg# paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg# Software.
147ec681f3Smrg#
157ec681f3Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg# IN THE SOFTWARE.
227ec681f3Smrg#
237ec681f3Smrg
247ec681f3Smrgfrom mako.template import Template
257ec681f3Smrgfrom collections import namedtuple
267ec681f3Smrgfrom enum import IntEnum
277ec681f3Smrgimport os
287ec681f3Smrg
297ec681f3SmrgTRACEPOINTS = {}
307ec681f3Smrg
317ec681f3Smrgclass Tracepoint(object):
327ec681f3Smrg    """Class that represents all the information about a tracepoint
337ec681f3Smrg    """
347ec681f3Smrg    def __init__(self, name, args=[], tp_struct=None, tp_print=None, tp_perfetto=None):
357ec681f3Smrg        """Parameters:
367ec681f3Smrg
377ec681f3Smrg        - name: the tracepoint name, a tracepoint function with the given
387ec681f3Smrg          name (prefixed by 'trace_') will be generated with the specied
397ec681f3Smrg          args (following a u_trace ptr).  Calling this tracepoint will
407ec681f3Smrg          emit a trace, if tracing is enabled.
417ec681f3Smrg        - args: the tracepoint func args, an array of TracepointArg
427ec681f3Smrg        - tp_print: (optional) array of format string followed by expressions
437ec681f3Smrg        - tp_perfetto: (optional) driver provided callback which can generate
447ec681f3Smrg          perfetto events
457ec681f3Smrg        """
467ec681f3Smrg        assert isinstance(name, str)
477ec681f3Smrg        assert isinstance(args, list)
487ec681f3Smrg        assert name not in TRACEPOINTS
497ec681f3Smrg
507ec681f3Smrg        self.name = name
517ec681f3Smrg        self.args = args
527ec681f3Smrg        if tp_struct is None:
537ec681f3Smrg           tp_struct = args
547ec681f3Smrg        self.tp_struct = tp_struct
557ec681f3Smrg        self.tp_print = tp_print
567ec681f3Smrg        self.tp_perfetto = tp_perfetto
577ec681f3Smrg
587ec681f3Smrg        TRACEPOINTS[name] = self
597ec681f3Smrg
607ec681f3Smrgclass TracepointArgStruct():
617ec681f3Smrg    """Represents struct that is being passed as an argument
627ec681f3Smrg    """
637ec681f3Smrg    def __init__(self, type, var):
647ec681f3Smrg        """Parameters:
657ec681f3Smrg
667ec681f3Smrg        - type: argument's C type.
677ec681f3Smrg        - var: name of the argument
687ec681f3Smrg        """
697ec681f3Smrg        assert isinstance(type, str)
707ec681f3Smrg        assert isinstance(var, str)
717ec681f3Smrg
727ec681f3Smrg        self.type = type
737ec681f3Smrg        self.var = var
747ec681f3Smrg
757ec681f3Smrgclass TracepointArg(object):
767ec681f3Smrg    """Class that represents either an argument being passed or a field in a struct
777ec681f3Smrg    """
787ec681f3Smrg    def __init__(self, type, var, c_format, name=None, to_prim_type=None):
797ec681f3Smrg        """Parameters:
807ec681f3Smrg
817ec681f3Smrg        - type: argument's C type.
827ec681f3Smrg        - var: either an argument name or a field in the struct
837ec681f3Smrg        - c_format: printf format to print the value.
847ec681f3Smrg        - name: (optional) name that will be used in intermidiate structs and will
857ec681f3Smrg          be displayed in output or perfetto, otherwise var will be used.
867ec681f3Smrg        - to_prim_type: (optional) C function to convert from arg's type to a type
877ec681f3Smrg          compatible with c_format.
887ec681f3Smrg        """
897ec681f3Smrg        assert isinstance(type, str)
907ec681f3Smrg        assert isinstance(var, str)
917ec681f3Smrg        assert isinstance(c_format, str)
927ec681f3Smrg
937ec681f3Smrg        self.type = type
947ec681f3Smrg        self.var = var
957ec681f3Smrg        self.c_format = c_format
967ec681f3Smrg        if name is None:
977ec681f3Smrg           name = var
987ec681f3Smrg        self.name = name
997ec681f3Smrg        self.to_prim_type = to_prim_type
1007ec681f3Smrg
1017ec681f3Smrg
1027ec681f3SmrgHEADERS = []
1037ec681f3Smrg
1047ec681f3Smrgclass HeaderScope(IntEnum):
1057ec681f3Smrg   HEADER = (1 << 0)
1067ec681f3Smrg   SOURCE = (1 << 1)
1077ec681f3Smrg
1087ec681f3Smrgclass Header(object):
1097ec681f3Smrg    """Class that represents a header file dependency of generated tracepoints
1107ec681f3Smrg    """
1117ec681f3Smrg    def __init__(self, hdr, scope=HeaderScope.HEADER|HeaderScope.SOURCE):
1127ec681f3Smrg        """Parameters:
1137ec681f3Smrg
1147ec681f3Smrg        - hdr: the required header path
1157ec681f3Smrg        """
1167ec681f3Smrg        assert isinstance(hdr, str)
1177ec681f3Smrg        self.hdr = hdr
1187ec681f3Smrg        self.scope = scope
1197ec681f3Smrg
1207ec681f3Smrg        HEADERS.append(self)
1217ec681f3Smrg
1227ec681f3Smrg
1237ec681f3SmrgFORWARD_DECLS = []
1247ec681f3Smrg
1257ec681f3Smrgclass ForwardDecl(object):
1267ec681f3Smrg   """Class that represents a forward declaration
1277ec681f3Smrg   """
1287ec681f3Smrg   def __init__(self, decl):
1297ec681f3Smrg        assert isinstance(decl, str)
1307ec681f3Smrg        self.decl = decl
1317ec681f3Smrg
1327ec681f3Smrg        FORWARD_DECLS.append(self)
1337ec681f3Smrg
1347ec681f3Smrg
1357ec681f3Smrghdr_template = """\
1367ec681f3Smrg/* Copyright (C) 2020 Google, Inc.
1377ec681f3Smrg *
1387ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
1397ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
1407ec681f3Smrg * to deal in the Software without restriction, including without limitation
1417ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1427ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
1437ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
1447ec681f3Smrg *
1457ec681f3Smrg * The above copyright notice and this permission notice (including the next
1467ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
1477ec681f3Smrg * Software.
1487ec681f3Smrg *
1497ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1507ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1517ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1527ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1537ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1547ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
1557ec681f3Smrg * IN THE SOFTWARE.
1567ec681f3Smrg */
1577ec681f3Smrg
1587ec681f3Smrg<% guard_name = '_' + hdrname + '_H' %>
1597ec681f3Smrg#ifndef ${guard_name}
1607ec681f3Smrg#define ${guard_name}
1617ec681f3Smrg
1627ec681f3Smrg% for header in HEADERS:
1637ec681f3Smrg#include "${header.hdr}"
1647ec681f3Smrg% endfor
1657ec681f3Smrg
1667ec681f3Smrg#include "util/perf/u_trace.h"
1677ec681f3Smrg
1687ec681f3Smrg#ifdef __cplusplus
1697ec681f3Smrgextern "C" {
1707ec681f3Smrg#endif
1717ec681f3Smrg
1727ec681f3Smrg% for declaration in FORWARD_DECLS:
1737ec681f3Smrg${declaration.decl};
1747ec681f3Smrg% endfor
1757ec681f3Smrg
1767ec681f3Smrg% for trace_name, trace in TRACEPOINTS.items():
1777ec681f3Smrg/*
1787ec681f3Smrg * ${trace_name}
1797ec681f3Smrg */
1807ec681f3Smrgstruct trace_${trace_name} {
1817ec681f3Smrg%    for arg in trace.tp_struct:
1827ec681f3Smrg         ${arg.type} ${arg.name};
1837ec681f3Smrg%    endfor
1847ec681f3Smrg%    if len(trace.args) == 0:
1857ec681f3Smrg#ifdef  __cplusplus
1867ec681f3Smrg     /* avoid warnings about empty struct size mis-match in C vs C++..
1877ec681f3Smrg      * the size mis-match is harmless because (a) nothing will deref
1887ec681f3Smrg      * the empty struct, and (b) the code that cares about allocating
1897ec681f3Smrg      * sizeof(struct trace_${trace_name}) (and wants this to be zero
1907ec681f3Smrg      * if there is no payload) is C
1917ec681f3Smrg      */
1927ec681f3Smrg     uint8_t dummy;
1937ec681f3Smrg#endif
1947ec681f3Smrg%    endif
1957ec681f3Smrg};
1967ec681f3Smrg%    if trace.tp_perfetto is not None:
1977ec681f3Smrg#ifdef HAVE_PERFETTO
1987ec681f3Smrgvoid ${trace.tp_perfetto}(${ctx_param}, uint64_t ts_ns, const void *flush_data, const struct trace_${trace_name} *payload);
1997ec681f3Smrg#endif
2007ec681f3Smrg%    endif
2017ec681f3Smrgvoid __trace_${trace_name}(struct u_trace *ut, void *cs
2027ec681f3Smrg%    for arg in trace.args:
2037ec681f3Smrg     , ${arg.type} ${arg.var}
2047ec681f3Smrg%    endfor
2057ec681f3Smrg);
2067ec681f3Smrgstatic inline void trace_${trace_name}(struct u_trace *ut, void *cs
2077ec681f3Smrg%    for arg in trace.args:
2087ec681f3Smrg     , ${arg.type} ${arg.var}
2097ec681f3Smrg%    endfor
2107ec681f3Smrg) {
2117ec681f3Smrg%    if trace.tp_perfetto is not None:
2127ec681f3Smrg   if (!unlikely(ut->enabled || ut_perfetto_enabled))
2137ec681f3Smrg%    else:
2147ec681f3Smrg   if (!unlikely(ut->enabled))
2157ec681f3Smrg%    endif
2167ec681f3Smrg      return;
2177ec681f3Smrg   __trace_${trace_name}(ut, cs
2187ec681f3Smrg%    for arg in trace.args:
2197ec681f3Smrg        , ${arg.var}
2207ec681f3Smrg%    endfor
2217ec681f3Smrg   );
2227ec681f3Smrg}
2237ec681f3Smrg% endfor
2247ec681f3Smrg
2257ec681f3Smrg#ifdef __cplusplus
2267ec681f3Smrg}
2277ec681f3Smrg#endif
2287ec681f3Smrg
2297ec681f3Smrg#endif /* ${guard_name} */
2307ec681f3Smrg"""
2317ec681f3Smrg
2327ec681f3Smrgsrc_template = """\
2337ec681f3Smrg/* Copyright (C) 2020 Google, Inc.
2347ec681f3Smrg *
2357ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
2367ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
2377ec681f3Smrg * to deal in the Software without restriction, including without limitation
2387ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
2397ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
2407ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
2417ec681f3Smrg *
2427ec681f3Smrg * The above copyright notice and this permission notice (including the next
2437ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
2447ec681f3Smrg * Software.
2457ec681f3Smrg *
2467ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2477ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2487ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2497ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2507ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2517ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2527ec681f3Smrg * IN THE SOFTWARE.
2537ec681f3Smrg */
2547ec681f3Smrg
2557ec681f3Smrg% for header in HEADERS:
2567ec681f3Smrg#include "${header.hdr}"
2577ec681f3Smrg% endfor
2587ec681f3Smrg
2597ec681f3Smrg#include "${hdr}"
2607ec681f3Smrg
2617ec681f3Smrg#define __NEEDS_TRACE_PRIV
2627ec681f3Smrg#include "util/perf/u_trace_priv.h"
2637ec681f3Smrg
2647ec681f3Smrg% for trace_name, trace in TRACEPOINTS.items():
2657ec681f3Smrg/*
2667ec681f3Smrg * ${trace_name}
2677ec681f3Smrg */
2687ec681f3Smrg%    if trace.args is not None and len(trace.args) > 0:
2697ec681f3Smrgstatic void __print_${trace_name}(FILE *out, const void *arg) {
2707ec681f3Smrg   const struct trace_${trace_name} *__entry =
2717ec681f3Smrg      (const struct trace_${trace_name} *)arg;
2727ec681f3Smrg%    if trace.tp_print is not None:
2737ec681f3Smrg   fprintf(out, "${trace.tp_print[0]}\\n"
2747ec681f3Smrg%       for arg in trace.tp_print[1:]:
2757ec681f3Smrg           , ${arg}
2767ec681f3Smrg%       endfor
2777ec681f3Smrg% else:
2787ec681f3Smrg   fprintf(out, ""
2797ec681f3Smrg%  for arg in trace.tp_struct:
2807ec681f3Smrg      "${arg.name}=${arg.c_format}, "
2817ec681f3Smrg%  endfor
2827ec681f3Smrg         "\\n"
2837ec681f3Smrg%  for arg in trace.tp_struct:
2847ec681f3Smrg   % if arg.to_prim_type:
2857ec681f3Smrg   ,${arg.to_prim_type.format('__entry->' + arg.name)}
2867ec681f3Smrg   % else:
2877ec681f3Smrg   ,__entry->${arg.name}
2887ec681f3Smrg   % endif
2897ec681f3Smrg%  endfor
2907ec681f3Smrg%endif
2917ec681f3Smrg   );
2927ec681f3Smrg}
2937ec681f3Smrg%    else:
2947ec681f3Smrg#define __print_${trace_name} NULL
2957ec681f3Smrg%    endif
2967ec681f3Smrgstatic const struct u_tracepoint __tp_${trace_name} = {
2977ec681f3Smrg    ALIGN_POT(sizeof(struct trace_${trace_name}), 8),   /* keep size 64b aligned */
2987ec681f3Smrg    "${trace_name}",
2997ec681f3Smrg    __print_${trace_name},
3007ec681f3Smrg%    if trace.tp_perfetto is not None:
3017ec681f3Smrg#ifdef HAVE_PERFETTO
3027ec681f3Smrg    (void (*)(void *pctx, uint64_t, const void *, const void *))${trace.tp_perfetto},
3037ec681f3Smrg#endif
3047ec681f3Smrg%    endif
3057ec681f3Smrg};
3067ec681f3Smrgvoid __trace_${trace_name}(struct u_trace *ut, void *cs
3077ec681f3Smrg%    for arg in trace.args:
3087ec681f3Smrg     , ${arg.type} ${arg.var}
3097ec681f3Smrg%    endfor
3107ec681f3Smrg) {
3117ec681f3Smrg   struct trace_${trace_name} *__entry =
3127ec681f3Smrg      (struct trace_${trace_name} *)u_trace_append(ut, cs, &__tp_${trace_name});
3137ec681f3Smrg   (void)__entry;
3147ec681f3Smrg%    for arg in trace.tp_struct:
3157ec681f3Smrg        __entry->${arg.name} = ${arg.var};
3167ec681f3Smrg%    endfor
3177ec681f3Smrg}
3187ec681f3Smrg
3197ec681f3Smrg% endfor
3207ec681f3Smrg"""
3217ec681f3Smrg
3227ec681f3Smrgdef utrace_generate(cpath, hpath, ctx_param):
3237ec681f3Smrg    if cpath is not None:
3247ec681f3Smrg        hdr = os.path.basename(cpath).rsplit('.', 1)[0] + '.h'
3257ec681f3Smrg        with open(cpath, 'w') as f:
3267ec681f3Smrg            f.write(Template(src_template).render(
3277ec681f3Smrg                hdr=hdr,
3287ec681f3Smrg                ctx_param=ctx_param,
3297ec681f3Smrg                HEADERS=[h for h in HEADERS if h.scope & HeaderScope.SOURCE],
3307ec681f3Smrg                TRACEPOINTS=TRACEPOINTS))
3317ec681f3Smrg
3327ec681f3Smrg    if hpath is not None:
3337ec681f3Smrg        hdr = os.path.basename(hpath)
3347ec681f3Smrg        with open(hpath, 'w') as f:
3357ec681f3Smrg            f.write(Template(hdr_template).render(
3367ec681f3Smrg                hdrname=hdr.rstrip('.h').upper(),
3377ec681f3Smrg                ctx_param=ctx_param,
3387ec681f3Smrg                HEADERS=[h for h in HEADERS if h.scope & HeaderScope.HEADER],
3397ec681f3Smrg                FORWARD_DECLS=FORWARD_DECLS,
3407ec681f3Smrg                TRACEPOINTS=TRACEPOINTS))
3417ec681f3Smrg
3427ec681f3Smrg
3437ec681f3Smrgperfetto_utils_hdr_template = """\
3447ec681f3Smrg/*
3457ec681f3Smrg * Copyright © 2021 Igalia S.L.
3467ec681f3Smrg *
3477ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
3487ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
3497ec681f3Smrg * to deal in the Software without restriction, including without limitation
3507ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
3517ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
3527ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
3537ec681f3Smrg *
3547ec681f3Smrg * The above copyright notice and this permission notice (including the next
3557ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
3567ec681f3Smrg * Software.
3577ec681f3Smrg *
3587ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3597ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3607ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
3617ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3627ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3637ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3647ec681f3Smrg * SOFTWARE.
3657ec681f3Smrg */
3667ec681f3Smrg
3677ec681f3Smrg<% guard_name = '_' + hdrname + '_H' %>
3687ec681f3Smrg#ifndef ${guard_name}
3697ec681f3Smrg#define ${guard_name}
3707ec681f3Smrg
3717ec681f3Smrg#include <perfetto.h>
3727ec681f3Smrg
3737ec681f3Smrg% for trace_name, trace in TRACEPOINTS.items():
3747ec681f3Smrgstatic void UNUSED
3757ec681f3Smrgtrace_payload_as_extra_${trace_name}(perfetto::protos::pbzero::GpuRenderStageEvent *event,
3767ec681f3Smrg                                     const struct trace_${trace_name} *payload)
3777ec681f3Smrg{
3787ec681f3Smrg%  if all([trace.tp_perfetto, trace.tp_struct]) and len(trace.tp_struct) > 0:
3797ec681f3Smrg   char buf[128];
3807ec681f3Smrg
3817ec681f3Smrg%  for arg in trace.tp_struct:
3827ec681f3Smrg   {
3837ec681f3Smrg      auto data = event->add_extra_data();
3847ec681f3Smrg      data->set_name("${arg.name}");
3857ec681f3Smrg
3867ec681f3Smrg%     if arg.to_prim_type:
3877ec681f3Smrg      sprintf(buf, "${arg.c_format}", ${arg.to_prim_type.format('payload->' + arg.name)});
3887ec681f3Smrg%     else:
3897ec681f3Smrg      sprintf(buf, "${arg.c_format}", payload->${arg.name});
3907ec681f3Smrg%     endif
3917ec681f3Smrg
3927ec681f3Smrg      data->set_value(buf);
3937ec681f3Smrg   }
3947ec681f3Smrg%  endfor
3957ec681f3Smrg
3967ec681f3Smrg%  endif
3977ec681f3Smrg}
3987ec681f3Smrg% endfor
3997ec681f3Smrg
4007ec681f3Smrg#endif /* ${guard_name} */
4017ec681f3Smrg"""
4027ec681f3Smrg
4037ec681f3Smrgdef utrace_generate_perfetto_utils(hpath):
4047ec681f3Smrg    if hpath is not None:
4057ec681f3Smrg        hdr = os.path.basename(hpath)
4067ec681f3Smrg        with open(hpath, 'wb') as f:
4077ec681f3Smrg            f.write(Template(perfetto_utils_hdr_template, output_encoding='utf-8').render(
4087ec681f3Smrg                hdrname=hdr.rstrip('.h').upper(),
4097ec681f3Smrg                TRACEPOINTS=TRACEPOINTS))
410