As an example, add branch information to intel-pt-events.py script. This shows how a simple python script can be used to customize perf script output for Intel PT branch traces or power event traces.
Showing the changes to tools/perf/scripts/python (3 of 3 files). Show all
Unified · Split
| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | #!/bin/bash |
| 2 | 2 | |
| 3 | 3 | # |
| 4 | −# print Intel PT Power Events and PTWRITE. The intel_pt PMU event needs | |
| 5 | −# to be specified with appropriate config terms. | |
| 4 | +# print Intel PT Events including Power Events and PTWRITE. The intel_pt PMU | |
| 5 | +# event needs to be specified with appropriate config terms. | |
| 6 | 6 | # |
| 7 | 7 | if ! echo "$@" | grep -q intel_pt ; then |
| 8 | 8 | echo "Options must include the Intel PT event e.g. -e intel_pt/pwr_evt,ptw/" |
| @@ -1,3 +1,3 @@ | ||
| 1 | 1 | #!/bin/bash |
| 2 | −# description: print Intel PT Power Events and PTWRITE | |
| 3 | −perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/intel-pt-events.py | |
| 2 | +# description: print Intel PT Events including Power Events and PTWRITE | |
| 3 | +perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/intel-pt-events.py | |
| @@ -1,5 +1,6 @@ | ||
| 1 | −# intel-pt-events.py: Print Intel PT Power Events and PTWRITE | |
| 2 | −# Copyright (c) 2017, Intel Corporation. | |
| 1 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | +# intel-pt-events.py: Print Intel PT Events including Power Events and PTWRITE | |
| 3 | +# Copyright (c) 2017-2021, Intel Corporation. | |
| 3 | 4 | # |
| 4 | 5 | # This program is free software; you can redistribute it and/or modify it |
| 5 | 6 | # under the terms and conditions of the GNU General Public License, |
| @@ -23,8 +24,36 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \ · 17 unmodified lines | ||
| 23 | 24 | #from perf_trace_context import * |
| 24 | 25 | #from Core import * |
| 25 | 26 | |
| 27 | +try: | |
| 28 | + broken_pipe_exception = BrokenPipeError | |
| 29 | +except: | |
| 30 | + broken_pipe_exception = IOError | |
| 31 | + | |
| 32 | +glb_switch_str = None | |
| 33 | +glb_switch_printed = True | |
| 34 | + | |
| 35 | +def get_optional_null(perf_dict, field): | |
| 36 | + if field in perf_dict: | |
| 37 | + return perf_dict[field] | |
| 38 | + return "" | |
| 39 | + | |
| 40 | +def get_optional_zero(perf_dict, field): | |
| 41 | + if field in perf_dict: | |
| 42 | + return perf_dict[field] | |
| 43 | + return 0 | |
| 44 | + | |
| 45 | +def get_optional(perf_dict, field): | |
| 46 | + if field in perf_dict: | |
| 47 | + return perf_dict[field] | |
| 48 | + return "[unknown]" | |
| 49 | + | |
| 50 | +def get_offset(perf_dict, field): | |
| 51 | + if field in perf_dict: | |
| 52 | + return "+%#x" % perf_dict[field] | |
| 53 | + return "" | |
| 54 | + | |
| 26 | 55 | def trace_begin(): |
| 27 | − print("Intel PT Power Events and PTWRITE") | |
| 56 | + print("Intel PT Branch Trace, Power Events and PTWRITE") | |
| 28 | 57 | |
| 29 | 58 | def trace_end(): |
| 30 | 59 | print("End") |
| @@ -77,58 +106,110 @@ def print_pwrx(raw_buf): · 46 unmodified lines | ||
| 77 | 106 | print("deepest cstate: %u last cstate: %u wake reason: %#x" % |
| 78 | 107 | (deepest_cstate, last_cstate, wake_reason), end=' ') |
| 79 | 108 | |
| 109 | +def print_psb(raw_buf): | |
| 110 | + data = struct.unpack_from("<IQ", raw_buf) | |
| 111 | + offset = data[1] | |
| 112 | + print("offset: %#x" % (offset), end=' ') | |
| 113 | + | |
| 80 | 114 | def print_common_start(comm, sample, name): |
| 81 | 115 | ts = sample["time"] |
| 82 | 116 | cpu = sample["cpu"] |
| 83 | 117 | pid = sample["pid"] |
| 84 | 118 | tid = sample["tid"] |
| 85 | − print("%16s %5u/%-5u [%03u] %9u.%09u %7s:" % | |
| 86 | − (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000, name), | |
| 119 | + flags_disp = get_optional_null(sample, "flags_disp") | |
| 120 | + # Unused fields: | |
| 121 | + # period = sample["period"] | |
| 122 | + # phys_addr = sample["phys_addr"] | |
| 123 | + # weight = sample["weight"] | |
| 124 | + # transaction = sample["transaction"] | |
| 125 | + # cpumode = get_optional_zero(sample, "cpumode") | |
| 126 | + print("%16s %5u/%-5u [%03u] %9u.%09u %7s %19s" % | |
| 127 | + (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000, name, flags_disp), | |
| 87 | 128 | end=' ') |
| 88 | 129 | |
| 89 | −def print_common_ip(sample, symbol, dso): | |
| 90 | − ip = sample["ip"] | |
| 91 | − print("%16x %s (%s)" % (ip, symbol, dso)) | |
| 130 | +def print_common_ip(param_dict, sample, symbol, dso): | |
| 131 | + ip = sample["ip"] | |
| 132 | + offs = get_offset(param_dict, "symoff") | |
| 133 | + print("%16x %s%s (%s)" % (ip, symbol, offs, dso), end=' ') | |
| 134 | + if "addr_correlates_sym" in sample: | |
| 135 | + addr = sample["addr"] | |
| 136 | + dso = get_optional(sample, "addr_dso") | |
| 137 | + symbol = get_optional(sample, "addr_symbol") | |
| 138 | + offs = get_offset(sample, "addr_symoff") | |
| 139 | + print("=> %x %s%s (%s)" % (addr, symbol, offs, dso)) | |
| 140 | + else: | |
| 141 | + print() | |
| 92 | 142 | |
| 93 | −def process_event(param_dict): | |
| 143 | +def do_process_event(param_dict): | |
| 144 | + global glb_switch_printed | |
| 145 | + if not glb_switch_printed: | |
| 146 | + print(glb_switch_str) | |
| 147 | + glb_switch_printed = True | |
| 94 | 148 | event_attr = param_dict["attr"] |
| 95 | − sample = param_dict["sample"] | |
| 96 | − raw_buf = param_dict["raw_buf"] | |
| 149 | + sample = param_dict["sample"] | |
| 150 | + raw_buf = param_dict["raw_buf"] | |
| 97 | 151 | comm = param_dict["comm"] |
| 98 | 152 | name = param_dict["ev_name"] |
| 153 | + # Unused fields: | |
| 154 | + # callchain = param_dict["callchain"] | |
| 155 | + # brstack = param_dict["brstack"] | |
| 156 | + # brstacksym = param_dict["brstacksym"] | |
| 99 | 157 | |
| 100 | 158 | # Symbol and dso info are not always resolved |
| 101 | − if "dso" in param_dict: | |
| 102 | − dso = param_dict["dso"] | |
| 103 | − else: | |
| 104 | − dso = "[unknown]" | |
| 159 | + dso = get_optional(param_dict, "dso") | |
| 160 | + symbol = get_optional(param_dict, "symbol") | |
| 105 | 161 | |
| 106 | − if "symbol" in param_dict: | |
| 107 | − symbol = param_dict["symbol"] | |
| 108 | − else: | |
| 109 | − symbol = "[unknown]" | |
| 162 | + print_common_start(comm, sample, name) | |
| 110 | 163 | |
| 111 | 164 | if name == "ptwrite": |
| 112 | − print_common_start(comm, sample, name) | |
| 113 | 165 | print_ptwrite(raw_buf) |
| 114 | − print_common_ip(sample, symbol, dso) | |
| 115 | 166 | elif name == "cbr": |
| 116 | − print_common_start(comm, sample, name) | |
| 117 | 167 | print_cbr(raw_buf) |
| 118 | − print_common_ip(sample, symbol, dso) | |
| 119 | 168 | elif name == "mwait": |
| 120 | − print_common_start(comm, sample, name) | |
| 121 | 169 | print_mwait(raw_buf) |
| 122 | − print_common_ip(sample, symbol, dso) | |
| 123 | 170 | elif name == "pwre": |
| 124 | − print_common_start(comm, sample, name) | |
| 125 | 171 | print_pwre(raw_buf) |
| 126 | − print_common_ip(sample, symbol, dso) | |
| 127 | 172 | elif name == "exstop": |
| 128 | − print_common_start(comm, sample, name) | |
| 129 | 173 | print_exstop(raw_buf) |
| 130 | − print_common_ip(sample, symbol, dso) | |
| 131 | 174 | elif name == "pwrx": |
| 132 | − print_common_start(comm, sample, name) | |
| 133 | 175 | print_pwrx(raw_buf) |
| 134 | − print_common_ip(sample, symbol, dso) | |
| 176 | + elif name == "psb": | |
| 177 | + print_psb(raw_buf) | |
| 178 | + | |
| 179 | + print_common_ip(param_dict, sample, symbol, dso) | |
| 180 | + | |
| 181 | +def process_event(param_dict): | |
| 182 | + try: | |
| 183 | + do_process_event(param_dict) | |
| 184 | + except broken_pipe_exception: | |
| 185 | + # Stop python printing broken pipe errors and traceback | |
| 186 | + sys.stdout = open(os.devnull, 'w') | |
| 187 | + sys.exit(1) | |
| 188 | + | |
| 189 | +def auxtrace_error(typ, code, cpu, pid, tid, ip, ts, msg, cpumode, *x): | |
| 190 | + try: | |
| 191 | + print("%16s %5u/%-5u [%03u] %9u.%09u error type %u code %u: %s ip 0x%16x" % | |
| 192 | + ("Trace error", pid, tid, cpu, ts / 1000000000, ts %1000000000, typ, code, msg, ip)) | |
| 193 | + except broken_pipe_exception: | |
| 194 | + # Stop python printing broken pipe errors and traceback | |
| 195 | + sys.stdout = open(os.devnull, 'w') | |
| 196 | + sys.exit(1) | |
| 197 | + | |
| 198 | +def context_switch(ts, cpu, pid, tid, np_pid, np_tid, machine_pid, out, out_preempt, *x): | |
| 199 | + global glb_switch_printed | |
| 200 | + global glb_switch_str | |
| 201 | + if out: | |
| 202 | + out_str = "Switch out " | |
| 203 | + else: | |
| 204 | + out_str = "Switch In " | |
| 205 | + if out_preempt: | |
| 206 | + preempt_str = "preempt" | |
| 207 | + else: | |
| 208 | + preempt_str = "" | |
| 209 | + if machine_pid == -1: | |
| 210 | + machine_str = "" | |
| 211 | + else: | |
| 212 | + machine_str = "machine PID %d" % machine_pid | |
| 213 | + glb_switch_str = "%16s %5d/%-5d [%03u] %9u.%09u %5d/%-5d %s %s" % \ | |
| 214 | + (out_str, pid, tid, cpu, ts / 1000000000, ts %1000000000, np_pid, np_tid, machine_str, preempt_str) | |
| 215 | + glb_switch_printed = False | |