• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 collections import namedtuple
26from enum import IntEnum
27import os
28
29TRACEPOINTS = {}
30
31class Tracepoint(object):
32    """Class that represents all the information about a tracepoint
33    """
34    def __init__(self, name, args=[], tp_struct=None, tp_print=None, tp_perfetto=None):
35        """Parameters:
36
37        - name: the tracepoint name, a tracepoint function with the given
38          name (prefixed by 'trace_') will be generated with the specied
39          args (following a u_trace ptr).  Calling this tracepoint will
40          emit a trace, if tracing is enabled.
41        - args: the tracepoint func args, an array of TracepointArg
42        - tp_print: (optional) array of format string followed by expressions
43        - tp_perfetto: (optional) driver provided callback which can generate
44          perfetto events
45        """
46        assert isinstance(name, str)
47        assert isinstance(args, list)
48        assert name not in TRACEPOINTS
49
50        self.name = name
51        self.args = args
52        if tp_struct is None:
53           tp_struct = args
54        self.tp_struct = tp_struct
55        self.tp_print = tp_print
56        self.tp_perfetto = tp_perfetto
57
58        TRACEPOINTS[name] = self
59
60class TracepointArgStruct():
61    """Represents struct that is being passed as an argument
62    """
63    def __init__(self, type, var):
64        """Parameters:
65
66        - type: argument's C type.
67        - var: name of the argument
68        """
69        assert isinstance(type, str)
70        assert isinstance(var, str)
71
72        self.type = type
73        self.var = var
74
75class TracepointArg(object):
76    """Class that represents either an argument being passed or a field in a struct
77    """
78    def __init__(self, type, var, c_format, name=None, to_prim_type=None):
79        """Parameters:
80
81        - type: argument's C type.
82        - var: either an argument name or a field in the struct
83        - c_format: printf format to print the value.
84        - name: (optional) name that will be used in intermidiate structs and will
85          be displayed in output or perfetto, otherwise var will be used.
86        - to_prim_type: (optional) C function to convert from arg's type to a type
87          compatible with c_format.
88        """
89        assert isinstance(type, str)
90        assert isinstance(var, str)
91        assert isinstance(c_format, str)
92
93        self.type = type
94        self.var = var
95        self.c_format = c_format
96        if name is None:
97           name = var
98        self.name = name
99        self.to_prim_type = to_prim_type
100
101
102HEADERS = []
103
104class HeaderScope(IntEnum):
105   HEADER = (1 << 0)
106   SOURCE = (1 << 1)
107
108class Header(object):
109    """Class that represents a header file dependency of generated tracepoints
110    """
111    def __init__(self, hdr, scope=HeaderScope.HEADER|HeaderScope.SOURCE):
112        """Parameters:
113
114        - hdr: the required header path
115        """
116        assert isinstance(hdr, str)
117        self.hdr = hdr
118        self.scope = scope
119
120        HEADERS.append(self)
121
122
123FORWARD_DECLS = []
124
125class ForwardDecl(object):
126   """Class that represents a forward declaration
127   """
128   def __init__(self, decl):
129        assert isinstance(decl, str)
130        self.decl = decl
131
132        FORWARD_DECLS.append(self)
133
134
135hdr_template = """\
136/* Copyright (C) 2020 Google, Inc.
137 *
138 * Permission is hereby granted, free of charge, to any person obtaining a
139 * copy of this software and associated documentation files (the "Software"),
140 * to deal in the Software without restriction, including without limitation
141 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
142 * and/or sell copies of the Software, and to permit persons to whom the
143 * Software is furnished to do so, subject to the following conditions:
144 *
145 * The above copyright notice and this permission notice (including the next
146 * paragraph) shall be included in all copies or substantial portions of the
147 * Software.
148 *
149 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
150 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
151 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
152 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
153 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
154 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
155 * IN THE SOFTWARE.
156 */
157
158<% guard_name = '_' + hdrname + '_H' %>
159#ifndef ${guard_name}
160#define ${guard_name}
161
162% for header in HEADERS:
163#include "${header.hdr}"
164% endfor
165
166#include "util/perf/u_trace.h"
167
168#ifdef __cplusplus
169extern "C" {
170#endif
171
172% for declaration in FORWARD_DECLS:
173${declaration.decl};
174% endfor
175
176% for trace_name, trace in TRACEPOINTS.items():
177/*
178 * ${trace_name}
179 */
180struct trace_${trace_name} {
181%    for arg in trace.tp_struct:
182         ${arg.type} ${arg.name};
183%    endfor
184%    if len(trace.args) == 0:
185#ifdef  __cplusplus
186     /* avoid warnings about empty struct size mis-match in C vs C++..
187      * the size mis-match is harmless because (a) nothing will deref
188      * the empty struct, and (b) the code that cares about allocating
189      * sizeof(struct trace_${trace_name}) (and wants this to be zero
190      * if there is no payload) is C
191      */
192     uint8_t dummy;
193#endif
194%    endif
195};
196%    if trace.tp_perfetto is not None:
197#ifdef HAVE_PERFETTO
198void ${trace.tp_perfetto}(${ctx_param}, uint64_t ts_ns, const void *flush_data, const struct trace_${trace_name} *payload);
199#endif
200%    endif
201void __trace_${trace_name}(struct u_trace *ut, void *cs
202%    for arg in trace.args:
203     , ${arg.type} ${arg.var}
204%    endfor
205);
206static inline void trace_${trace_name}(struct u_trace *ut, void *cs
207%    for arg in trace.args:
208     , ${arg.type} ${arg.var}
209%    endfor
210) {
211%    if trace.tp_perfetto is not None:
212   if (!unlikely(ut->enabled || ut_perfetto_enabled))
213%    else:
214   if (!unlikely(ut->enabled))
215%    endif
216      return;
217   __trace_${trace_name}(ut, cs
218%    for arg in trace.args:
219        , ${arg.var}
220%    endfor
221   );
222}
223% endfor
224
225#ifdef __cplusplus
226}
227#endif
228
229#endif /* ${guard_name} */
230"""
231
232src_template = """\
233/* Copyright (C) 2020 Google, Inc.
234 *
235 * Permission is hereby granted, free of charge, to any person obtaining a
236 * copy of this software and associated documentation files (the "Software"),
237 * to deal in the Software without restriction, including without limitation
238 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
239 * and/or sell copies of the Software, and to permit persons to whom the
240 * Software is furnished to do so, subject to the following conditions:
241 *
242 * The above copyright notice and this permission notice (including the next
243 * paragraph) shall be included in all copies or substantial portions of the
244 * Software.
245 *
246 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
247 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
248 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
249 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
250 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
251 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
252 * IN THE SOFTWARE.
253 */
254
255% for header in HEADERS:
256#include "${header.hdr}"
257% endfor
258
259#include "${hdr}"
260
261#define __NEEDS_TRACE_PRIV
262#include "util/perf/u_trace_priv.h"
263
264% for trace_name, trace in TRACEPOINTS.items():
265/*
266 * ${trace_name}
267 */
268%    if trace.args is not None and len(trace.args) > 0:
269static void __print_${trace_name}(FILE *out, const void *arg) {
270   const struct trace_${trace_name} *__entry =
271      (const struct trace_${trace_name} *)arg;
272%    if trace.tp_print is not None:
273   fprintf(out, "${trace.tp_print[0]}\\n"
274%       for arg in trace.tp_print[1:]:
275           , ${arg}
276%       endfor
277% else:
278   fprintf(out, ""
279%  for arg in trace.tp_struct:
280      "${arg.name}=${arg.c_format}, "
281%  endfor
282         "\\n"
283%  for arg in trace.tp_struct:
284   % if arg.to_prim_type:
285   ,${arg.to_prim_type.format('__entry->' + arg.name)}
286   % else:
287   ,__entry->${arg.name}
288   % endif
289%  endfor
290%endif
291   );
292}
293%    else:
294#define __print_${trace_name} NULL
295%    endif
296static const struct u_tracepoint __tp_${trace_name} = {
297    ALIGN_POT(sizeof(struct trace_${trace_name}), 8),   /* keep size 64b aligned */
298    "${trace_name}",
299    __print_${trace_name},
300%    if trace.tp_perfetto is not None:
301#ifdef HAVE_PERFETTO
302    (void (*)(void *pctx, uint64_t, const void *, const void *))${trace.tp_perfetto},
303#endif
304%    endif
305};
306void __trace_${trace_name}(struct u_trace *ut, void *cs
307%    for arg in trace.args:
308     , ${arg.type} ${arg.var}
309%    endfor
310) {
311   struct trace_${trace_name} *__entry =
312      (struct trace_${trace_name} *)u_trace_append(ut, cs, &__tp_${trace_name});
313   (void)__entry;
314%    for arg in trace.tp_struct:
315        __entry->${arg.name} = ${arg.var};
316%    endfor
317}
318
319% endfor
320"""
321
322def utrace_generate(cpath, hpath, ctx_param):
323    if cpath is not None:
324        hdr = os.path.basename(cpath).rsplit('.', 1)[0] + '.h'
325        with open(cpath, 'w') as f:
326            f.write(Template(src_template).render(
327                hdr=hdr,
328                ctx_param=ctx_param,
329                HEADERS=[h for h in HEADERS if h.scope & HeaderScope.SOURCE],
330                TRACEPOINTS=TRACEPOINTS))
331
332    if hpath is not None:
333        hdr = os.path.basename(hpath)
334        with open(hpath, 'w') as f:
335            f.write(Template(hdr_template).render(
336                hdrname=hdr.rstrip('.h').upper(),
337                ctx_param=ctx_param,
338                HEADERS=[h for h in HEADERS if h.scope & HeaderScope.HEADER],
339                FORWARD_DECLS=FORWARD_DECLS,
340                TRACEPOINTS=TRACEPOINTS))
341
342
343perfetto_utils_hdr_template = """\
344/*
345 * Copyright © 2021 Igalia S.L.
346 *
347 * Permission is hereby granted, free of charge, to any person obtaining a
348 * copy of this software and associated documentation files (the "Software"),
349 * to deal in the Software without restriction, including without limitation
350 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
351 * and/or sell copies of the Software, and to permit persons to whom the
352 * Software is furnished to do so, subject to the following conditions:
353 *
354 * The above copyright notice and this permission notice (including the next
355 * paragraph) shall be included in all copies or substantial portions of the
356 * Software.
357 *
358 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
359 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
360 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
361 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
362 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
363 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
364 * SOFTWARE.
365 */
366
367<% guard_name = '_' + hdrname + '_H' %>
368#ifndef ${guard_name}
369#define ${guard_name}
370
371#include <perfetto.h>
372
373% for trace_name, trace in TRACEPOINTS.items():
374static void UNUSED
375trace_payload_as_extra_${trace_name}(perfetto::protos::pbzero::GpuRenderStageEvent *event,
376                                     const struct trace_${trace_name} *payload)
377{
378%  if all([trace.tp_perfetto, trace.tp_struct]) and len(trace.tp_struct) > 0:
379   char buf[128];
380
381%  for arg in trace.tp_struct:
382   {
383      auto data = event->add_extra_data();
384      data->set_name("${arg.name}");
385
386%     if arg.to_prim_type:
387      sprintf(buf, "${arg.c_format}", ${arg.to_prim_type.format('payload->' + arg.name)});
388%     else:
389      sprintf(buf, "${arg.c_format}", payload->${arg.name});
390%     endif
391
392      data->set_value(buf);
393   }
394%  endfor
395
396%  endif
397}
398% endfor
399
400#endif /* ${guard_name} */
401"""
402
403def utrace_generate_perfetto_utils(hpath):
404    if hpath is not None:
405        hdr = os.path.basename(hpath)
406        with open(hpath, 'wb') as f:
407            f.write(Template(perfetto_utils_hdr_template, output_encoding='utf-8').render(
408                hdrname=hdr.rstrip('.h').upper(),
409                TRACEPOINTS=TRACEPOINTS))
410