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