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 | #!/bin/bash | 1 | #!/bin/bash |
| 2 | 2 | ||
| 3 | # | 3 | # |
| 4 | # print Intel PT Power Events and PTWRITE. The intel_pt PMU event needs | 4 | # print Intel PT Events including Power Events and PTWRITE. The intel_pt PMU |
| 5 | # to be specified with appropriate config terms. | 5 | # event needs to be specified with appropriate config terms. |
| 6 | # | 6 | # |
| 7 | if ! echo "$@" | grep -q intel_pt ; then | 7 | if ! echo "$@" | grep -q intel_pt ; then |
| 8 | echo "Options must include the Intel PT event e.g. -e intel_pt/pwr_evt,ptw/" | 8 | echo "Options must include the Intel PT event e.g. -e intel_pt/pwr_evt,ptw/" |
| @@ -1,3 +1,3 @@ | |||
| 1 | #!/bin/bash | 1 | #!/bin/bash |
| 2 | # description: print Intel PT Power Events and PTWRITE | 2 | # description: print Intel PT Events including Power Events and PTWRITE |
| 3 | perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/intel-pt-events.py | 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 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | # Copyright (c) 2017, Intel Corporation. | 2 | # intel-pt-events.py: Print Intel PT Events including Power Events and PTWRITE |
| 3 | # Copyright (c) 2017-2021, Intel Corporation. | ||
| 3 | # | 4 | # |
| 4 | # This program is free software; you can redistribute it and/or modify it | 5 | # This program is free software; you can redistribute it and/or modify it |
| 5 | # under the terms and conditions of the GNU General Public License, | 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 | #from perf_trace_context import * | 24 | #from perf_trace_context import * |
| 24 | #from Core import * | 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 | def trace_begin(): | 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 | def trace_end(): | 58 | def trace_end(): |
| 30 | print("End") | 59 | print("End") |
| @@ -77,58 +106,110 @@ def print_pwrx(raw_buf): · 46 unmodified lines | |||
| 77 | print("deepest cstate: %u last cstate: %u wake reason: %#x" % | 106 | print("deepest cstate: %u last cstate: %u wake reason: %#x" % |
| 78 | (deepest_cstate, last_cstate, wake_reason), end=' ') | 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 | def print_common_start(comm, sample, name): | 114 | def print_common_start(comm, sample, name): |
| 81 | ts = sample["time"] | 115 | ts = sample["time"] |
| 82 | cpu = sample["cpu"] | 116 | cpu = sample["cpu"] |
| 83 | pid = sample["pid"] | 117 | pid = sample["pid"] |
| 84 | tid = sample["tid"] | 118 | tid = sample["tid"] |
| 85 | print("%16s %5u/%-5u [%03u] %9u.%09u %7s:" % | 119 | flags_disp = get_optional_null(sample, "flags_disp") |
| 86 | (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000, name), | 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 | end=' ') | 128 | end=' ') |
| 88 | 129 | ||
| 89 | def print_common_ip(sample, symbol, dso): | 130 | def print_common_ip(param_dict, sample, symbol, dso): |
| 90 | ip = sample["ip"] | 131 | ip = sample["ip"] |
| 91 | print("%16x %s (%s)" % (ip, symbol, dso)) | 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 | event_attr = param_dict["attr"] | 148 | event_attr = param_dict["attr"] |
| 95 | sample = param_dict["sample"] | 149 | sample = param_dict["sample"] |
| 96 | raw_buf = param_dict["raw_buf"] | 150 | raw_buf = param_dict["raw_buf"] |
| 97 | comm = param_dict["comm"] | 151 | comm = param_dict["comm"] |
| 98 | name = param_dict["ev_name"] | 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 | # Symbol and dso info are not always resolved | 158 | # Symbol and dso info are not always resolved |
| 101 | if "dso" in param_dict: | 159 | dso = get_optional(param_dict, "dso") |
| 102 | dso = param_dict["dso"] | 160 | symbol = get_optional(param_dict, "symbol") |
| 103 | else: | ||
| 104 | dso = "[unknown]" | ||
| 105 | 161 | ||
| 106 | if "symbol" in param_dict: | 162 | print_common_start(comm, sample, name) |
| 107 | symbol = param_dict["symbol"] | ||
| 108 | else: | ||
| 109 | symbol = "[unknown]" | ||
| 110 | 163 | ||
| 111 | if name == "ptwrite": | 164 | if name == "ptwrite": |
| 112 | print_common_start(comm, sample, name) | ||
| 113 | print_ptwrite(raw_buf) | 165 | print_ptwrite(raw_buf) |
| 114 | print_common_ip(sample, symbol, dso) | ||
| 115 | elif name == "cbr": | 166 | elif name == "cbr": |
| 116 | print_common_start(comm, sample, name) | ||
| 117 | print_cbr(raw_buf) | 167 | print_cbr(raw_buf) |
| 118 | print_common_ip(sample, symbol, dso) | ||
| 119 | elif name == "mwait": | 168 | elif name == "mwait": |
| 120 | print_common_start(comm, sample, name) | ||
| 121 | print_mwait(raw_buf) | 169 | print_mwait(raw_buf) |
| 122 | print_common_ip(sample, symbol, dso) | ||
| 123 | elif name == "pwre": | 170 | elif name == "pwre": |
| 124 | print_common_start(comm, sample, name) | ||
| 125 | print_pwre(raw_buf) | 171 | print_pwre(raw_buf) |
| 126 | print_common_ip(sample, symbol, dso) | ||
| 127 | elif name == "exstop": | 172 | elif name == "exstop": |
| 128 | print_common_start(comm, sample, name) | ||
| 129 | print_exstop(raw_buf) | 173 | print_exstop(raw_buf) |
| 130 | print_common_ip(sample, symbol, dso) | ||
| 131 | elif name == "pwrx": | 174 | elif name == "pwrx": |
| 132 | print_common_start(comm, sample, name) | ||
| 133 | print_pwrx(raw_buf) | 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 | ||