xref: /aosp_15_r20/external/mesa3d/src/util/perf/u_trace.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1#
2# Copyright (C) 2020 Google, Inc.
3#
4# Permission is hereby granted, free of charge, to any person obtaining a
5# copy of this software and associated documentation files (the "Software"),
6# to deal in the Software without restriction, including without limitation
7# the rights to use, copy, modify, merge, publish, distribute, sublicense,
8# and/or sell copies of the Software, and to permit persons to whom the
9# Software is furnished to do so, subject to the following conditions:
10#
11# The above copyright notice and this permission notice (including the next
12# paragraph) shall be included in all copies or substantial portions of the
13# Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21# IN THE SOFTWARE.
22#
23
24from mako.template import Template
25from mako import exceptions
26from collections import namedtuple
27from enum import IntEnum
28import os
29
30TRACEPOINTS = {}
31TRACEPOINTS_TOGGLES = {}
32
33class Tracepoint(object):
34    """Class that represents all the information about a tracepoint
35    """
36    def __init__(self, name, args=[], toggle_name=None,
37                 tp_struct=None, tp_print=None, tp_perfetto=None,
38                 tp_markers=None, tp_flags=[], need_cs_param=True):
39        """Parameters:
40
41        - name: the tracepoint name, a tracepoint function with the given
42          name (prefixed by 'trace_') will be generated with the specied
43          args (following a u_trace ptr).  Calling this tracepoint will
44          emit a trace, if tracing is enabled.
45        - args: the tracepoint func args, an array of TracepointArg
46        - tp_print: (optional) array of format string followed by expressions
47        - tp_perfetto: (optional) driver provided callback which can generate
48          perfetto events
49        - tp_markers: (optional) driver provided printf-style callback which can
50          generate CS markers, this requires 'need_cs_param' as the first param
51          is the CS that the label should be emitted into
52        - need_cs_param: whether tracepoint functions need an additional cs
53          parameter.
54        """
55        assert isinstance(name, str)
56        assert isinstance(args, list)
57        assert name not in TRACEPOINTS
58
59        def needs_storage(a):
60            if a.c_format is None:
61                return False
62            if a.is_indirect:
63                return False
64            return True
65
66        self.name = name
67        self.args = args
68        # For storage data, include all the specified tp_struct by the caller
69        # as well as arguments needing storage
70        self.tp_struct = []
71        if tp_struct is not None:
72           self.tp_struct += tp_struct
73        self.tp_struct += [x for x in args if needs_storage(x)]
74        # For printing, include all the arguments & tp_struct elements that
75        # have a format printer
76        self.tp_print = [x for x in args if x.c_format is not None]
77        if tp_struct is not None:
78            self.tp_print += [x for x in tp_struct if x.c_format is not None]
79
80        self.has_variable_arg = False
81        for arg in self.tp_struct:
82            if arg.length_arg != None and not arg.length_arg.isdigit():
83                self.has_variable_arg = True
84                break
85        self.tp_print_custom = tp_print
86
87        # Compute the offset of each indirect argument
88        self.indirect_args = [x for x in args if x.is_indirect]
89        indirect_sizes = []
90        for indirect in self.indirect_args:
91            indirect.indirect_offset = ' + '.join(indirect_sizes) if len(indirect_sizes) > 0 else 0
92            indirect_sizes.append(f"sizeof({indirect.type}")
93
94        self.tp_perfetto = tp_perfetto
95        self.tp_markers = tp_markers
96        self.tp_flags = tp_flags
97        self.toggle_name = toggle_name
98        self.need_cs_param = need_cs_param
99
100        TRACEPOINTS[name] = self
101        if toggle_name is not None and toggle_name not in TRACEPOINTS_TOGGLES:
102            TRACEPOINTS_TOGGLES[toggle_name] = len(TRACEPOINTS_TOGGLES)
103
104    def can_generate_print(self):
105        return self.args is not None and len(self.args) > 0
106
107    def enabled_expr(self, trace_toggle_name):
108        if trace_toggle_name is None:
109            return "true"
110        assert self.toggle_name is not None
111        return "({0} & {1}_{2})".format(trace_toggle_name,
112                                        trace_toggle_name.upper(),
113                                        self.toggle_name.upper())
114
115class TracepointArgStruct():
116    """Represents struct that is being passed as an argument
117    """
118    def __init__(self, type, var, c_format=None, fields=[], is_indirect=False):
119        """Parameters:
120
121        - type: argument's C type.
122        - var: name of the argument
123        """
124        assert isinstance(type, str)
125        assert isinstance(var, str)
126
127        self.type = type
128        self.var = var
129        self.name = var
130        self.is_indirect = is_indirect
131        self.indirect_offset = 0
132        self.is_struct = True
133        self.c_format = c_format
134        self.fields = fields
135        self.to_prim_type = None
136
137        if self.is_indirect:
138            self.func_param = f"struct u_trace_address {self.var}"
139        else:
140            self.func_param = f"{self.type} {self.var}"
141
142    def value_expr(self, entry_name):
143        ret = None
144        if self.is_struct:
145            if self.is_indirect:
146                ret = ", ".join([f"__{self.name}->{f}" for f in self.fields])
147            else:
148                ret = ", ".join([f"{entry_name}->{self.name}.{f}" for f in self.fields])
149        else:
150            ret = f"{entry_name}->{self.name}"
151        return ret
152
153class TracepointArg(object):
154    """Class that represents either an argument being passed or a field in a struct
155    """
156    def __init__(self, type, var, c_format=None, name=None, to_prim_type=None,
157                 length_arg=None, copy_func=None, is_indirect=False):
158        """Parameters:
159
160        - type: argument's C type.
161        - var: either an argument name or a field in the struct
162        - c_format: printf format to print the value.
163        - name: (optional) name that will be used in intermidiate structs and will
164          be displayed in output or perfetto, otherwise var will be used.
165        - to_prim_type: (optional) C function to convert from arg's type to a type
166          compatible with c_format.
167        - length_arg: whether this argument is a variable length array
168        """
169        assert isinstance(type, str)
170        assert isinstance(var, str)
171
172        self.type = type
173        self.var = var
174        self.c_format = c_format
175        if name is None:
176           name = var
177        self.name = name
178        self.to_prim_type = to_prim_type
179        self.length_arg = length_arg
180        self.copy_func = copy_func
181
182        self.is_struct = False
183        self.is_indirect = is_indirect
184        self.indirect_offset = 0
185
186        if self.is_indirect:
187            pass
188        elif self.type == "str":
189            if self.length_arg and self.length_arg.isdigit():
190                self.struct_member = f"char {self.name}[{length_arg} + 1]"
191            else:
192                self.struct_member = f"char {self.name}[0]"
193        else:
194            self.struct_member = f"{self.type} {self.name}"
195
196        if self.is_indirect:
197            self.func_param = f"struct u_trace_address {self.var}"
198        elif self.type == "str":
199            self.func_param = f"const char *{self.var}"
200        else:
201            self.func_param = f"{self.type} {self.var}"
202
203    def value_expr(self, entry_name):
204        if self.is_indirect:
205            ret = f"*__{self.name}"
206        else:
207            ret = f"{entry_name}->{self.name}"
208        if not self.is_struct and self.to_prim_type:
209            ret = self.to_prim_type.format(ret)
210        return ret
211
212
213HEADERS = []
214
215class HeaderScope(IntEnum):
216    HEADER = (1 << 0)
217    SOURCE = (1 << 1)
218    PERFETTO = (1 << 2)
219
220class Header(object):
221    """Class that represents a header file dependency of generated tracepoints
222    """
223    def __init__(self, hdr, scope=HeaderScope.HEADER):
224        """Parameters:
225
226        - hdr: the required header path
227        """
228        assert isinstance(hdr, str)
229        self.hdr = hdr
230        self.scope = scope
231
232        HEADERS.append(self)
233
234
235FORWARD_DECLS = []
236
237class ForwardDecl(object):
238   """Class that represents a forward declaration
239   """
240   def __init__(self, decl):
241        assert isinstance(decl, str)
242        self.decl = decl
243
244        FORWARD_DECLS.append(self)
245
246
247hdr_template = """\
248/* Copyright (C) 2020 Google, Inc.
249 *
250 * Permission is hereby granted, free of charge, to any person obtaining a
251 * copy of this software and associated documentation files (the "Software"),
252 * to deal in the Software without restriction, including without limitation
253 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
254 * and/or sell copies of the Software, and to permit persons to whom the
255 * Software is furnished to do so, subject to the following conditions:
256 *
257 * The above copyright notice and this permission notice (including the next
258 * paragraph) shall be included in all copies or substantial portions of the
259 * Software.
260 *
261 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
262 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
263 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
264 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
265 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
266 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
267 * IN THE SOFTWARE.
268 */
269
270<% guard_name = '_' + hdrname + '_H' %>
271#ifndef ${guard_name}
272#define ${guard_name}
273
274% for header in HEADERS:
275#include "${header.hdr}"
276% endfor
277
278#include "util/perf/u_trace.h"
279
280#ifdef __cplusplus
281extern "C" {
282#endif
283
284% for declaration in FORWARD_DECLS:
285${declaration.decl};
286% endfor
287
288% if trace_toggle_name is not None:
289enum ${trace_toggle_name.lower()} {
290%    for toggle_name, config_id in TRACEPOINTS_TOGGLES.items():
291   ${trace_toggle_name.upper()}_${toggle_name.upper()} = 1ull << ${config_id},
292%    endfor
293};
294
295extern uint64_t ${trace_toggle_name};
296
297void ${trace_toggle_name}_config_variable(void);
298% endif
299
300% for trace_name, trace in TRACEPOINTS.items():
301
302/*
303 * ${trace_name}
304 */
305struct trace_${trace_name} {
306%    for arg in trace.tp_struct:
307   ${arg.struct_member};
308%    endfor
309%    if len(trace.tp_struct) == 0:
310#ifdef __cplusplus
311   /* avoid warnings about empty struct size mis-match in C vs C++..
312    * the size mis-match is harmless because (a) nothing will deref
313    * the empty struct, and (b) the code that cares about allocating
314    * sizeof(struct trace_${trace_name}) (and wants this to be zero
315    * if there is no payload) is C
316    */
317   uint8_t dummy;
318#endif
319%    endif
320};
321%    if trace.tp_perfetto is not None:
322#ifdef HAVE_PERFETTO
323void ${trace.tp_perfetto}(
324   ${ctx_param},
325   uint64_t ts_ns,
326   uint16_t tp_idx,
327   const void *flush_data,
328   const struct trace_${trace_name} *payload,
329   const void *indirect_data);
330#endif
331%    endif
332void __trace_${trace_name}(
333       struct u_trace *ut
334     , enum u_trace_type enabled_traces
335%    if trace.need_cs_param:
336     , void *cs
337%    endif
338%    for arg in trace.args:
339     , ${arg.func_param}
340%    endfor
341);
342static ALWAYS_INLINE void trace_${trace_name}(
343     struct u_trace *ut
344%    if trace.need_cs_param:
345   , void *cs
346%    endif
347%    for arg in trace.args:
348   , ${arg.func_param}
349%    endfor
350) {
351   enum u_trace_type enabled_traces = p_atomic_read_relaxed(&ut->utctx->enabled_traces);
352   if (!unlikely(enabled_traces != 0 &&
353                 ${trace.enabled_expr(trace_toggle_name)}))
354      return;
355   __trace_${trace_name}(
356        ut
357      , enabled_traces
358%    if trace.need_cs_param:
359      , cs
360%    endif
361%    for arg in trace.args:
362      , ${arg.var}
363%    endfor
364   );
365}
366% endfor
367
368#ifdef __cplusplus
369}
370#endif
371
372#endif /* ${guard_name} */
373"""
374
375src_template = """\
376/* Copyright (C) 2020 Google, Inc.
377 *
378 * Permission is hereby granted, free of charge, to any person obtaining a
379 * copy of this software and associated documentation files (the "Software"),
380 * to deal in the Software without restriction, including without limitation
381 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
382 * and/or sell copies of the Software, and to permit persons to whom the
383 * Software is furnished to do so, subject to the following conditions:
384 *
385 * The above copyright notice and this permission notice (including the next
386 * paragraph) shall be included in all copies or substantial portions of the
387 * Software.
388 *
389 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
390 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
391 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
392 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
393 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
394 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
395 * IN THE SOFTWARE.
396 */
397
398#include "${hdr}"
399
400% for header in HEADERS:
401#include "${header.hdr}"
402% endfor
403
404#define __NEEDS_TRACE_PRIV
405#include "util/u_debug.h"
406#include "util/perf/u_trace_priv.h"
407
408% if trace_toggle_name is not None:
409static const struct debug_control config_control[] = {
410%    for toggle_name in TRACEPOINTS_TOGGLES.keys():
411   { "${toggle_name}", ${trace_toggle_name.upper()}_${toggle_name.upper()}, },
412%    endfor
413   { NULL, 0, },
414};
415uint64_t ${trace_toggle_name} = 0;
416
417static void
418${trace_toggle_name}_variable_once(void)
419{
420   uint64_t default_value = 0
421%    for name in trace_toggle_defaults:
422     | ${trace_toggle_name.upper()}_${name.upper()}
423%    endfor
424     ;
425
426   ${trace_toggle_name} =
427      parse_enable_string(getenv("${trace_toggle_name.upper()}"),
428                          default_value,
429                          config_control);
430}
431
432void
433${trace_toggle_name}_config_variable(void)
434{
435   static once_flag process_${trace_toggle_name}_variable_flag = ONCE_FLAG_INIT;
436
437   call_once(&process_${trace_toggle_name}_variable_flag,
438             ${trace_toggle_name}_variable_once);
439}
440% endif
441
442% for index, (trace_name, trace) in enumerate(TRACEPOINTS.items()):
443/*
444 * ${trace_name}
445 */
446 % if trace.can_generate_print():
447static void __print_${trace_name}(FILE *out, const void *arg, const void *indirect) {
448  % if len(trace.tp_struct) > 0:
449   const struct trace_${trace_name} *__entry =
450      (const struct trace_${trace_name} *)arg;
451  % endif
452  % for arg in trace.indirect_args:
453   const ${arg.type} *__${arg.name} = (const ${arg.type} *) ((char *)indirect + ${arg.indirect_offset});
454  % endfor
455  % if trace.tp_print_custom is not None:
456   fprintf(out, "${trace.tp_print_custom[0]}\\n"
457   % for arg in trace.tp_print_custom[1:]:
458           , ${arg}
459   % endfor
460  % else:
461   fprintf(out, ""
462   % for arg in trace.tp_print:
463      "${arg.name}=${arg.c_format}, "
464   % endfor
465         "\\n"
466   % for arg in trace.tp_print:
467   ,${arg.value_expr("__entry")}
468   % endfor
469  % endif
470   );
471}
472
473static void __print_json_${trace_name}(FILE *out, const void *arg, const void *indirect) {
474  % if len(trace.tp_struct) > 0:
475   const struct trace_${trace_name} *__entry =
476      (const struct trace_${trace_name} *)arg;
477  % endif
478  % for arg in trace.indirect_args:
479   const ${arg.type} *__${arg.var} = (const ${arg.type} *) ((char *)indirect + ${arg.indirect_offset});
480  % endfor
481  % if trace.tp_print_custom is not None:
482   fprintf(out, "\\"unstructured\\": \\"${trace.tp_print_custom[0]}\\""
483   % for arg in trace.tp_print_custom[1:]:
484           , ${arg}
485   % endfor
486  % else:
487   fprintf(out, ""
488   % for arg in trace.tp_print:
489      "\\"${arg.name}\\": \\"${arg.c_format}\\""
490    % if arg != trace.tp_print[-1]:
491         ", "
492    % endif
493   % endfor
494   % for arg in trace.tp_print:
495   ,${arg.value_expr("__entry")}
496   % endfor
497  % endif
498   );
499}
500
501 % else:
502#define __print_${trace_name} NULL
503#define __print_json_${trace_name} NULL
504 % endif
505 % if trace.tp_markers is not None:
506
507__attribute__((format(printf, 3, 4))) void ${trace.tp_markers}(struct u_trace_context *utctx, void *, const char *, ...);
508
509static void __emit_label_${trace_name}(struct u_trace_context *utctx, void *cs, struct trace_${trace_name} *entry) {
510   ${trace.tp_markers}(utctx, cs, "${trace_name}("
511   % for idx,arg in enumerate(trace.tp_print):
512   % if not arg.is_indirect:
513      "${"," if idx != 0 else ""}${arg.name}=${arg.c_format}"
514   % endif
515   % endfor
516      ")"
517   % for arg in trace.tp_print:
518   % if not arg.is_indirect:
519      ,${arg.value_expr('entry')}
520   % endif
521   % endfor
522   );
523}
524
525 % endif
526static const struct u_tracepoint __tp_${trace_name} = {
527    "${trace_name}",
528    ALIGN_POT(sizeof(struct trace_${trace_name}), 8),   /* keep size 64b aligned */
529    0
530 % for arg in trace.indirect_args:
531    + sizeof(${arg.type})
532 % endfor
533    ,
534    ${0 if len(trace.tp_flags) == 0 else " | ".join(trace.tp_flags)},
535    ${index},
536    __print_${trace_name},
537    __print_json_${trace_name},
538 % if trace.tp_perfetto is not None:
539#ifdef HAVE_PERFETTO
540    (void (*)(void *pctx, uint64_t, uint16_t, const void *, const void *, const void *))${trace.tp_perfetto},
541#endif
542 % endif
543};
544void __trace_${trace_name}(
545     struct u_trace *ut
546   , enum u_trace_type enabled_traces
547 % if trace.need_cs_param:
548   , void *cs
549 % endif
550 % for arg in trace.args:
551   , ${arg.func_param}
552 % endfor
553) {
554   struct trace_${trace_name} entry;
555 % if len(trace.indirect_args) > 0:
556   struct u_trace_address indirects[] = {
557  % for arg in trace.indirect_args:
558      ${arg.var},
559  % endfor
560   };
561   uint8_t indirect_sizes[] = {
562  % for arg in trace.indirect_args:
563      sizeof(${arg.type}),
564  % endfor
565   };
566 % endif
567   UNUSED struct trace_${trace_name} *__entry =
568      enabled_traces & U_TRACE_TYPE_REQUIRE_QUEUING ?
569      (struct trace_${trace_name} *)u_trace_appendv(ut, ${"cs," if trace.need_cs_param else "NULL,"} &__tp_${trace_name},
570                                                    0
571  % for arg in trace.tp_struct:
572   % if arg.length_arg is not None and not arg.length_arg.isdigit():
573                                                    + ${arg.length_arg}
574   % endif
575  % endfor
576                                                    ,
577  % if len(trace.indirect_args) > 0:
578                                                    ARRAY_SIZE(indirects), indirects, indirect_sizes
579  % else:
580                                                    0, NULL, NULL
581  % endif
582                                                    ) :
583      &entry;
584 % for arg in trace.tp_struct:
585  % if arg.copy_func is None:
586   __entry->${arg.name} = ${arg.var};
587  % else:
588   ${arg.copy_func}(__entry->${arg.name}, ${arg.var}, ${arg.length_arg});
589  % endif
590 % endfor
591 % if trace.tp_markers is not None:
592   if (enabled_traces & U_TRACE_TYPE_MARKERS)
593      __emit_label_${trace_name}(ut->utctx, cs, __entry);
594 % endif
595}
596
597% endfor
598"""
599
600def utrace_generate(cpath, hpath, ctx_param, trace_toggle_name=None,
601                    trace_toggle_defaults=[]):
602    """Parameters:
603
604    - cpath: c file to generate.
605    - hpath: h file to generate.
606    - ctx_param: type of the first parameter to the perfetto vfuncs.
607    - trace_toggle_name: (optional) name of the environment variable
608      enabling/disabling tracepoints.
609    - trace_toggle_defaults: (optional) list of tracepoints enabled by default.
610    """
611    if cpath is not None:
612        hdr = os.path.basename(cpath).rsplit('.', 1)[0] + '.h'
613        with open(cpath, 'w', encoding='utf-8') as f:
614            try:
615                f.write(Template(src_template).render(
616                    hdr=hdr,
617                    ctx_param=ctx_param,
618                    trace_toggle_name=trace_toggle_name,
619                    trace_toggle_defaults=trace_toggle_defaults,
620                    HEADERS=[h for h in HEADERS if h.scope & HeaderScope.SOURCE],
621                    TRACEPOINTS=TRACEPOINTS,
622                    TRACEPOINTS_TOGGLES=TRACEPOINTS_TOGGLES))
623            except:
624                print(exceptions.text_error_template().render())
625
626    if hpath is not None:
627        hdr = os.path.basename(hpath)
628        with open(hpath, 'w', encoding='utf-8') as f:
629            try:
630                f.write(Template(hdr_template).render(
631                    hdrname=hdr.rstrip('.h').upper(),
632                    ctx_param=ctx_param,
633                    trace_toggle_name=trace_toggle_name,
634                    HEADERS=[h for h in HEADERS if h.scope & HeaderScope.HEADER],
635                    FORWARD_DECLS=FORWARD_DECLS,
636                    TRACEPOINTS=TRACEPOINTS,
637                    TRACEPOINTS_TOGGLES=TRACEPOINTS_TOGGLES))
638            except:
639                print(exceptions.text_error_template().render())
640
641
642perfetto_utils_hdr_template = """\
643/*
644 * Copyright © 2021 Igalia S.L.
645 *
646 * Permission is hereby granted, free of charge, to any person obtaining a
647 * copy of this software and associated documentation files (the "Software"),
648 * to deal in the Software without restriction, including without limitation
649 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
650 * and/or sell copies of the Software, and to permit persons to whom the
651 * Software is furnished to do so, subject to the following conditions:
652 *
653 * The above copyright notice and this permission notice (including the next
654 * paragraph) shall be included in all copies or substantial portions of the
655 * Software.
656 *
657 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
658 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
659 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
660 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
661 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
662 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
663 * SOFTWARE.
664 */
665
666<% guard_name = '_' + hdrname + '_H' %>
667#ifndef ${guard_name}
668#define ${guard_name}
669
670#include <perfetto.h>
671
672% for header in HEADERS:
673#include "${header.hdr}"
674% endfor
675
676UNUSED static const char *${basename}_names[] = {
677% for trace_name, trace in TRACEPOINTS.items():
678   "${trace_name}",
679% endfor
680};
681
682% for trace_name, trace in TRACEPOINTS.items():
683static void UNUSED
684trace_payload_as_extra_${trace_name}(perfetto::protos::pbzero::GpuRenderStageEvent *event,
685                                     const struct trace_${trace_name} *payload,
686                                     const void *indirect_data)
687{
688 % if trace.tp_perfetto is not None and len(trace.tp_print) > 0:
689   char buf[128];
690
691  % for arg in trace.tp_print:
692   {
693      auto data = event->add_extra_data();
694      data->set_name("${arg.name}");
695
696   % if arg.is_indirect:
697      const ${arg.type}* __${arg.var} = (const ${arg.type}*)((uint8_t *)indirect_data + ${arg.indirect_offset});
698   % endif
699      sprintf(buf, "${arg.c_format}", ${arg.value_expr("payload")});
700
701      data->set_value(buf);
702   }
703  % endfor
704
705 % endif
706}
707% endfor
708
709#endif /* ${guard_name} */
710"""
711
712def utrace_generate_perfetto_utils(hpath,basename="tracepoint"):
713    if hpath is not None:
714        hdr = os.path.basename(hpath)
715        with open(hpath, 'w', encoding='utf-8') as f:
716            try:
717                f.write(Template(perfetto_utils_hdr_template).render(
718                    basename=basename,
719                    hdrname=hdr.rstrip('.h').upper(),
720                    HEADERS=[h for h in HEADERS if h.scope & HeaderScope.PERFETTO],
721                    TRACEPOINTS=TRACEPOINTS))
722            except:
723                print(exceptions.text_error_template().render())
724