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