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