| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
|---|
| 2 | 2 | #include "builtin.h" |
|---|
| 3 | 3 | |
|---|
| 4 | | -#include "perf.h" |
|---|
| 5 | | -#include "util/cache.h" |
|---|
| 4 | +#include "util/counts.h" |
|---|
| 6 | 5 | #include "util/debug.h" |
|---|
| 6 | +#include "util/dso.h" |
|---|
| 7 | 7 | #include <subcmd/exec-cmd.h> |
|---|
| 8 | 8 | #include "util/header.h" |
|---|
| 9 | 9 | #include <subcmd/parse-options.h> |
|---|
| 10 | 10 | #include "util/perf_regs.h" |
|---|
| 11 | 11 | #include "util/session.h" |
|---|
| 12 | 12 | #include "util/tool.h" |
|---|
| 13 | +#include "util/map.h" |
|---|
| 14 | +#include "util/srcline.h" |
|---|
| 13 | 15 | #include "util/symbol.h" |
|---|
| 14 | 16 | #include "util/thread.h" |
|---|
| 15 | 17 | #include "util/trace-event.h" |
|---|
| 16 | | -#include "util/util.h" |
|---|
| 17 | 18 | #include "util/evlist.h" |
|---|
| 18 | 19 | #include "util/evsel.h" |
|---|
| 20 | +#include "util/evsel_fprintf.h" |
|---|
| 21 | +#include "util/evswitch.h" |
|---|
| 19 | 22 | #include "util/sort.h" |
|---|
| 20 | 23 | #include "util/data.h" |
|---|
| 21 | 24 | #include "util/auxtrace.h" |
|---|
| .. | .. |
|---|
| 27 | 30 | #include "util/thread-stack.h" |
|---|
| 28 | 31 | #include "util/time-utils.h" |
|---|
| 29 | 32 | #include "util/path.h" |
|---|
| 33 | +#include "ui/ui.h" |
|---|
| 30 | 34 | #include "print_binary.h" |
|---|
| 35 | +#include "archinsn.h" |
|---|
| 31 | 36 | #include <linux/bitmap.h> |
|---|
| 32 | 37 | #include <linux/kernel.h> |
|---|
| 33 | 38 | #include <linux/stringify.h> |
|---|
| 34 | 39 | #include <linux/time64.h> |
|---|
| 40 | +#include <linux/zalloc.h> |
|---|
| 41 | +#include <sys/utsname.h> |
|---|
| 35 | 42 | #include "asm/bug.h" |
|---|
| 36 | 43 | #include "util/mem-events.h" |
|---|
| 37 | 44 | #include "util/dump-insn.h" |
|---|
| .. | .. |
|---|
| 44 | 51 | #include <sys/stat.h> |
|---|
| 45 | 52 | #include <fcntl.h> |
|---|
| 46 | 53 | #include <unistd.h> |
|---|
| 54 | +#include <subcmd/pager.h> |
|---|
| 55 | +#include <perf/evlist.h> |
|---|
| 56 | +#include <linux/err.h> |
|---|
| 57 | +#include "util/record.h" |
|---|
| 58 | +#include "util/util.h" |
|---|
| 59 | +#include "perf.h" |
|---|
| 47 | 60 | |
|---|
| 48 | | -#include "sane_ctype.h" |
|---|
| 61 | +#include <linux/ctype.h> |
|---|
| 49 | 62 | |
|---|
| 50 | 63 | static char const *script_name; |
|---|
| 51 | 64 | static char const *generate_script_lang; |
|---|
| 65 | +static bool reltime; |
|---|
| 66 | +static bool deltatime; |
|---|
| 67 | +static u64 initial_time; |
|---|
| 68 | +static u64 previous_time; |
|---|
| 52 | 69 | static bool debug_mode; |
|---|
| 53 | 70 | static u64 last_timestamp; |
|---|
| 54 | 71 | static u64 nr_unordered; |
|---|
| .. | .. |
|---|
| 56 | 73 | static bool latency_format; |
|---|
| 57 | 74 | static bool system_wide; |
|---|
| 58 | 75 | static bool print_flags; |
|---|
| 59 | | -static bool nanosecs; |
|---|
| 60 | 76 | static const char *cpu_list; |
|---|
| 61 | 77 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
|---|
| 62 | 78 | static struct perf_stat_config stat_config; |
|---|
| 63 | 79 | static int max_blocks; |
|---|
| 80 | +static bool native_arch; |
|---|
| 64 | 81 | |
|---|
| 65 | 82 | unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; |
|---|
| 66 | 83 | |
|---|
| 67 | 84 | enum perf_output_field { |
|---|
| 68 | | - PERF_OUTPUT_COMM = 1U << 0, |
|---|
| 69 | | - PERF_OUTPUT_TID = 1U << 1, |
|---|
| 70 | | - PERF_OUTPUT_PID = 1U << 2, |
|---|
| 71 | | - PERF_OUTPUT_TIME = 1U << 3, |
|---|
| 72 | | - PERF_OUTPUT_CPU = 1U << 4, |
|---|
| 73 | | - PERF_OUTPUT_EVNAME = 1U << 5, |
|---|
| 74 | | - PERF_OUTPUT_TRACE = 1U << 6, |
|---|
| 75 | | - PERF_OUTPUT_IP = 1U << 7, |
|---|
| 76 | | - PERF_OUTPUT_SYM = 1U << 8, |
|---|
| 77 | | - PERF_OUTPUT_DSO = 1U << 9, |
|---|
| 78 | | - PERF_OUTPUT_ADDR = 1U << 10, |
|---|
| 79 | | - PERF_OUTPUT_SYMOFFSET = 1U << 11, |
|---|
| 80 | | - PERF_OUTPUT_SRCLINE = 1U << 12, |
|---|
| 81 | | - PERF_OUTPUT_PERIOD = 1U << 13, |
|---|
| 82 | | - PERF_OUTPUT_IREGS = 1U << 14, |
|---|
| 83 | | - PERF_OUTPUT_BRSTACK = 1U << 15, |
|---|
| 84 | | - PERF_OUTPUT_BRSTACKSYM = 1U << 16, |
|---|
| 85 | | - PERF_OUTPUT_DATA_SRC = 1U << 17, |
|---|
| 86 | | - PERF_OUTPUT_WEIGHT = 1U << 18, |
|---|
| 87 | | - PERF_OUTPUT_BPF_OUTPUT = 1U << 19, |
|---|
| 88 | | - PERF_OUTPUT_CALLINDENT = 1U << 20, |
|---|
| 89 | | - PERF_OUTPUT_INSN = 1U << 21, |
|---|
| 90 | | - PERF_OUTPUT_INSNLEN = 1U << 22, |
|---|
| 91 | | - PERF_OUTPUT_BRSTACKINSN = 1U << 23, |
|---|
| 92 | | - PERF_OUTPUT_BRSTACKOFF = 1U << 24, |
|---|
| 93 | | - PERF_OUTPUT_SYNTH = 1U << 25, |
|---|
| 94 | | - PERF_OUTPUT_PHYS_ADDR = 1U << 26, |
|---|
| 95 | | - PERF_OUTPUT_UREGS = 1U << 27, |
|---|
| 96 | | - PERF_OUTPUT_METRIC = 1U << 28, |
|---|
| 97 | | - PERF_OUTPUT_MISC = 1U << 29, |
|---|
| 85 | + PERF_OUTPUT_COMM = 1ULL << 0, |
|---|
| 86 | + PERF_OUTPUT_TID = 1ULL << 1, |
|---|
| 87 | + PERF_OUTPUT_PID = 1ULL << 2, |
|---|
| 88 | + PERF_OUTPUT_TIME = 1ULL << 3, |
|---|
| 89 | + PERF_OUTPUT_CPU = 1ULL << 4, |
|---|
| 90 | + PERF_OUTPUT_EVNAME = 1ULL << 5, |
|---|
| 91 | + PERF_OUTPUT_TRACE = 1ULL << 6, |
|---|
| 92 | + PERF_OUTPUT_IP = 1ULL << 7, |
|---|
| 93 | + PERF_OUTPUT_SYM = 1ULL << 8, |
|---|
| 94 | + PERF_OUTPUT_DSO = 1ULL << 9, |
|---|
| 95 | + PERF_OUTPUT_ADDR = 1ULL << 10, |
|---|
| 96 | + PERF_OUTPUT_SYMOFFSET = 1ULL << 11, |
|---|
| 97 | + PERF_OUTPUT_SRCLINE = 1ULL << 12, |
|---|
| 98 | + PERF_OUTPUT_PERIOD = 1ULL << 13, |
|---|
| 99 | + PERF_OUTPUT_IREGS = 1ULL << 14, |
|---|
| 100 | + PERF_OUTPUT_BRSTACK = 1ULL << 15, |
|---|
| 101 | + PERF_OUTPUT_BRSTACKSYM = 1ULL << 16, |
|---|
| 102 | + PERF_OUTPUT_DATA_SRC = 1ULL << 17, |
|---|
| 103 | + PERF_OUTPUT_WEIGHT = 1ULL << 18, |
|---|
| 104 | + PERF_OUTPUT_BPF_OUTPUT = 1ULL << 19, |
|---|
| 105 | + PERF_OUTPUT_CALLINDENT = 1ULL << 20, |
|---|
| 106 | + PERF_OUTPUT_INSN = 1ULL << 21, |
|---|
| 107 | + PERF_OUTPUT_INSNLEN = 1ULL << 22, |
|---|
| 108 | + PERF_OUTPUT_BRSTACKINSN = 1ULL << 23, |
|---|
| 109 | + PERF_OUTPUT_BRSTACKOFF = 1ULL << 24, |
|---|
| 110 | + PERF_OUTPUT_SYNTH = 1ULL << 25, |
|---|
| 111 | + PERF_OUTPUT_PHYS_ADDR = 1ULL << 26, |
|---|
| 112 | + PERF_OUTPUT_UREGS = 1ULL << 27, |
|---|
| 113 | + PERF_OUTPUT_METRIC = 1ULL << 28, |
|---|
| 114 | + PERF_OUTPUT_MISC = 1ULL << 29, |
|---|
| 115 | + PERF_OUTPUT_SRCCODE = 1ULL << 30, |
|---|
| 116 | + PERF_OUTPUT_IPC = 1ULL << 31, |
|---|
| 117 | + PERF_OUTPUT_TOD = 1ULL << 32, |
|---|
| 118 | +}; |
|---|
| 119 | + |
|---|
| 120 | +struct perf_script { |
|---|
| 121 | + struct perf_tool tool; |
|---|
| 122 | + struct perf_session *session; |
|---|
| 123 | + bool show_task_events; |
|---|
| 124 | + bool show_mmap_events; |
|---|
| 125 | + bool show_switch_events; |
|---|
| 126 | + bool show_namespace_events; |
|---|
| 127 | + bool show_lost_events; |
|---|
| 128 | + bool show_round_events; |
|---|
| 129 | + bool show_bpf_events; |
|---|
| 130 | + bool show_cgroup_events; |
|---|
| 131 | + bool show_text_poke_events; |
|---|
| 132 | + bool allocated; |
|---|
| 133 | + bool per_event_dump; |
|---|
| 134 | + bool stitch_lbr; |
|---|
| 135 | + struct evswitch evswitch; |
|---|
| 136 | + struct perf_cpu_map *cpus; |
|---|
| 137 | + struct perf_thread_map *threads; |
|---|
| 138 | + int name_width; |
|---|
| 139 | + const char *time_str; |
|---|
| 140 | + struct perf_time_interval *ptime_range; |
|---|
| 141 | + int range_size; |
|---|
| 142 | + int range_num; |
|---|
| 98 | 143 | }; |
|---|
| 99 | 144 | |
|---|
| 100 | 145 | struct output_option { |
|---|
| .. | .. |
|---|
| 131 | 176 | {.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR}, |
|---|
| 132 | 177 | {.str = "metric", .field = PERF_OUTPUT_METRIC}, |
|---|
| 133 | 178 | {.str = "misc", .field = PERF_OUTPUT_MISC}, |
|---|
| 179 | + {.str = "srccode", .field = PERF_OUTPUT_SRCCODE}, |
|---|
| 180 | + {.str = "ipc", .field = PERF_OUTPUT_IPC}, |
|---|
| 181 | + {.str = "tod", .field = PERF_OUTPUT_TOD}, |
|---|
| 134 | 182 | }; |
|---|
| 135 | 183 | |
|---|
| 136 | 184 | enum { |
|---|
| .. | .. |
|---|
| 145 | 193 | unsigned int print_ip_opts; |
|---|
| 146 | 194 | u64 fields; |
|---|
| 147 | 195 | u64 invalid_fields; |
|---|
| 196 | + u64 user_set_fields; |
|---|
| 197 | + u64 user_unset_fields; |
|---|
| 148 | 198 | } output[OUTPUT_TYPE_MAX] = { |
|---|
| 149 | 199 | |
|---|
| 150 | 200 | [PERF_TYPE_HARDWARE] = { |
|---|
| .. | .. |
|---|
| 231 | 281 | }, |
|---|
| 232 | 282 | }; |
|---|
| 233 | 283 | |
|---|
| 234 | | -struct perf_evsel_script { |
|---|
| 284 | +struct evsel_script { |
|---|
| 235 | 285 | char *filename; |
|---|
| 236 | 286 | FILE *fp; |
|---|
| 237 | 287 | u64 samples; |
|---|
| .. | .. |
|---|
| 240 | 290 | int gnum; |
|---|
| 241 | 291 | }; |
|---|
| 242 | 292 | |
|---|
| 243 | | -static inline struct perf_evsel_script *evsel_script(struct perf_evsel *evsel) |
|---|
| 293 | +static inline struct evsel_script *evsel_script(struct evsel *evsel) |
|---|
| 244 | 294 | { |
|---|
| 245 | | - return (struct perf_evsel_script *)evsel->priv; |
|---|
| 295 | + return (struct evsel_script *)evsel->priv; |
|---|
| 246 | 296 | } |
|---|
| 247 | 297 | |
|---|
| 248 | | -static struct perf_evsel_script *perf_evsel_script__new(struct perf_evsel *evsel, |
|---|
| 249 | | - struct perf_data *data) |
|---|
| 298 | +static struct evsel_script *evsel_script__new(struct evsel *evsel, struct perf_data *data) |
|---|
| 250 | 299 | { |
|---|
| 251 | | - struct perf_evsel_script *es = zalloc(sizeof(*es)); |
|---|
| 300 | + struct evsel_script *es = zalloc(sizeof(*es)); |
|---|
| 252 | 301 | |
|---|
| 253 | 302 | if (es != NULL) { |
|---|
| 254 | | - if (asprintf(&es->filename, "%s.%s.dump", data->file.path, perf_evsel__name(evsel)) < 0) |
|---|
| 303 | + if (asprintf(&es->filename, "%s.%s.dump", data->file.path, evsel__name(evsel)) < 0) |
|---|
| 255 | 304 | goto out_free; |
|---|
| 256 | 305 | es->fp = fopen(es->filename, "w"); |
|---|
| 257 | 306 | if (es->fp == NULL) |
|---|
| .. | .. |
|---|
| 266 | 315 | return NULL; |
|---|
| 267 | 316 | } |
|---|
| 268 | 317 | |
|---|
| 269 | | -static void perf_evsel_script__delete(struct perf_evsel_script *es) |
|---|
| 318 | +static void evsel_script__delete(struct evsel_script *es) |
|---|
| 270 | 319 | { |
|---|
| 271 | 320 | zfree(&es->filename); |
|---|
| 272 | 321 | fclose(es->fp); |
|---|
| .. | .. |
|---|
| 274 | 323 | free(es); |
|---|
| 275 | 324 | } |
|---|
| 276 | 325 | |
|---|
| 277 | | -static int perf_evsel_script__fprintf(struct perf_evsel_script *es, FILE *fp) |
|---|
| 326 | +static int evsel_script__fprintf(struct evsel_script *es, FILE *fp) |
|---|
| 278 | 327 | { |
|---|
| 279 | 328 | struct stat st; |
|---|
| 280 | 329 | |
|---|
| .. | .. |
|---|
| 329 | 378 | |
|---|
| 330 | 379 | #define PRINT_FIELD(x) (output[output_type(attr->type)].fields & PERF_OUTPUT_##x) |
|---|
| 331 | 380 | |
|---|
| 332 | | -static int perf_evsel__do_check_stype(struct perf_evsel *evsel, |
|---|
| 333 | | - u64 sample_type, const char *sample_msg, |
|---|
| 334 | | - enum perf_output_field field, |
|---|
| 335 | | - bool allow_user_set) |
|---|
| 381 | +static int evsel__do_check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg, |
|---|
| 382 | + enum perf_output_field field, bool allow_user_set) |
|---|
| 336 | 383 | { |
|---|
| 337 | | - struct perf_event_attr *attr = &evsel->attr; |
|---|
| 384 | + struct perf_event_attr *attr = &evsel->core.attr; |
|---|
| 338 | 385 | int type = output_type(attr->type); |
|---|
| 339 | 386 | const char *evname; |
|---|
| 340 | 387 | |
|---|
| 341 | 388 | if (attr->sample_type & sample_type) |
|---|
| 342 | 389 | return 0; |
|---|
| 343 | 390 | |
|---|
| 344 | | - if (output[type].user_set) { |
|---|
| 391 | + if (output[type].user_set_fields & field) { |
|---|
| 345 | 392 | if (allow_user_set) |
|---|
| 346 | 393 | return 0; |
|---|
| 347 | | - evname = perf_evsel__name(evsel); |
|---|
| 394 | + evname = evsel__name(evsel); |
|---|
| 348 | 395 | pr_err("Samples for '%s' event do not have %s attribute set. " |
|---|
| 349 | 396 | "Cannot print '%s' field.\n", |
|---|
| 350 | 397 | evname, sample_msg, output_field2str(field)); |
|---|
| .. | .. |
|---|
| 353 | 400 | |
|---|
| 354 | 401 | /* user did not ask for it explicitly so remove from the default list */ |
|---|
| 355 | 402 | output[type].fields &= ~field; |
|---|
| 356 | | - evname = perf_evsel__name(evsel); |
|---|
| 403 | + evname = evsel__name(evsel); |
|---|
| 357 | 404 | pr_debug("Samples for '%s' event do not have %s attribute set. " |
|---|
| 358 | 405 | "Skipping '%s' field.\n", |
|---|
| 359 | 406 | evname, sample_msg, output_field2str(field)); |
|---|
| .. | .. |
|---|
| 361 | 408 | return 0; |
|---|
| 362 | 409 | } |
|---|
| 363 | 410 | |
|---|
| 364 | | -static int perf_evsel__check_stype(struct perf_evsel *evsel, |
|---|
| 365 | | - u64 sample_type, const char *sample_msg, |
|---|
| 366 | | - enum perf_output_field field) |
|---|
| 411 | +static int evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg, |
|---|
| 412 | + enum perf_output_field field) |
|---|
| 367 | 413 | { |
|---|
| 368 | | - return perf_evsel__do_check_stype(evsel, sample_type, sample_msg, field, |
|---|
| 369 | | - false); |
|---|
| 414 | + return evsel__do_check_stype(evsel, sample_type, sample_msg, field, false); |
|---|
| 370 | 415 | } |
|---|
| 371 | 416 | |
|---|
| 372 | | -static int perf_evsel__check_attr(struct perf_evsel *evsel, |
|---|
| 373 | | - struct perf_session *session) |
|---|
| 417 | +static int evsel__check_attr(struct evsel *evsel, struct perf_session *session) |
|---|
| 374 | 418 | { |
|---|
| 375 | | - struct perf_event_attr *attr = &evsel->attr; |
|---|
| 419 | + struct perf_event_attr *attr = &evsel->core.attr; |
|---|
| 376 | 420 | bool allow_user_set; |
|---|
| 377 | 421 | |
|---|
| 378 | 422 | if (perf_header__has_feat(&session->header, HEADER_STAT)) |
|---|
| .. | .. |
|---|
| 382 | 426 | HEADER_AUXTRACE); |
|---|
| 383 | 427 | |
|---|
| 384 | 428 | if (PRINT_FIELD(TRACE) && |
|---|
| 385 | | - !perf_session__has_traces(session, "record -R")) |
|---|
| 429 | + !perf_session__has_traces(session, "record -R")) |
|---|
| 386 | 430 | return -EINVAL; |
|---|
| 387 | 431 | |
|---|
| 388 | 432 | if (PRINT_FIELD(IP)) { |
|---|
| 389 | | - if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", |
|---|
| 390 | | - PERF_OUTPUT_IP)) |
|---|
| 433 | + if (evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", PERF_OUTPUT_IP)) |
|---|
| 391 | 434 | return -EINVAL; |
|---|
| 392 | 435 | } |
|---|
| 393 | 436 | |
|---|
| 394 | 437 | if (PRINT_FIELD(ADDR) && |
|---|
| 395 | | - perf_evsel__do_check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR", |
|---|
| 396 | | - PERF_OUTPUT_ADDR, allow_user_set)) |
|---|
| 438 | + evsel__do_check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR", PERF_OUTPUT_ADDR, allow_user_set)) |
|---|
| 397 | 439 | return -EINVAL; |
|---|
| 398 | 440 | |
|---|
| 399 | 441 | if (PRINT_FIELD(DATA_SRC) && |
|---|
| 400 | | - perf_evsel__check_stype(evsel, PERF_SAMPLE_DATA_SRC, "DATA_SRC", |
|---|
| 401 | | - PERF_OUTPUT_DATA_SRC)) |
|---|
| 442 | + evsel__check_stype(evsel, PERF_SAMPLE_DATA_SRC, "DATA_SRC", PERF_OUTPUT_DATA_SRC)) |
|---|
| 402 | 443 | return -EINVAL; |
|---|
| 403 | 444 | |
|---|
| 404 | 445 | if (PRINT_FIELD(WEIGHT) && |
|---|
| 405 | | - perf_evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT, "WEIGHT", |
|---|
| 406 | | - PERF_OUTPUT_WEIGHT)) |
|---|
| 446 | + evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT, "WEIGHT", PERF_OUTPUT_WEIGHT)) |
|---|
| 407 | 447 | return -EINVAL; |
|---|
| 408 | 448 | |
|---|
| 409 | | - if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { |
|---|
| 449 | + if (PRINT_FIELD(SYM) && |
|---|
| 450 | + !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) { |
|---|
| 410 | 451 | pr_err("Display of symbols requested but neither sample IP nor " |
|---|
| 411 | | - "sample address\nis selected. Hence, no addresses to convert " |
|---|
| 452 | + "sample address\navailable. Hence, no addresses to convert " |
|---|
| 412 | 453 | "to symbols.\n"); |
|---|
| 413 | 454 | return -EINVAL; |
|---|
| 414 | 455 | } |
|---|
| .. | .. |
|---|
| 417 | 458 | "selected.\n"); |
|---|
| 418 | 459 | return -EINVAL; |
|---|
| 419 | 460 | } |
|---|
| 420 | | - if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR) && |
|---|
| 421 | | - !PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM) && !PRINT_FIELD(BRSTACKOFF)) { |
|---|
| 422 | | - pr_err("Display of DSO requested but no address to convert. Select\n" |
|---|
| 423 | | - "sample IP, sample address, brstack, brstacksym, or brstackoff.\n"); |
|---|
| 461 | + if (PRINT_FIELD(DSO) && |
|---|
| 462 | + !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) { |
|---|
| 463 | + pr_err("Display of DSO requested but no address to convert.\n"); |
|---|
| 424 | 464 | return -EINVAL; |
|---|
| 425 | 465 | } |
|---|
| 426 | | - if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { |
|---|
| 466 | + if ((PRINT_FIELD(SRCLINE) || PRINT_FIELD(SRCCODE)) && !PRINT_FIELD(IP)) { |
|---|
| 427 | 467 | pr_err("Display of source line number requested but sample IP is not\n" |
|---|
| 428 | 468 | "selected. Hence, no address to lookup the source line number.\n"); |
|---|
| 429 | 469 | return -EINVAL; |
|---|
| 430 | 470 | } |
|---|
| 431 | 471 | if (PRINT_FIELD(BRSTACKINSN) && !allow_user_set && |
|---|
| 432 | | - !(perf_evlist__combined_branch_type(session->evlist) & |
|---|
| 433 | | - PERF_SAMPLE_BRANCH_ANY)) { |
|---|
| 472 | + !(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_ANY)) { |
|---|
| 434 | 473 | pr_err("Display of branch stack assembler requested, but non all-branch filter set\n" |
|---|
| 435 | 474 | "Hint: run 'perf record -b ...'\n"); |
|---|
| 436 | 475 | return -EINVAL; |
|---|
| 437 | 476 | } |
|---|
| 438 | 477 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && |
|---|
| 439 | | - perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", |
|---|
| 440 | | - PERF_OUTPUT_TID|PERF_OUTPUT_PID)) |
|---|
| 478 | + evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", PERF_OUTPUT_TID|PERF_OUTPUT_PID)) |
|---|
| 441 | 479 | return -EINVAL; |
|---|
| 442 | 480 | |
|---|
| 443 | 481 | if (PRINT_FIELD(TIME) && |
|---|
| 444 | | - perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME", |
|---|
| 445 | | - PERF_OUTPUT_TIME)) |
|---|
| 482 | + evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME", PERF_OUTPUT_TIME)) |
|---|
| 446 | 483 | return -EINVAL; |
|---|
| 447 | 484 | |
|---|
| 448 | 485 | if (PRINT_FIELD(CPU) && |
|---|
| 449 | | - perf_evsel__do_check_stype(evsel, PERF_SAMPLE_CPU, "CPU", |
|---|
| 450 | | - PERF_OUTPUT_CPU, allow_user_set)) |
|---|
| 486 | + evsel__do_check_stype(evsel, PERF_SAMPLE_CPU, "CPU", PERF_OUTPUT_CPU, allow_user_set)) |
|---|
| 451 | 487 | return -EINVAL; |
|---|
| 452 | 488 | |
|---|
| 453 | 489 | if (PRINT_FIELD(IREGS) && |
|---|
| 454 | | - perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS", |
|---|
| 455 | | - PERF_OUTPUT_IREGS)) |
|---|
| 490 | + evsel__do_check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS", PERF_OUTPUT_IREGS, allow_user_set)) |
|---|
| 456 | 491 | return -EINVAL; |
|---|
| 457 | 492 | |
|---|
| 458 | 493 | if (PRINT_FIELD(UREGS) && |
|---|
| 459 | | - perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_USER, "UREGS", |
|---|
| 460 | | - PERF_OUTPUT_UREGS)) |
|---|
| 494 | + evsel__check_stype(evsel, PERF_SAMPLE_REGS_USER, "UREGS", PERF_OUTPUT_UREGS)) |
|---|
| 461 | 495 | return -EINVAL; |
|---|
| 462 | 496 | |
|---|
| 463 | 497 | if (PRINT_FIELD(PHYS_ADDR) && |
|---|
| 464 | | - perf_evsel__check_stype(evsel, PERF_SAMPLE_PHYS_ADDR, "PHYS_ADDR", |
|---|
| 465 | | - PERF_OUTPUT_PHYS_ADDR)) |
|---|
| 498 | + evsel__check_stype(evsel, PERF_SAMPLE_PHYS_ADDR, "PHYS_ADDR", PERF_OUTPUT_PHYS_ADDR)) |
|---|
| 466 | 499 | return -EINVAL; |
|---|
| 467 | 500 | |
|---|
| 468 | 501 | return 0; |
|---|
| .. | .. |
|---|
| 495 | 528 | */ |
|---|
| 496 | 529 | static int perf_session__check_output_opt(struct perf_session *session) |
|---|
| 497 | 530 | { |
|---|
| 531 | + bool tod = false; |
|---|
| 498 | 532 | unsigned int j; |
|---|
| 499 | | - struct perf_evsel *evsel; |
|---|
| 533 | + struct evsel *evsel; |
|---|
| 500 | 534 | |
|---|
| 501 | 535 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
|---|
| 502 | 536 | evsel = perf_session__find_first_evtype(session, attr_type(j)); |
|---|
| .. | .. |
|---|
| 514 | 548 | } |
|---|
| 515 | 549 | |
|---|
| 516 | 550 | if (evsel && output[j].fields && |
|---|
| 517 | | - perf_evsel__check_attr(evsel, session)) |
|---|
| 551 | + evsel__check_attr(evsel, session)) |
|---|
| 518 | 552 | return -1; |
|---|
| 519 | 553 | |
|---|
| 520 | 554 | if (evsel == NULL) |
|---|
| 521 | 555 | continue; |
|---|
| 522 | 556 | |
|---|
| 523 | | - set_print_ip_opts(&evsel->attr); |
|---|
| 557 | + set_print_ip_opts(&evsel->core.attr); |
|---|
| 558 | + tod |= output[j].fields & PERF_OUTPUT_TOD; |
|---|
| 524 | 559 | } |
|---|
| 525 | 560 | |
|---|
| 526 | 561 | if (!no_callchain) { |
|---|
| .. | .. |
|---|
| 547 | 582 | j = PERF_TYPE_TRACEPOINT; |
|---|
| 548 | 583 | |
|---|
| 549 | 584 | evlist__for_each_entry(session->evlist, evsel) { |
|---|
| 550 | | - if (evsel->attr.type != j) |
|---|
| 585 | + if (evsel->core.attr.type != j) |
|---|
| 551 | 586 | continue; |
|---|
| 552 | 587 | |
|---|
| 553 | 588 | if (evsel__has_callchain(evsel)) { |
|---|
| .. | .. |
|---|
| 555 | 590 | output[j].fields |= PERF_OUTPUT_SYM; |
|---|
| 556 | 591 | output[j].fields |= PERF_OUTPUT_SYMOFFSET; |
|---|
| 557 | 592 | output[j].fields |= PERF_OUTPUT_DSO; |
|---|
| 558 | | - set_print_ip_opts(&evsel->attr); |
|---|
| 593 | + set_print_ip_opts(&evsel->core.attr); |
|---|
| 559 | 594 | goto out; |
|---|
| 560 | 595 | } |
|---|
| 561 | 596 | } |
|---|
| 562 | 597 | } |
|---|
| 563 | 598 | |
|---|
| 599 | + if (tod && !session->header.env.clock.enabled) { |
|---|
| 600 | + pr_err("Can't provide 'tod' time, missing clock data. " |
|---|
| 601 | + "Please record with -k/--clockid option.\n"); |
|---|
| 602 | + return -1; |
|---|
| 603 | + } |
|---|
| 564 | 604 | out: |
|---|
| 565 | 605 | return 0; |
|---|
| 566 | 606 | } |
|---|
| 567 | 607 | |
|---|
| 568 | | -static int perf_sample__fprintf_iregs(struct perf_sample *sample, |
|---|
| 569 | | - struct perf_event_attr *attr, FILE *fp) |
|---|
| 608 | +static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, |
|---|
| 609 | + FILE *fp) |
|---|
| 570 | 610 | { |
|---|
| 571 | | - struct regs_dump *regs = &sample->intr_regs; |
|---|
| 572 | | - uint64_t mask = attr->sample_regs_intr; |
|---|
| 573 | | - unsigned i = 0, r; |
|---|
| 574 | | - int printed = 0; |
|---|
| 575 | | - |
|---|
| 576 | | - if (!regs) |
|---|
| 577 | | - return 0; |
|---|
| 578 | | - |
|---|
| 579 | | - for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { |
|---|
| 580 | | - u64 val = regs->regs[i++]; |
|---|
| 581 | | - printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r), val); |
|---|
| 582 | | - } |
|---|
| 583 | | - |
|---|
| 584 | | - return printed; |
|---|
| 585 | | -} |
|---|
| 586 | | - |
|---|
| 587 | | -static int perf_sample__fprintf_uregs(struct perf_sample *sample, |
|---|
| 588 | | - struct perf_event_attr *attr, FILE *fp) |
|---|
| 589 | | -{ |
|---|
| 590 | | - struct regs_dump *regs = &sample->user_regs; |
|---|
| 591 | | - uint64_t mask = attr->sample_regs_user; |
|---|
| 592 | 611 | unsigned i = 0, r; |
|---|
| 593 | 612 | int printed = 0; |
|---|
| 594 | 613 | |
|---|
| .. | .. |
|---|
| 605 | 624 | return printed; |
|---|
| 606 | 625 | } |
|---|
| 607 | 626 | |
|---|
| 608 | | -static int perf_sample__fprintf_start(struct perf_sample *sample, |
|---|
| 627 | +#define DEFAULT_TOD_FMT "%F %H:%M:%S" |
|---|
| 628 | + |
|---|
| 629 | +static char* |
|---|
| 630 | +tod_scnprintf(struct perf_script *script, char *buf, int buflen, |
|---|
| 631 | + u64 timestamp) |
|---|
| 632 | +{ |
|---|
| 633 | + u64 tod_ns, clockid_ns; |
|---|
| 634 | + struct perf_env *env; |
|---|
| 635 | + unsigned long nsec; |
|---|
| 636 | + struct tm ltime; |
|---|
| 637 | + char date[64]; |
|---|
| 638 | + time_t sec; |
|---|
| 639 | + |
|---|
| 640 | + buf[0] = '\0'; |
|---|
| 641 | + if (buflen < 64 || !script) |
|---|
| 642 | + return buf; |
|---|
| 643 | + |
|---|
| 644 | + env = &script->session->header.env; |
|---|
| 645 | + if (!env->clock.enabled) { |
|---|
| 646 | + scnprintf(buf, buflen, "disabled"); |
|---|
| 647 | + return buf; |
|---|
| 648 | + } |
|---|
| 649 | + |
|---|
| 650 | + clockid_ns = env->clock.clockid_ns; |
|---|
| 651 | + tod_ns = env->clock.tod_ns; |
|---|
| 652 | + |
|---|
| 653 | + if (timestamp > clockid_ns) |
|---|
| 654 | + tod_ns += timestamp - clockid_ns; |
|---|
| 655 | + else |
|---|
| 656 | + tod_ns -= clockid_ns - timestamp; |
|---|
| 657 | + |
|---|
| 658 | + sec = (time_t) (tod_ns / NSEC_PER_SEC); |
|---|
| 659 | + nsec = tod_ns - sec * NSEC_PER_SEC; |
|---|
| 660 | + |
|---|
| 661 | + if (localtime_r(&sec, <ime) == NULL) { |
|---|
| 662 | + scnprintf(buf, buflen, "failed"); |
|---|
| 663 | + } else { |
|---|
| 664 | + strftime(date, sizeof(date), DEFAULT_TOD_FMT, <ime); |
|---|
| 665 | + |
|---|
| 666 | + if (symbol_conf.nanosecs) { |
|---|
| 667 | + snprintf(buf, buflen, "%s.%09lu", date, nsec); |
|---|
| 668 | + } else { |
|---|
| 669 | + snprintf(buf, buflen, "%s.%06lu", |
|---|
| 670 | + date, nsec / NSEC_PER_USEC); |
|---|
| 671 | + } |
|---|
| 672 | + } |
|---|
| 673 | + |
|---|
| 674 | + return buf; |
|---|
| 675 | +} |
|---|
| 676 | + |
|---|
| 677 | +static int perf_sample__fprintf_iregs(struct perf_sample *sample, |
|---|
| 678 | + struct perf_event_attr *attr, FILE *fp) |
|---|
| 679 | +{ |
|---|
| 680 | + return perf_sample__fprintf_regs(&sample->intr_regs, |
|---|
| 681 | + attr->sample_regs_intr, fp); |
|---|
| 682 | +} |
|---|
| 683 | + |
|---|
| 684 | +static int perf_sample__fprintf_uregs(struct perf_sample *sample, |
|---|
| 685 | + struct perf_event_attr *attr, FILE *fp) |
|---|
| 686 | +{ |
|---|
| 687 | + return perf_sample__fprintf_regs(&sample->user_regs, |
|---|
| 688 | + attr->sample_regs_user, fp); |
|---|
| 689 | +} |
|---|
| 690 | + |
|---|
| 691 | +static int perf_sample__fprintf_start(struct perf_script *script, |
|---|
| 692 | + struct perf_sample *sample, |
|---|
| 609 | 693 | struct thread *thread, |
|---|
| 610 | | - struct perf_evsel *evsel, |
|---|
| 694 | + struct evsel *evsel, |
|---|
| 611 | 695 | u32 type, FILE *fp) |
|---|
| 612 | 696 | { |
|---|
| 613 | | - struct perf_event_attr *attr = &evsel->attr; |
|---|
| 697 | + struct perf_event_attr *attr = &evsel->core.attr; |
|---|
| 614 | 698 | unsigned long secs; |
|---|
| 615 | 699 | unsigned long long nsecs; |
|---|
| 616 | 700 | int printed = 0; |
|---|
| 701 | + char tstr[128]; |
|---|
| 617 | 702 | |
|---|
| 618 | 703 | if (PRINT_FIELD(COMM)) { |
|---|
| 704 | + const char *comm = thread ? thread__comm_str(thread) : ":-1"; |
|---|
| 705 | + |
|---|
| 619 | 706 | if (latency_format) |
|---|
| 620 | | - printed += fprintf(fp, "%8.8s ", thread__comm_str(thread)); |
|---|
| 707 | + printed += fprintf(fp, "%8.8s ", comm); |
|---|
| 621 | 708 | else if (PRINT_FIELD(IP) && evsel__has_callchain(evsel) && symbol_conf.use_callchain) |
|---|
| 622 | | - printed += fprintf(fp, "%s ", thread__comm_str(thread)); |
|---|
| 709 | + printed += fprintf(fp, "%s ", comm); |
|---|
| 623 | 710 | else |
|---|
| 624 | | - printed += fprintf(fp, "%16s ", thread__comm_str(thread)); |
|---|
| 711 | + printed += fprintf(fp, "%16s ", comm); |
|---|
| 625 | 712 | } |
|---|
| 626 | 713 | |
|---|
| 627 | 714 | if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) |
|---|
| .. | .. |
|---|
| 682 | 769 | printed += ret; |
|---|
| 683 | 770 | } |
|---|
| 684 | 771 | |
|---|
| 772 | + if (PRINT_FIELD(TOD)) { |
|---|
| 773 | + tod_scnprintf(script, tstr, sizeof(tstr), sample->time); |
|---|
| 774 | + printed += fprintf(fp, "%s ", tstr); |
|---|
| 775 | + } |
|---|
| 776 | + |
|---|
| 685 | 777 | if (PRINT_FIELD(TIME)) { |
|---|
| 686 | | - nsecs = sample->time; |
|---|
| 778 | + u64 t = sample->time; |
|---|
| 779 | + if (reltime) { |
|---|
| 780 | + if (!initial_time) |
|---|
| 781 | + initial_time = sample->time; |
|---|
| 782 | + t = sample->time - initial_time; |
|---|
| 783 | + } else if (deltatime) { |
|---|
| 784 | + if (previous_time) |
|---|
| 785 | + t = sample->time - previous_time; |
|---|
| 786 | + else { |
|---|
| 787 | + t = 0; |
|---|
| 788 | + } |
|---|
| 789 | + previous_time = sample->time; |
|---|
| 790 | + } |
|---|
| 791 | + nsecs = t; |
|---|
| 687 | 792 | secs = nsecs / NSEC_PER_SEC; |
|---|
| 688 | 793 | nsecs -= secs * NSEC_PER_SEC; |
|---|
| 689 | 794 | |
|---|
| 690 | | - if (nanosecs) |
|---|
| 795 | + if (symbol_conf.nanosecs) |
|---|
| 691 | 796 | printed += fprintf(fp, "%5lu.%09llu: ", secs, nsecs); |
|---|
| 692 | 797 | else { |
|---|
| 693 | 798 | char sample_time[32]; |
|---|
| 694 | | - timestamp__scnprintf_usec(sample->time, sample_time, sizeof(sample_time)); |
|---|
| 799 | + timestamp__scnprintf_usec(t, sample_time, sizeof(sample_time)); |
|---|
| 695 | 800 | printed += fprintf(fp, "%12s: ", sample_time); |
|---|
| 696 | 801 | } |
|---|
| 697 | 802 | } |
|---|
| .. | .. |
|---|
| 713 | 818 | struct perf_event_attr *attr, FILE *fp) |
|---|
| 714 | 819 | { |
|---|
| 715 | 820 | struct branch_stack *br = sample->branch_stack; |
|---|
| 821 | + struct branch_entry *entries = perf_sample__branch_entries(sample); |
|---|
| 716 | 822 | struct addr_location alf, alt; |
|---|
| 717 | 823 | u64 i, from, to; |
|---|
| 718 | 824 | int printed = 0; |
|---|
| .. | .. |
|---|
| 721 | 827 | return 0; |
|---|
| 722 | 828 | |
|---|
| 723 | 829 | for (i = 0; i < br->nr; i++) { |
|---|
| 724 | | - from = br->entries[i].from; |
|---|
| 725 | | - to = br->entries[i].to; |
|---|
| 830 | + from = entries[i].from; |
|---|
| 831 | + to = entries[i].to; |
|---|
| 726 | 832 | |
|---|
| 727 | 833 | if (PRINT_FIELD(DSO)) { |
|---|
| 728 | 834 | memset(&alf, 0, sizeof(alf)); |
|---|
| .. | .. |
|---|
| 746 | 852 | } |
|---|
| 747 | 853 | |
|---|
| 748 | 854 | printed += fprintf(fp, "/%c/%c/%c/%d ", |
|---|
| 749 | | - mispred_str( br->entries + i), |
|---|
| 750 | | - br->entries[i].flags.in_tx? 'X' : '-', |
|---|
| 751 | | - br->entries[i].flags.abort? 'A' : '-', |
|---|
| 752 | | - br->entries[i].flags.cycles); |
|---|
| 855 | + mispred_str(entries + i), |
|---|
| 856 | + entries[i].flags.in_tx ? 'X' : '-', |
|---|
| 857 | + entries[i].flags.abort ? 'A' : '-', |
|---|
| 858 | + entries[i].flags.cycles); |
|---|
| 753 | 859 | } |
|---|
| 754 | 860 | |
|---|
| 755 | 861 | return printed; |
|---|
| .. | .. |
|---|
| 760 | 866 | struct perf_event_attr *attr, FILE *fp) |
|---|
| 761 | 867 | { |
|---|
| 762 | 868 | struct branch_stack *br = sample->branch_stack; |
|---|
| 869 | + struct branch_entry *entries = perf_sample__branch_entries(sample); |
|---|
| 763 | 870 | struct addr_location alf, alt; |
|---|
| 764 | 871 | u64 i, from, to; |
|---|
| 765 | 872 | int printed = 0; |
|---|
| .. | .. |
|---|
| 771 | 878 | |
|---|
| 772 | 879 | memset(&alf, 0, sizeof(alf)); |
|---|
| 773 | 880 | memset(&alt, 0, sizeof(alt)); |
|---|
| 774 | | - from = br->entries[i].from; |
|---|
| 775 | | - to = br->entries[i].to; |
|---|
| 881 | + from = entries[i].from; |
|---|
| 882 | + to = entries[i].to; |
|---|
| 776 | 883 | |
|---|
| 777 | 884 | thread__find_symbol_fb(thread, sample->cpumode, from, &alf); |
|---|
| 778 | 885 | thread__find_symbol_fb(thread, sample->cpumode, to, &alt); |
|---|
| .. | .. |
|---|
| 791 | 898 | printed += fprintf(fp, ")"); |
|---|
| 792 | 899 | } |
|---|
| 793 | 900 | printed += fprintf(fp, "/%c/%c/%c/%d ", |
|---|
| 794 | | - mispred_str( br->entries + i), |
|---|
| 795 | | - br->entries[i].flags.in_tx? 'X' : '-', |
|---|
| 796 | | - br->entries[i].flags.abort? 'A' : '-', |
|---|
| 797 | | - br->entries[i].flags.cycles); |
|---|
| 901 | + mispred_str(entries + i), |
|---|
| 902 | + entries[i].flags.in_tx ? 'X' : '-', |
|---|
| 903 | + entries[i].flags.abort ? 'A' : '-', |
|---|
| 904 | + entries[i].flags.cycles); |
|---|
| 798 | 905 | } |
|---|
| 799 | 906 | |
|---|
| 800 | 907 | return printed; |
|---|
| .. | .. |
|---|
| 805 | 912 | struct perf_event_attr *attr, FILE *fp) |
|---|
| 806 | 913 | { |
|---|
| 807 | 914 | struct branch_stack *br = sample->branch_stack; |
|---|
| 915 | + struct branch_entry *entries = perf_sample__branch_entries(sample); |
|---|
| 808 | 916 | struct addr_location alf, alt; |
|---|
| 809 | 917 | u64 i, from, to; |
|---|
| 810 | 918 | int printed = 0; |
|---|
| .. | .. |
|---|
| 816 | 924 | |
|---|
| 817 | 925 | memset(&alf, 0, sizeof(alf)); |
|---|
| 818 | 926 | memset(&alt, 0, sizeof(alt)); |
|---|
| 819 | | - from = br->entries[i].from; |
|---|
| 820 | | - to = br->entries[i].to; |
|---|
| 927 | + from = entries[i].from; |
|---|
| 928 | + to = entries[i].to; |
|---|
| 821 | 929 | |
|---|
| 822 | 930 | if (thread__find_map_fb(thread, sample->cpumode, from, &alf) && |
|---|
| 823 | 931 | !alf.map->dso->adjust_symbols) |
|---|
| .. | .. |
|---|
| 840 | 948 | printed += fprintf(fp, ")"); |
|---|
| 841 | 949 | } |
|---|
| 842 | 950 | printed += fprintf(fp, "/%c/%c/%c/%d ", |
|---|
| 843 | | - mispred_str(br->entries + i), |
|---|
| 844 | | - br->entries[i].flags.in_tx ? 'X' : '-', |
|---|
| 845 | | - br->entries[i].flags.abort ? 'A' : '-', |
|---|
| 846 | | - br->entries[i].flags.cycles); |
|---|
| 951 | + mispred_str(entries + i), |
|---|
| 952 | + entries[i].flags.in_tx ? 'X' : '-', |
|---|
| 953 | + entries[i].flags.abort ? 'A' : '-', |
|---|
| 954 | + entries[i].flags.cycles); |
|---|
| 847 | 955 | } |
|---|
| 848 | 956 | |
|---|
| 849 | 957 | return printed; |
|---|
| .. | .. |
|---|
| 910 | 1018 | return len; |
|---|
| 911 | 1019 | } |
|---|
| 912 | 1020 | |
|---|
| 1021 | +static int map__fprintf_srccode(struct map *map, u64 addr, FILE *fp, struct srccode_state *state) |
|---|
| 1022 | +{ |
|---|
| 1023 | + char *srcfile; |
|---|
| 1024 | + int ret = 0; |
|---|
| 1025 | + unsigned line; |
|---|
| 1026 | + int len; |
|---|
| 1027 | + char *srccode; |
|---|
| 1028 | + |
|---|
| 1029 | + if (!map || !map->dso) |
|---|
| 1030 | + return 0; |
|---|
| 1031 | + srcfile = get_srcline_split(map->dso, |
|---|
| 1032 | + map__rip_2objdump(map, addr), |
|---|
| 1033 | + &line); |
|---|
| 1034 | + if (!srcfile) |
|---|
| 1035 | + return 0; |
|---|
| 1036 | + |
|---|
| 1037 | + /* Avoid redundant printing */ |
|---|
| 1038 | + if (state && |
|---|
| 1039 | + state->srcfile && |
|---|
| 1040 | + !strcmp(state->srcfile, srcfile) && |
|---|
| 1041 | + state->line == line) { |
|---|
| 1042 | + free(srcfile); |
|---|
| 1043 | + return 0; |
|---|
| 1044 | + } |
|---|
| 1045 | + |
|---|
| 1046 | + srccode = find_sourceline(srcfile, line, &len); |
|---|
| 1047 | + if (!srccode) |
|---|
| 1048 | + goto out_free_line; |
|---|
| 1049 | + |
|---|
| 1050 | + ret = fprintf(fp, "|%-8d %.*s", line, len, srccode); |
|---|
| 1051 | + |
|---|
| 1052 | + if (state) { |
|---|
| 1053 | + state->srcfile = srcfile; |
|---|
| 1054 | + state->line = line; |
|---|
| 1055 | + } |
|---|
| 1056 | + return ret; |
|---|
| 1057 | + |
|---|
| 1058 | +out_free_line: |
|---|
| 1059 | + free(srcfile); |
|---|
| 1060 | + return ret; |
|---|
| 1061 | +} |
|---|
| 1062 | + |
|---|
| 1063 | +static int print_srccode(struct thread *thread, u8 cpumode, uint64_t addr) |
|---|
| 1064 | +{ |
|---|
| 1065 | + struct addr_location al; |
|---|
| 1066 | + int ret = 0; |
|---|
| 1067 | + |
|---|
| 1068 | + memset(&al, 0, sizeof(al)); |
|---|
| 1069 | + thread__find_map(thread, cpumode, addr, &al); |
|---|
| 1070 | + if (!al.map) |
|---|
| 1071 | + return 0; |
|---|
| 1072 | + ret = map__fprintf_srccode(al.map, al.addr, stdout, |
|---|
| 1073 | + &thread->srccode_state); |
|---|
| 1074 | + if (ret) |
|---|
| 1075 | + ret += printf("\n"); |
|---|
| 1076 | + return ret; |
|---|
| 1077 | +} |
|---|
| 1078 | + |
|---|
| 913 | 1079 | static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, |
|---|
| 914 | 1080 | struct perf_insn *x, u8 *inbuf, int len, |
|---|
| 915 | | - int insn, FILE *fp) |
|---|
| 1081 | + int insn, FILE *fp, int *total_cycles) |
|---|
| 916 | 1082 | { |
|---|
| 917 | 1083 | int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip, |
|---|
| 918 | 1084 | dump_insn(x, ip, inbuf, len, NULL), |
|---|
| .. | .. |
|---|
| 921 | 1087 | en->flags.in_tx ? " INTX" : "", |
|---|
| 922 | 1088 | en->flags.abort ? " ABORT" : ""); |
|---|
| 923 | 1089 | if (en->flags.cycles) { |
|---|
| 924 | | - printed += fprintf(fp, " %d cycles", en->flags.cycles); |
|---|
| 1090 | + *total_cycles += en->flags.cycles; |
|---|
| 1091 | + printed += fprintf(fp, " %d cycles [%d]", en->flags.cycles, *total_cycles); |
|---|
| 925 | 1092 | if (insn) |
|---|
| 926 | 1093 | printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles); |
|---|
| 927 | 1094 | } |
|---|
| .. | .. |
|---|
| 972 | 1139 | struct machine *machine, FILE *fp) |
|---|
| 973 | 1140 | { |
|---|
| 974 | 1141 | struct branch_stack *br = sample->branch_stack; |
|---|
| 1142 | + struct branch_entry *entries = perf_sample__branch_entries(sample); |
|---|
| 975 | 1143 | u64 start, end; |
|---|
| 976 | 1144 | int i, insn, len, nr, ilen, printed = 0; |
|---|
| 977 | 1145 | struct perf_insn x; |
|---|
| 978 | 1146 | u8 buffer[MAXBB]; |
|---|
| 979 | 1147 | unsigned off; |
|---|
| 980 | 1148 | struct symbol *lastsym = NULL; |
|---|
| 1149 | + int total_cycles = 0; |
|---|
| 981 | 1150 | |
|---|
| 982 | 1151 | if (!(br && br->nr)) |
|---|
| 983 | 1152 | return 0; |
|---|
| .. | .. |
|---|
| 991 | 1160 | printed += fprintf(fp, "%c", '\n'); |
|---|
| 992 | 1161 | |
|---|
| 993 | 1162 | /* Handle first from jump, of which we don't know the entry. */ |
|---|
| 994 | | - len = grab_bb(buffer, br->entries[nr-1].from, |
|---|
| 995 | | - br->entries[nr-1].from, |
|---|
| 1163 | + len = grab_bb(buffer, entries[nr-1].from, |
|---|
| 1164 | + entries[nr-1].from, |
|---|
| 996 | 1165 | machine, thread, &x.is64bit, &x.cpumode, false); |
|---|
| 997 | 1166 | if (len > 0) { |
|---|
| 998 | | - printed += ip__fprintf_sym(br->entries[nr - 1].from, thread, |
|---|
| 1167 | + printed += ip__fprintf_sym(entries[nr - 1].from, thread, |
|---|
| 999 | 1168 | x.cpumode, x.cpu, &lastsym, attr, fp); |
|---|
| 1000 | | - printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], |
|---|
| 1001 | | - &x, buffer, len, 0, fp); |
|---|
| 1169 | + printed += ip__fprintf_jump(entries[nr - 1].from, &entries[nr - 1], |
|---|
| 1170 | + &x, buffer, len, 0, fp, &total_cycles); |
|---|
| 1171 | + if (PRINT_FIELD(SRCCODE)) |
|---|
| 1172 | + printed += print_srccode(thread, x.cpumode, entries[nr - 1].from); |
|---|
| 1002 | 1173 | } |
|---|
| 1003 | 1174 | |
|---|
| 1004 | 1175 | /* Print all blocks */ |
|---|
| 1005 | 1176 | for (i = nr - 2; i >= 0; i--) { |
|---|
| 1006 | | - if (br->entries[i].from || br->entries[i].to) |
|---|
| 1177 | + if (entries[i].from || entries[i].to) |
|---|
| 1007 | 1178 | pr_debug("%d: %" PRIx64 "-%" PRIx64 "\n", i, |
|---|
| 1008 | | - br->entries[i].from, |
|---|
| 1009 | | - br->entries[i].to); |
|---|
| 1010 | | - start = br->entries[i + 1].to; |
|---|
| 1011 | | - end = br->entries[i].from; |
|---|
| 1179 | + entries[i].from, |
|---|
| 1180 | + entries[i].to); |
|---|
| 1181 | + start = entries[i + 1].to; |
|---|
| 1182 | + end = entries[i].from; |
|---|
| 1012 | 1183 | |
|---|
| 1013 | 1184 | len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, false); |
|---|
| 1014 | 1185 | /* Patch up missing kernel transfers due to ring filters */ |
|---|
| 1015 | 1186 | if (len == -ENXIO && i > 0) { |
|---|
| 1016 | | - end = br->entries[--i].from; |
|---|
| 1187 | + end = entries[--i].from; |
|---|
| 1017 | 1188 | pr_debug("\tpatching up to %" PRIx64 "-%" PRIx64 "\n", start, end); |
|---|
| 1018 | 1189 | len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, false); |
|---|
| 1019 | 1190 | } |
|---|
| .. | .. |
|---|
| 1026 | 1197 | |
|---|
| 1027 | 1198 | printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); |
|---|
| 1028 | 1199 | if (ip == end) { |
|---|
| 1029 | | - printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp); |
|---|
| 1200 | + printed += ip__fprintf_jump(ip, &entries[i], &x, buffer + off, len - off, ++insn, fp, |
|---|
| 1201 | + &total_cycles); |
|---|
| 1202 | + if (PRINT_FIELD(SRCCODE)) |
|---|
| 1203 | + printed += print_srccode(thread, x.cpumode, ip); |
|---|
| 1030 | 1204 | break; |
|---|
| 1031 | 1205 | } else { |
|---|
| 1032 | 1206 | ilen = 0; |
|---|
| .. | .. |
|---|
| 1034 | 1208 | dump_insn(&x, ip, buffer + off, len - off, &ilen)); |
|---|
| 1035 | 1209 | if (ilen == 0) |
|---|
| 1036 | 1210 | break; |
|---|
| 1211 | + if (PRINT_FIELD(SRCCODE)) |
|---|
| 1212 | + print_srccode(thread, x.cpumode, ip); |
|---|
| 1037 | 1213 | insn++; |
|---|
| 1038 | 1214 | } |
|---|
| 1039 | 1215 | } |
|---|
| .. | .. |
|---|
| 1045 | 1221 | * Hit the branch? In this case we are already done, and the target |
|---|
| 1046 | 1222 | * has not been executed yet. |
|---|
| 1047 | 1223 | */ |
|---|
| 1048 | | - if (br->entries[0].from == sample->ip) |
|---|
| 1224 | + if (entries[0].from == sample->ip) |
|---|
| 1049 | 1225 | goto out; |
|---|
| 1050 | | - if (br->entries[0].flags.abort) |
|---|
| 1226 | + if (entries[0].flags.abort) |
|---|
| 1051 | 1227 | goto out; |
|---|
| 1052 | 1228 | |
|---|
| 1053 | 1229 | /* |
|---|
| 1054 | 1230 | * Print final block upto sample |
|---|
| 1231 | + * |
|---|
| 1232 | + * Due to pipeline delays the LBRs might be missing a branch |
|---|
| 1233 | + * or two, which can result in very large or negative blocks |
|---|
| 1234 | + * between final branch and sample. When this happens just |
|---|
| 1235 | + * continue walking after the last TO until we hit a branch. |
|---|
| 1055 | 1236 | */ |
|---|
| 1056 | | - start = br->entries[0].to; |
|---|
| 1237 | + start = entries[0].to; |
|---|
| 1057 | 1238 | end = sample->ip; |
|---|
| 1239 | + if (end < start) { |
|---|
| 1240 | + /* Missing jump. Scan 128 bytes for the next branch */ |
|---|
| 1241 | + end = start + 128; |
|---|
| 1242 | + } |
|---|
| 1058 | 1243 | len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true); |
|---|
| 1059 | 1244 | printed += ip__fprintf_sym(start, thread, x.cpumode, x.cpu, &lastsym, attr, fp); |
|---|
| 1060 | 1245 | if (len <= 0) { |
|---|
| .. | .. |
|---|
| 1063 | 1248 | machine, thread, &x.is64bit, &x.cpumode, false); |
|---|
| 1064 | 1249 | if (len <= 0) |
|---|
| 1065 | 1250 | goto out; |
|---|
| 1066 | | - |
|---|
| 1067 | 1251 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip, |
|---|
| 1068 | 1252 | dump_insn(&x, sample->ip, buffer, len, NULL)); |
|---|
| 1253 | + if (PRINT_FIELD(SRCCODE)) |
|---|
| 1254 | + print_srccode(thread, x.cpumode, sample->ip); |
|---|
| 1069 | 1255 | goto out; |
|---|
| 1070 | 1256 | } |
|---|
| 1071 | 1257 | for (off = 0; off <= end - start; off += ilen) { |
|---|
| .. | .. |
|---|
| 1074 | 1260 | dump_insn(&x, start + off, buffer + off, len - off, &ilen)); |
|---|
| 1075 | 1261 | if (ilen == 0) |
|---|
| 1076 | 1262 | break; |
|---|
| 1263 | + if (arch_is_branch(buffer + off, len - off, x.is64bit) && start + off != sample->ip) { |
|---|
| 1264 | + /* |
|---|
| 1265 | + * Hit a missing branch. Just stop. |
|---|
| 1266 | + */ |
|---|
| 1267 | + printed += fprintf(fp, "\t... not reaching sample ...\n"); |
|---|
| 1268 | + break; |
|---|
| 1269 | + } |
|---|
| 1270 | + if (PRINT_FIELD(SRCCODE)) |
|---|
| 1271 | + print_srccode(thread, x.cpumode, start + off); |
|---|
| 1077 | 1272 | } |
|---|
| 1078 | 1273 | out: |
|---|
| 1079 | 1274 | return printed; |
|---|
| .. | .. |
|---|
| 1108 | 1303 | return printed; |
|---|
| 1109 | 1304 | } |
|---|
| 1110 | 1305 | |
|---|
| 1306 | +static const char *resolve_branch_sym(struct perf_sample *sample, |
|---|
| 1307 | + struct evsel *evsel, |
|---|
| 1308 | + struct thread *thread, |
|---|
| 1309 | + struct addr_location *al, |
|---|
| 1310 | + u64 *ip) |
|---|
| 1311 | +{ |
|---|
| 1312 | + struct addr_location addr_al; |
|---|
| 1313 | + struct perf_event_attr *attr = &evsel->core.attr; |
|---|
| 1314 | + const char *name = NULL; |
|---|
| 1315 | + |
|---|
| 1316 | + if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { |
|---|
| 1317 | + if (sample_addr_correlates_sym(attr)) { |
|---|
| 1318 | + thread__resolve(thread, &addr_al, sample); |
|---|
| 1319 | + if (addr_al.sym) |
|---|
| 1320 | + name = addr_al.sym->name; |
|---|
| 1321 | + else |
|---|
| 1322 | + *ip = sample->addr; |
|---|
| 1323 | + } else { |
|---|
| 1324 | + *ip = sample->addr; |
|---|
| 1325 | + } |
|---|
| 1326 | + } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { |
|---|
| 1327 | + if (al->sym) |
|---|
| 1328 | + name = al->sym->name; |
|---|
| 1329 | + else |
|---|
| 1330 | + *ip = sample->ip; |
|---|
| 1331 | + } |
|---|
| 1332 | + return name; |
|---|
| 1333 | +} |
|---|
| 1334 | + |
|---|
| 1111 | 1335 | static int perf_sample__fprintf_callindent(struct perf_sample *sample, |
|---|
| 1112 | | - struct perf_evsel *evsel, |
|---|
| 1336 | + struct evsel *evsel, |
|---|
| 1113 | 1337 | struct thread *thread, |
|---|
| 1114 | 1338 | struct addr_location *al, FILE *fp) |
|---|
| 1115 | 1339 | { |
|---|
| 1116 | | - struct perf_event_attr *attr = &evsel->attr; |
|---|
| 1117 | | - size_t depth = thread_stack__depth(thread); |
|---|
| 1118 | | - struct addr_location addr_al; |
|---|
| 1340 | + struct perf_event_attr *attr = &evsel->core.attr; |
|---|
| 1341 | + size_t depth = thread_stack__depth(thread, sample->cpu); |
|---|
| 1119 | 1342 | const char *name = NULL; |
|---|
| 1120 | 1343 | static int spacing; |
|---|
| 1121 | 1344 | int len = 0; |
|---|
| 1345 | + int dlen = 0; |
|---|
| 1122 | 1346 | u64 ip = 0; |
|---|
| 1123 | 1347 | |
|---|
| 1124 | 1348 | /* |
|---|
| .. | .. |
|---|
| 1128 | 1352 | if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) |
|---|
| 1129 | 1353 | depth += 1; |
|---|
| 1130 | 1354 | |
|---|
| 1131 | | - if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { |
|---|
| 1132 | | - if (sample_addr_correlates_sym(attr)) { |
|---|
| 1133 | | - thread__resolve(thread, &addr_al, sample); |
|---|
| 1134 | | - if (addr_al.sym) |
|---|
| 1135 | | - name = addr_al.sym->name; |
|---|
| 1136 | | - else |
|---|
| 1137 | | - ip = sample->addr; |
|---|
| 1138 | | - } else { |
|---|
| 1139 | | - ip = sample->addr; |
|---|
| 1140 | | - } |
|---|
| 1141 | | - } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { |
|---|
| 1142 | | - if (al->sym) |
|---|
| 1143 | | - name = al->sym->name; |
|---|
| 1144 | | - else |
|---|
| 1145 | | - ip = sample->ip; |
|---|
| 1355 | + name = resolve_branch_sym(sample, evsel, thread, al, &ip); |
|---|
| 1356 | + |
|---|
| 1357 | + if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) { |
|---|
| 1358 | + dlen += fprintf(fp, "("); |
|---|
| 1359 | + dlen += map__fprintf_dsoname(al->map, fp); |
|---|
| 1360 | + dlen += fprintf(fp, ")\t"); |
|---|
| 1146 | 1361 | } |
|---|
| 1147 | 1362 | |
|---|
| 1148 | 1363 | if (name) |
|---|
| .. | .. |
|---|
| 1163 | 1378 | if (len < spacing) |
|---|
| 1164 | 1379 | len += fprintf(fp, "%*s", spacing - len, ""); |
|---|
| 1165 | 1380 | |
|---|
| 1166 | | - return len; |
|---|
| 1381 | + return len + dlen; |
|---|
| 1382 | +} |
|---|
| 1383 | + |
|---|
| 1384 | +__weak void arch_fetch_insn(struct perf_sample *sample __maybe_unused, |
|---|
| 1385 | + struct thread *thread __maybe_unused, |
|---|
| 1386 | + struct machine *machine __maybe_unused) |
|---|
| 1387 | +{ |
|---|
| 1167 | 1388 | } |
|---|
| 1168 | 1389 | |
|---|
| 1169 | 1390 | static int perf_sample__fprintf_insn(struct perf_sample *sample, |
|---|
| .. | .. |
|---|
| 1173 | 1394 | { |
|---|
| 1174 | 1395 | int printed = 0; |
|---|
| 1175 | 1396 | |
|---|
| 1397 | + if (sample->insn_len == 0 && native_arch) |
|---|
| 1398 | + arch_fetch_insn(sample, thread, machine); |
|---|
| 1399 | + |
|---|
| 1176 | 1400 | if (PRINT_FIELD(INSNLEN)) |
|---|
| 1177 | 1401 | printed += fprintf(fp, " ilen: %d", sample->insn_len); |
|---|
| 1178 | | - if (PRINT_FIELD(INSN)) { |
|---|
| 1402 | + if (PRINT_FIELD(INSN) && sample->insn_len) { |
|---|
| 1179 | 1403 | int i; |
|---|
| 1180 | 1404 | |
|---|
| 1181 | 1405 | printed += fprintf(fp, " insn:"); |
|---|
| .. | .. |
|---|
| 1188 | 1412 | return printed; |
|---|
| 1189 | 1413 | } |
|---|
| 1190 | 1414 | |
|---|
| 1415 | +static int perf_sample__fprintf_ipc(struct perf_sample *sample, |
|---|
| 1416 | + struct perf_event_attr *attr, FILE *fp) |
|---|
| 1417 | +{ |
|---|
| 1418 | + unsigned int ipc; |
|---|
| 1419 | + |
|---|
| 1420 | + if (!PRINT_FIELD(IPC) || !sample->cyc_cnt || !sample->insn_cnt) |
|---|
| 1421 | + return 0; |
|---|
| 1422 | + |
|---|
| 1423 | + ipc = (sample->insn_cnt * 100) / sample->cyc_cnt; |
|---|
| 1424 | + |
|---|
| 1425 | + return fprintf(fp, " \t IPC: %u.%02u (%" PRIu64 "/%" PRIu64 ") ", |
|---|
| 1426 | + ipc / 100, ipc % 100, sample->insn_cnt, sample->cyc_cnt); |
|---|
| 1427 | +} |
|---|
| 1428 | + |
|---|
| 1191 | 1429 | static int perf_sample__fprintf_bts(struct perf_sample *sample, |
|---|
| 1192 | | - struct perf_evsel *evsel, |
|---|
| 1430 | + struct evsel *evsel, |
|---|
| 1193 | 1431 | struct thread *thread, |
|---|
| 1194 | 1432 | struct addr_location *al, |
|---|
| 1195 | 1433 | struct machine *machine, FILE *fp) |
|---|
| 1196 | 1434 | { |
|---|
| 1197 | | - struct perf_event_attr *attr = &evsel->attr; |
|---|
| 1435 | + struct perf_event_attr *attr = &evsel->core.attr; |
|---|
| 1198 | 1436 | unsigned int type = output_type(attr->type); |
|---|
| 1199 | 1437 | bool print_srcline_last = false; |
|---|
| 1200 | 1438 | int printed = 0; |
|---|
| .. | .. |
|---|
| 1221 | 1459 | } else |
|---|
| 1222 | 1460 | printed += fprintf(fp, "\n"); |
|---|
| 1223 | 1461 | |
|---|
| 1224 | | - printed += sample__fprintf_sym(sample, al, 0, print_opts, cursor, fp); |
|---|
| 1462 | + printed += sample__fprintf_sym(sample, al, 0, print_opts, cursor, |
|---|
| 1463 | + symbol_conf.bt_stop_list, fp); |
|---|
| 1225 | 1464 | } |
|---|
| 1226 | 1465 | |
|---|
| 1227 | 1466 | /* print branch_to information */ |
|---|
| 1228 | 1467 | if (PRINT_FIELD(ADDR) || |
|---|
| 1229 | | - ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
|---|
| 1468 | + ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) && |
|---|
| 1230 | 1469 | !output[type].user_set)) { |
|---|
| 1231 | 1470 | printed += fprintf(fp, " => "); |
|---|
| 1232 | 1471 | printed += perf_sample__fprintf_addr(sample, thread, attr, fp); |
|---|
| 1233 | 1472 | } |
|---|
| 1234 | 1473 | |
|---|
| 1474 | + printed += perf_sample__fprintf_ipc(sample, attr, fp); |
|---|
| 1475 | + |
|---|
| 1235 | 1476 | if (print_srcline_last) |
|---|
| 1236 | 1477 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); |
|---|
| 1237 | 1478 | |
|---|
| 1238 | 1479 | printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp); |
|---|
| 1239 | | - return printed + fprintf(fp, "\n"); |
|---|
| 1480 | + printed += fprintf(fp, "\n"); |
|---|
| 1481 | + if (PRINT_FIELD(SRCCODE)) { |
|---|
| 1482 | + int ret = map__fprintf_srccode(al->map, al->addr, stdout, |
|---|
| 1483 | + &thread->srccode_state); |
|---|
| 1484 | + if (ret) { |
|---|
| 1485 | + printed += ret; |
|---|
| 1486 | + printed += printf("\n"); |
|---|
| 1487 | + } |
|---|
| 1488 | + } |
|---|
| 1489 | + return printed; |
|---|
| 1240 | 1490 | } |
|---|
| 1241 | 1491 | |
|---|
| 1242 | 1492 | static struct { |
|---|
| .. | .. |
|---|
| 1259 | 1509 | {0, NULL} |
|---|
| 1260 | 1510 | }; |
|---|
| 1261 | 1511 | |
|---|
| 1512 | +static const char *sample_flags_to_name(u32 flags) |
|---|
| 1513 | +{ |
|---|
| 1514 | + int i; |
|---|
| 1515 | + |
|---|
| 1516 | + for (i = 0; sample_flags[i].name ; i++) { |
|---|
| 1517 | + if (sample_flags[i].flags == flags) |
|---|
| 1518 | + return sample_flags[i].name; |
|---|
| 1519 | + } |
|---|
| 1520 | + |
|---|
| 1521 | + return NULL; |
|---|
| 1522 | +} |
|---|
| 1523 | + |
|---|
| 1262 | 1524 | static int perf_sample__fprintf_flags(u32 flags, FILE *fp) |
|---|
| 1263 | 1525 | { |
|---|
| 1264 | 1526 | const char *chars = PERF_IP_FLAG_CHARS; |
|---|
| .. | .. |
|---|
| 1268 | 1530 | char str[33]; |
|---|
| 1269 | 1531 | int i, pos = 0; |
|---|
| 1270 | 1532 | |
|---|
| 1271 | | - for (i = 0; sample_flags[i].name ; i++) { |
|---|
| 1272 | | - if (sample_flags[i].flags == (flags & ~PERF_IP_FLAG_IN_TX)) { |
|---|
| 1273 | | - name = sample_flags[i].name; |
|---|
| 1274 | | - break; |
|---|
| 1275 | | - } |
|---|
| 1533 | + name = sample_flags_to_name(flags & ~PERF_IP_FLAG_IN_TX); |
|---|
| 1534 | + if (name) |
|---|
| 1535 | + return fprintf(fp, " %-15s%4s ", name, in_tx ? "(x)" : ""); |
|---|
| 1536 | + |
|---|
| 1537 | + if (flags & PERF_IP_FLAG_TRACE_BEGIN) { |
|---|
| 1538 | + name = sample_flags_to_name(flags & ~(PERF_IP_FLAG_IN_TX | PERF_IP_FLAG_TRACE_BEGIN)); |
|---|
| 1539 | + if (name) |
|---|
| 1540 | + return fprintf(fp, " tr strt %-7s%4s ", name, in_tx ? "(x)" : ""); |
|---|
| 1541 | + } |
|---|
| 1542 | + |
|---|
| 1543 | + if (flags & PERF_IP_FLAG_TRACE_END) { |
|---|
| 1544 | + name = sample_flags_to_name(flags & ~(PERF_IP_FLAG_IN_TX | PERF_IP_FLAG_TRACE_END)); |
|---|
| 1545 | + if (name) |
|---|
| 1546 | + return fprintf(fp, " tr end %-7s%4s ", name, in_tx ? "(x)" : ""); |
|---|
| 1276 | 1547 | } |
|---|
| 1277 | 1548 | |
|---|
| 1278 | 1549 | for (i = 0; i < n; i++, flags >>= 1) { |
|---|
| .. | .. |
|---|
| 1285 | 1556 | } |
|---|
| 1286 | 1557 | str[pos] = 0; |
|---|
| 1287 | 1558 | |
|---|
| 1288 | | - if (name) |
|---|
| 1289 | | - return fprintf(fp, " %-7s%4s ", name, in_tx ? "(x)" : ""); |
|---|
| 1290 | | - |
|---|
| 1291 | | - return fprintf(fp, " %-11s ", str); |
|---|
| 1559 | + return fprintf(fp, " %-19s ", str); |
|---|
| 1292 | 1560 | } |
|---|
| 1293 | 1561 | |
|---|
| 1294 | 1562 | struct printer_data { |
|---|
| .. | .. |
|---|
| 1468 | 1736 | } |
|---|
| 1469 | 1737 | |
|---|
| 1470 | 1738 | static int perf_sample__fprintf_synth(struct perf_sample *sample, |
|---|
| 1471 | | - struct perf_evsel *evsel, FILE *fp) |
|---|
| 1739 | + struct evsel *evsel, FILE *fp) |
|---|
| 1472 | 1740 | { |
|---|
| 1473 | | - switch (evsel->attr.config) { |
|---|
| 1741 | + switch (evsel->core.attr.config) { |
|---|
| 1474 | 1742 | case PERF_SYNTH_INTEL_PTWRITE: |
|---|
| 1475 | 1743 | return perf_sample__fprintf_synth_ptwrite(sample, fp); |
|---|
| 1476 | 1744 | case PERF_SYNTH_INTEL_MWAIT: |
|---|
| .. | .. |
|---|
| 1490 | 1758 | return 0; |
|---|
| 1491 | 1759 | } |
|---|
| 1492 | 1760 | |
|---|
| 1493 | | -struct perf_script { |
|---|
| 1494 | | - struct perf_tool tool; |
|---|
| 1495 | | - struct perf_session *session; |
|---|
| 1496 | | - bool show_task_events; |
|---|
| 1497 | | - bool show_mmap_events; |
|---|
| 1498 | | - bool show_switch_events; |
|---|
| 1499 | | - bool show_namespace_events; |
|---|
| 1500 | | - bool show_lost_events; |
|---|
| 1501 | | - bool show_round_events; |
|---|
| 1502 | | - bool allocated; |
|---|
| 1503 | | - bool per_event_dump; |
|---|
| 1504 | | - struct cpu_map *cpus; |
|---|
| 1505 | | - struct thread_map *threads; |
|---|
| 1506 | | - int name_width; |
|---|
| 1507 | | - const char *time_str; |
|---|
| 1508 | | - struct perf_time_interval *ptime_range; |
|---|
| 1509 | | - int range_size; |
|---|
| 1510 | | - int range_num; |
|---|
| 1511 | | -}; |
|---|
| 1512 | | - |
|---|
| 1513 | | -static int perf_evlist__max_name_len(struct perf_evlist *evlist) |
|---|
| 1761 | +static int evlist__max_name_len(struct evlist *evlist) |
|---|
| 1514 | 1762 | { |
|---|
| 1515 | | - struct perf_evsel *evsel; |
|---|
| 1763 | + struct evsel *evsel; |
|---|
| 1516 | 1764 | int max = 0; |
|---|
| 1517 | 1765 | |
|---|
| 1518 | 1766 | evlist__for_each_entry(evlist, evsel) { |
|---|
| 1519 | | - int len = strlen(perf_evsel__name(evsel)); |
|---|
| 1767 | + int len = strlen(evsel__name(evsel)); |
|---|
| 1520 | 1768 | |
|---|
| 1521 | 1769 | max = MAX(len, max); |
|---|
| 1522 | 1770 | } |
|---|
| .. | .. |
|---|
| 1544 | 1792 | struct metric_ctx { |
|---|
| 1545 | 1793 | struct perf_sample *sample; |
|---|
| 1546 | 1794 | struct thread *thread; |
|---|
| 1547 | | - struct perf_evsel *evsel; |
|---|
| 1795 | + struct evsel *evsel; |
|---|
| 1548 | 1796 | FILE *fp; |
|---|
| 1549 | 1797 | }; |
|---|
| 1550 | 1798 | |
|---|
| 1551 | | -static void script_print_metric(void *ctx, const char *color, |
|---|
| 1799 | +static void script_print_metric(struct perf_stat_config *config __maybe_unused, |
|---|
| 1800 | + void *ctx, const char *color, |
|---|
| 1552 | 1801 | const char *fmt, |
|---|
| 1553 | 1802 | const char *unit, double val) |
|---|
| 1554 | 1803 | { |
|---|
| .. | .. |
|---|
| 1556 | 1805 | |
|---|
| 1557 | 1806 | if (!fmt) |
|---|
| 1558 | 1807 | return; |
|---|
| 1559 | | - perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel, |
|---|
| 1808 | + perf_sample__fprintf_start(NULL, mctx->sample, mctx->thread, mctx->evsel, |
|---|
| 1560 | 1809 | PERF_RECORD_SAMPLE, mctx->fp); |
|---|
| 1561 | 1810 | fputs("\tmetric: ", mctx->fp); |
|---|
| 1562 | 1811 | if (color) |
|---|
| .. | .. |
|---|
| 1566 | 1815 | fprintf(mctx->fp, " %s\n", unit); |
|---|
| 1567 | 1816 | } |
|---|
| 1568 | 1817 | |
|---|
| 1569 | | -static void script_new_line(void *ctx) |
|---|
| 1818 | +static void script_new_line(struct perf_stat_config *config __maybe_unused, |
|---|
| 1819 | + void *ctx) |
|---|
| 1570 | 1820 | { |
|---|
| 1571 | 1821 | struct metric_ctx *mctx = ctx; |
|---|
| 1572 | 1822 | |
|---|
| 1573 | | - perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel, |
|---|
| 1823 | + perf_sample__fprintf_start(NULL, mctx->sample, mctx->thread, mctx->evsel, |
|---|
| 1574 | 1824 | PERF_RECORD_SAMPLE, mctx->fp); |
|---|
| 1575 | 1825 | fputs("\tmetric: ", mctx->fp); |
|---|
| 1576 | 1826 | } |
|---|
| 1577 | 1827 | |
|---|
| 1578 | 1828 | static void perf_sample__fprint_metric(struct perf_script *script, |
|---|
| 1579 | 1829 | struct thread *thread, |
|---|
| 1580 | | - struct perf_evsel *evsel, |
|---|
| 1830 | + struct evsel *evsel, |
|---|
| 1581 | 1831 | struct perf_sample *sample, |
|---|
| 1582 | 1832 | FILE *fp) |
|---|
| 1583 | 1833 | { |
|---|
| .. | .. |
|---|
| 1592 | 1842 | }, |
|---|
| 1593 | 1843 | .force_header = false, |
|---|
| 1594 | 1844 | }; |
|---|
| 1595 | | - struct perf_evsel *ev2; |
|---|
| 1845 | + struct evsel *ev2; |
|---|
| 1596 | 1846 | u64 val; |
|---|
| 1597 | 1847 | |
|---|
| 1598 | 1848 | if (!evsel->stats) |
|---|
| .. | .. |
|---|
| 1605 | 1855 | sample->cpu, |
|---|
| 1606 | 1856 | &rt_stat); |
|---|
| 1607 | 1857 | evsel_script(evsel)->val = val; |
|---|
| 1608 | | - if (evsel_script(evsel->leader)->gnum == evsel->leader->nr_members) { |
|---|
| 1858 | + if (evsel_script(evsel->leader)->gnum == evsel->leader->core.nr_members) { |
|---|
| 1609 | 1859 | for_each_group_member (ev2, evsel->leader) { |
|---|
| 1610 | | - perf_stat__print_shadow_stats(ev2, |
|---|
| 1860 | + perf_stat__print_shadow_stats(&stat_config, ev2, |
|---|
| 1611 | 1861 | evsel_script(ev2)->val, |
|---|
| 1612 | 1862 | sample->cpu, |
|---|
| 1613 | 1863 | &ctx, |
|---|
| .. | .. |
|---|
| 1618 | 1868 | } |
|---|
| 1619 | 1869 | } |
|---|
| 1620 | 1870 | |
|---|
| 1871 | +static bool show_event(struct perf_sample *sample, |
|---|
| 1872 | + struct evsel *evsel, |
|---|
| 1873 | + struct thread *thread, |
|---|
| 1874 | + struct addr_location *al) |
|---|
| 1875 | +{ |
|---|
| 1876 | + int depth = thread_stack__depth(thread, sample->cpu); |
|---|
| 1877 | + |
|---|
| 1878 | + if (!symbol_conf.graph_function) |
|---|
| 1879 | + return true; |
|---|
| 1880 | + |
|---|
| 1881 | + if (thread->filter) { |
|---|
| 1882 | + if (depth <= thread->filter_entry_depth) { |
|---|
| 1883 | + thread->filter = false; |
|---|
| 1884 | + return false; |
|---|
| 1885 | + } |
|---|
| 1886 | + return true; |
|---|
| 1887 | + } else { |
|---|
| 1888 | + const char *s = symbol_conf.graph_function; |
|---|
| 1889 | + u64 ip; |
|---|
| 1890 | + const char *name = resolve_branch_sym(sample, evsel, thread, al, |
|---|
| 1891 | + &ip); |
|---|
| 1892 | + unsigned nlen; |
|---|
| 1893 | + |
|---|
| 1894 | + if (!name) |
|---|
| 1895 | + return false; |
|---|
| 1896 | + nlen = strlen(name); |
|---|
| 1897 | + while (*s) { |
|---|
| 1898 | + unsigned len = strcspn(s, ","); |
|---|
| 1899 | + if (nlen == len && !strncmp(name, s, len)) { |
|---|
| 1900 | + thread->filter = true; |
|---|
| 1901 | + thread->filter_entry_depth = depth; |
|---|
| 1902 | + return true; |
|---|
| 1903 | + } |
|---|
| 1904 | + s += len; |
|---|
| 1905 | + if (*s == ',') |
|---|
| 1906 | + s++; |
|---|
| 1907 | + } |
|---|
| 1908 | + return false; |
|---|
| 1909 | + } |
|---|
| 1910 | +} |
|---|
| 1911 | + |
|---|
| 1621 | 1912 | static void process_event(struct perf_script *script, |
|---|
| 1622 | | - struct perf_sample *sample, struct perf_evsel *evsel, |
|---|
| 1913 | + struct perf_sample *sample, struct evsel *evsel, |
|---|
| 1623 | 1914 | struct addr_location *al, |
|---|
| 1624 | 1915 | struct machine *machine) |
|---|
| 1625 | 1916 | { |
|---|
| 1626 | 1917 | struct thread *thread = al->thread; |
|---|
| 1627 | | - struct perf_event_attr *attr = &evsel->attr; |
|---|
| 1918 | + struct perf_event_attr *attr = &evsel->core.attr; |
|---|
| 1628 | 1919 | unsigned int type = output_type(attr->type); |
|---|
| 1629 | | - struct perf_evsel_script *es = evsel->priv; |
|---|
| 1920 | + struct evsel_script *es = evsel->priv; |
|---|
| 1630 | 1921 | FILE *fp = es->fp; |
|---|
| 1631 | 1922 | |
|---|
| 1632 | 1923 | if (output[type].fields == 0) |
|---|
| 1633 | 1924 | return; |
|---|
| 1634 | 1925 | |
|---|
| 1926 | + if (!show_event(sample, evsel, thread, al)) |
|---|
| 1927 | + return; |
|---|
| 1928 | + |
|---|
| 1929 | + if (evswitch__discard(&script->evswitch, evsel)) |
|---|
| 1930 | + return; |
|---|
| 1931 | + |
|---|
| 1635 | 1932 | ++es->samples; |
|---|
| 1636 | 1933 | |
|---|
| 1637 | | - perf_sample__fprintf_start(sample, thread, evsel, |
|---|
| 1934 | + perf_sample__fprintf_start(script, sample, thread, evsel, |
|---|
| 1638 | 1935 | PERF_RECORD_SAMPLE, fp); |
|---|
| 1639 | 1936 | |
|---|
| 1640 | 1937 | if (PRINT_FIELD(PERIOD)) |
|---|
| 1641 | 1938 | fprintf(fp, "%10" PRIu64 " ", sample->period); |
|---|
| 1642 | 1939 | |
|---|
| 1643 | 1940 | if (PRINT_FIELD(EVNAME)) { |
|---|
| 1644 | | - const char *evname = perf_evsel__name(evsel); |
|---|
| 1941 | + const char *evname = evsel__name(evsel); |
|---|
| 1645 | 1942 | |
|---|
| 1646 | 1943 | if (!script->name_width) |
|---|
| 1647 | | - script->name_width = perf_evlist__max_name_len(script->session->evlist); |
|---|
| 1944 | + script->name_width = evlist__max_name_len(script->session->evlist); |
|---|
| 1648 | 1945 | |
|---|
| 1649 | 1946 | fprintf(fp, "%*s: ", script->name_width, evname ?: "[unknown]"); |
|---|
| 1650 | 1947 | } |
|---|
| .. | .. |
|---|
| 1677 | 1974 | if (PRINT_FIELD(IP)) { |
|---|
| 1678 | 1975 | struct callchain_cursor *cursor = NULL; |
|---|
| 1679 | 1976 | |
|---|
| 1977 | + if (script->stitch_lbr) |
|---|
| 1978 | + al->thread->lbr_stitch_enable = true; |
|---|
| 1979 | + |
|---|
| 1680 | 1980 | if (symbol_conf.use_callchain && sample->callchain && |
|---|
| 1681 | 1981 | thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
|---|
| 1682 | 1982 | sample, NULL, NULL, scripting_max_stack) == 0) |
|---|
| 1683 | 1983 | cursor = &callchain_cursor; |
|---|
| 1684 | 1984 | |
|---|
| 1685 | 1985 | fputc(cursor ? '\n' : ' ', fp); |
|---|
| 1686 | | - sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, fp); |
|---|
| 1986 | + sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, |
|---|
| 1987 | + symbol_conf.bt_stop_list, fp); |
|---|
| 1687 | 1988 | } |
|---|
| 1688 | 1989 | |
|---|
| 1689 | 1990 | if (PRINT_FIELD(IREGS)) |
|---|
| .. | .. |
|---|
| 1699 | 2000 | else if (PRINT_FIELD(BRSTACKOFF)) |
|---|
| 1700 | 2001 | perf_sample__fprintf_brstackoff(sample, thread, attr, fp); |
|---|
| 1701 | 2002 | |
|---|
| 1702 | | - if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) |
|---|
| 2003 | + if (evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) |
|---|
| 1703 | 2004 | perf_sample__fprintf_bpf_output(sample, fp); |
|---|
| 1704 | 2005 | perf_sample__fprintf_insn(sample, attr, thread, machine, fp); |
|---|
| 1705 | 2006 | |
|---|
| 1706 | 2007 | if (PRINT_FIELD(PHYS_ADDR)) |
|---|
| 1707 | 2008 | fprintf(fp, "%16" PRIx64, sample->phys_addr); |
|---|
| 2009 | + |
|---|
| 2010 | + perf_sample__fprintf_ipc(sample, attr, fp); |
|---|
| 2011 | + |
|---|
| 1708 | 2012 | fprintf(fp, "\n"); |
|---|
| 2013 | + |
|---|
| 2014 | + if (PRINT_FIELD(SRCCODE)) { |
|---|
| 2015 | + if (map__fprintf_srccode(al->map, al->addr, stdout, |
|---|
| 2016 | + &thread->srccode_state)) |
|---|
| 2017 | + printf("\n"); |
|---|
| 2018 | + } |
|---|
| 1709 | 2019 | |
|---|
| 1710 | 2020 | if (PRINT_FIELD(METRIC)) |
|---|
| 1711 | 2021 | perf_sample__fprint_metric(script, thread, evsel, sample, fp); |
|---|
| 2022 | + |
|---|
| 2023 | + if (verbose) |
|---|
| 2024 | + fflush(fp); |
|---|
| 1712 | 2025 | } |
|---|
| 1713 | 2026 | |
|---|
| 1714 | 2027 | static struct scripting_ops *scripting_ops; |
|---|
| 1715 | 2028 | |
|---|
| 1716 | | -static void __process_stat(struct perf_evsel *counter, u64 tstamp) |
|---|
| 2029 | +static void __process_stat(struct evsel *counter, u64 tstamp) |
|---|
| 1717 | 2030 | { |
|---|
| 1718 | | - int nthreads = thread_map__nr(counter->threads); |
|---|
| 1719 | | - int ncpus = perf_evsel__nr_cpus(counter); |
|---|
| 2031 | + int nthreads = perf_thread_map__nr(counter->core.threads); |
|---|
| 2032 | + int ncpus = evsel__nr_cpus(counter); |
|---|
| 1720 | 2033 | int cpu, thread; |
|---|
| 1721 | 2034 | static int header_printed; |
|---|
| 1722 | 2035 | |
|---|
| 1723 | | - if (counter->system_wide) |
|---|
| 2036 | + if (counter->core.system_wide) |
|---|
| 1724 | 2037 | nthreads = 1; |
|---|
| 1725 | 2038 | |
|---|
| 1726 | 2039 | if (!header_printed) { |
|---|
| .. | .. |
|---|
| 1736 | 2049 | counts = perf_counts(counter->counts, cpu, thread); |
|---|
| 1737 | 2050 | |
|---|
| 1738 | 2051 | printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n", |
|---|
| 1739 | | - counter->cpus->map[cpu], |
|---|
| 1740 | | - thread_map__pid(counter->threads, thread), |
|---|
| 2052 | + counter->core.cpus->map[cpu], |
|---|
| 2053 | + perf_thread_map__pid(counter->core.threads, thread), |
|---|
| 1741 | 2054 | counts->val, |
|---|
| 1742 | 2055 | counts->ena, |
|---|
| 1743 | 2056 | counts->run, |
|---|
| 1744 | 2057 | tstamp, |
|---|
| 1745 | | - perf_evsel__name(counter)); |
|---|
| 2058 | + evsel__name(counter)); |
|---|
| 1746 | 2059 | } |
|---|
| 1747 | 2060 | } |
|---|
| 1748 | 2061 | } |
|---|
| 1749 | 2062 | |
|---|
| 1750 | | -static void process_stat(struct perf_evsel *counter, u64 tstamp) |
|---|
| 2063 | +static void process_stat(struct evsel *counter, u64 tstamp) |
|---|
| 1751 | 2064 | { |
|---|
| 1752 | 2065 | if (scripting_ops && scripting_ops->process_stat) |
|---|
| 1753 | 2066 | scripting_ops->process_stat(&stat_config, counter, tstamp); |
|---|
| .. | .. |
|---|
| 1779 | 2092 | return scripting_ops ? scripting_ops->stop_script() : 0; |
|---|
| 1780 | 2093 | } |
|---|
| 1781 | 2094 | |
|---|
| 2095 | +static bool filter_cpu(struct perf_sample *sample) |
|---|
| 2096 | +{ |
|---|
| 2097 | + if (cpu_list && sample->cpu != (u32)-1) |
|---|
| 2098 | + return !test_bit(sample->cpu, cpu_bitmap); |
|---|
| 2099 | + return false; |
|---|
| 2100 | +} |
|---|
| 2101 | + |
|---|
| 1782 | 2102 | static int process_sample_event(struct perf_tool *tool, |
|---|
| 1783 | 2103 | union perf_event *event, |
|---|
| 1784 | 2104 | struct perf_sample *sample, |
|---|
| 1785 | | - struct perf_evsel *evsel, |
|---|
| 2105 | + struct evsel *evsel, |
|---|
| 1786 | 2106 | struct machine *machine) |
|---|
| 1787 | 2107 | { |
|---|
| 1788 | 2108 | struct perf_script *scr = container_of(tool, struct perf_script, tool); |
|---|
| .. | .. |
|---|
| 1813 | 2133 | if (al.filtered) |
|---|
| 1814 | 2134 | goto out_put; |
|---|
| 1815 | 2135 | |
|---|
| 1816 | | - if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) |
|---|
| 2136 | + if (filter_cpu(sample)) |
|---|
| 1817 | 2137 | goto out_put; |
|---|
| 1818 | 2138 | |
|---|
| 1819 | 2139 | if (scripting_ops) |
|---|
| .. | .. |
|---|
| 1826 | 2146 | return 0; |
|---|
| 1827 | 2147 | } |
|---|
| 1828 | 2148 | |
|---|
| 2149 | +// Used when scr->per_event_dump is not set |
|---|
| 2150 | +static struct evsel_script es_stdout; |
|---|
| 2151 | + |
|---|
| 1829 | 2152 | static int process_attr(struct perf_tool *tool, union perf_event *event, |
|---|
| 1830 | | - struct perf_evlist **pevlist) |
|---|
| 2153 | + struct evlist **pevlist) |
|---|
| 1831 | 2154 | { |
|---|
| 1832 | 2155 | struct perf_script *scr = container_of(tool, struct perf_script, tool); |
|---|
| 1833 | | - struct perf_evlist *evlist; |
|---|
| 1834 | | - struct perf_evsel *evsel, *pos; |
|---|
| 2156 | + struct evlist *evlist; |
|---|
| 2157 | + struct evsel *evsel, *pos; |
|---|
| 2158 | + u64 sample_type; |
|---|
| 1835 | 2159 | int err; |
|---|
| 1836 | | - static struct perf_evsel_script *es; |
|---|
| 1837 | 2160 | |
|---|
| 1838 | 2161 | err = perf_event__process_attr(tool, event, pevlist); |
|---|
| 1839 | 2162 | if (err) |
|---|
| 1840 | 2163 | return err; |
|---|
| 1841 | 2164 | |
|---|
| 1842 | 2165 | evlist = *pevlist; |
|---|
| 1843 | | - evsel = perf_evlist__last(*pevlist); |
|---|
| 2166 | + evsel = evlist__last(*pevlist); |
|---|
| 1844 | 2167 | |
|---|
| 1845 | 2168 | if (!evsel->priv) { |
|---|
| 1846 | | - if (scr->per_event_dump) { |
|---|
| 1847 | | - evsel->priv = perf_evsel_script__new(evsel, |
|---|
| 1848 | | - scr->session->data); |
|---|
| 1849 | | - } else { |
|---|
| 1850 | | - es = zalloc(sizeof(*es)); |
|---|
| 1851 | | - if (!es) |
|---|
| 2169 | + if (scr->per_event_dump) { |
|---|
| 2170 | + evsel->priv = evsel_script__new(evsel, scr->session->data); |
|---|
| 2171 | + if (!evsel->priv) |
|---|
| 1852 | 2172 | return -ENOMEM; |
|---|
| 1853 | | - es->fp = stdout; |
|---|
| 1854 | | - evsel->priv = es; |
|---|
| 2173 | + } else { // Replicate what is done in perf_script__setup_per_event_dump() |
|---|
| 2174 | + es_stdout.fp = stdout; |
|---|
| 2175 | + evsel->priv = &es_stdout; |
|---|
| 1855 | 2176 | } |
|---|
| 1856 | 2177 | } |
|---|
| 1857 | 2178 | |
|---|
| 1858 | | - if (evsel->attr.type >= PERF_TYPE_MAX && |
|---|
| 1859 | | - evsel->attr.type != PERF_TYPE_SYNTH) |
|---|
| 2179 | + if (evsel->core.attr.type >= PERF_TYPE_MAX && |
|---|
| 2180 | + evsel->core.attr.type != PERF_TYPE_SYNTH) |
|---|
| 1860 | 2181 | return 0; |
|---|
| 1861 | 2182 | |
|---|
| 1862 | 2183 | evlist__for_each_entry(evlist, pos) { |
|---|
| 1863 | | - if (pos->attr.type == evsel->attr.type && pos != evsel) |
|---|
| 2184 | + if (pos->core.attr.type == evsel->core.attr.type && pos != evsel) |
|---|
| 1864 | 2185 | return 0; |
|---|
| 1865 | 2186 | } |
|---|
| 1866 | 2187 | |
|---|
| 1867 | | - set_print_ip_opts(&evsel->attr); |
|---|
| 2188 | + if (evsel->core.attr.sample_type) { |
|---|
| 2189 | + err = evsel__check_attr(evsel, scr->session); |
|---|
| 2190 | + if (err) |
|---|
| 2191 | + return err; |
|---|
| 2192 | + } |
|---|
| 1868 | 2193 | |
|---|
| 1869 | | - if (evsel->attr.sample_type) |
|---|
| 1870 | | - err = perf_evsel__check_attr(evsel, scr->session); |
|---|
| 2194 | + /* |
|---|
| 2195 | + * Check if we need to enable callchains based |
|---|
| 2196 | + * on events sample_type. |
|---|
| 2197 | + */ |
|---|
| 2198 | + sample_type = evlist__combined_sample_type(evlist); |
|---|
| 2199 | + callchain_param_setup(sample_type); |
|---|
| 1871 | 2200 | |
|---|
| 1872 | | - return err; |
|---|
| 2201 | + /* Enable fields for callchain entries */ |
|---|
| 2202 | + if (symbol_conf.use_callchain && |
|---|
| 2203 | + (sample_type & PERF_SAMPLE_CALLCHAIN || |
|---|
| 2204 | + sample_type & PERF_SAMPLE_BRANCH_STACK || |
|---|
| 2205 | + (sample_type & PERF_SAMPLE_REGS_USER && |
|---|
| 2206 | + sample_type & PERF_SAMPLE_STACK_USER))) { |
|---|
| 2207 | + int type = output_type(evsel->core.attr.type); |
|---|
| 2208 | + |
|---|
| 2209 | + if (!(output[type].user_unset_fields & PERF_OUTPUT_IP)) |
|---|
| 2210 | + output[type].fields |= PERF_OUTPUT_IP; |
|---|
| 2211 | + if (!(output[type].user_unset_fields & PERF_OUTPUT_SYM)) |
|---|
| 2212 | + output[type].fields |= PERF_OUTPUT_SYM; |
|---|
| 2213 | + } |
|---|
| 2214 | + set_print_ip_opts(&evsel->core.attr); |
|---|
| 2215 | + return 0; |
|---|
| 2216 | +} |
|---|
| 2217 | + |
|---|
| 2218 | +static int print_event_with_time(struct perf_tool *tool, |
|---|
| 2219 | + union perf_event *event, |
|---|
| 2220 | + struct perf_sample *sample, |
|---|
| 2221 | + struct machine *machine, |
|---|
| 2222 | + pid_t pid, pid_t tid, u64 timestamp) |
|---|
| 2223 | +{ |
|---|
| 2224 | + struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 2225 | + struct perf_session *session = script->session; |
|---|
| 2226 | + struct evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
|---|
| 2227 | + struct thread *thread = NULL; |
|---|
| 2228 | + |
|---|
| 2229 | + if (evsel && !evsel->core.attr.sample_id_all) { |
|---|
| 2230 | + sample->cpu = 0; |
|---|
| 2231 | + sample->time = timestamp; |
|---|
| 2232 | + sample->pid = pid; |
|---|
| 2233 | + sample->tid = tid; |
|---|
| 2234 | + } |
|---|
| 2235 | + |
|---|
| 2236 | + if (filter_cpu(sample)) |
|---|
| 2237 | + return 0; |
|---|
| 2238 | + |
|---|
| 2239 | + if (tid != -1) |
|---|
| 2240 | + thread = machine__findnew_thread(machine, pid, tid); |
|---|
| 2241 | + |
|---|
| 2242 | + if (evsel) { |
|---|
| 2243 | + perf_sample__fprintf_start(script, sample, thread, evsel, |
|---|
| 2244 | + event->header.type, stdout); |
|---|
| 2245 | + } |
|---|
| 2246 | + |
|---|
| 2247 | + perf_event__fprintf(event, machine, stdout); |
|---|
| 2248 | + |
|---|
| 2249 | + thread__put(thread); |
|---|
| 2250 | + |
|---|
| 2251 | + return 0; |
|---|
| 2252 | +} |
|---|
| 2253 | + |
|---|
| 2254 | +static int print_event(struct perf_tool *tool, union perf_event *event, |
|---|
| 2255 | + struct perf_sample *sample, struct machine *machine, |
|---|
| 2256 | + pid_t pid, pid_t tid) |
|---|
| 2257 | +{ |
|---|
| 2258 | + return print_event_with_time(tool, event, sample, machine, pid, tid, 0); |
|---|
| 1873 | 2259 | } |
|---|
| 1874 | 2260 | |
|---|
| 1875 | 2261 | static int process_comm_event(struct perf_tool *tool, |
|---|
| .. | .. |
|---|
| 1877 | 2263 | struct perf_sample *sample, |
|---|
| 1878 | 2264 | struct machine *machine) |
|---|
| 1879 | 2265 | { |
|---|
| 1880 | | - struct thread *thread; |
|---|
| 1881 | | - struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 1882 | | - struct perf_session *session = script->session; |
|---|
| 1883 | | - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
|---|
| 1884 | | - int ret = -1; |
|---|
| 1885 | | - |
|---|
| 1886 | | - thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid); |
|---|
| 1887 | | - if (thread == NULL) { |
|---|
| 1888 | | - pr_debug("problem processing COMM event, skipping it.\n"); |
|---|
| 1889 | | - return -1; |
|---|
| 1890 | | - } |
|---|
| 1891 | | - |
|---|
| 1892 | 2266 | if (perf_event__process_comm(tool, event, sample, machine) < 0) |
|---|
| 1893 | | - goto out; |
|---|
| 2267 | + return -1; |
|---|
| 1894 | 2268 | |
|---|
| 1895 | | - if (!evsel->attr.sample_id_all) { |
|---|
| 1896 | | - sample->cpu = 0; |
|---|
| 1897 | | - sample->time = 0; |
|---|
| 1898 | | - sample->tid = event->comm.tid; |
|---|
| 1899 | | - sample->pid = event->comm.pid; |
|---|
| 1900 | | - } |
|---|
| 1901 | | - perf_sample__fprintf_start(sample, thread, evsel, |
|---|
| 1902 | | - PERF_RECORD_COMM, stdout); |
|---|
| 1903 | | - perf_event__fprintf(event, stdout); |
|---|
| 1904 | | - ret = 0; |
|---|
| 1905 | | -out: |
|---|
| 1906 | | - thread__put(thread); |
|---|
| 1907 | | - return ret; |
|---|
| 2269 | + return print_event(tool, event, sample, machine, event->comm.pid, |
|---|
| 2270 | + event->comm.tid); |
|---|
| 1908 | 2271 | } |
|---|
| 1909 | 2272 | |
|---|
| 1910 | 2273 | static int process_namespaces_event(struct perf_tool *tool, |
|---|
| .. | .. |
|---|
| 1912 | 2275 | struct perf_sample *sample, |
|---|
| 1913 | 2276 | struct machine *machine) |
|---|
| 1914 | 2277 | { |
|---|
| 1915 | | - struct thread *thread; |
|---|
| 1916 | | - struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 1917 | | - struct perf_session *session = script->session; |
|---|
| 1918 | | - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
|---|
| 1919 | | - int ret = -1; |
|---|
| 1920 | | - |
|---|
| 1921 | | - thread = machine__findnew_thread(machine, event->namespaces.pid, |
|---|
| 1922 | | - event->namespaces.tid); |
|---|
| 1923 | | - if (thread == NULL) { |
|---|
| 1924 | | - pr_debug("problem processing NAMESPACES event, skipping it.\n"); |
|---|
| 1925 | | - return -1; |
|---|
| 1926 | | - } |
|---|
| 1927 | | - |
|---|
| 1928 | 2278 | if (perf_event__process_namespaces(tool, event, sample, machine) < 0) |
|---|
| 1929 | | - goto out; |
|---|
| 2279 | + return -1; |
|---|
| 1930 | 2280 | |
|---|
| 1931 | | - if (!evsel->attr.sample_id_all) { |
|---|
| 1932 | | - sample->cpu = 0; |
|---|
| 1933 | | - sample->time = 0; |
|---|
| 1934 | | - sample->tid = event->namespaces.tid; |
|---|
| 1935 | | - sample->pid = event->namespaces.pid; |
|---|
| 1936 | | - } |
|---|
| 1937 | | - perf_sample__fprintf_start(sample, thread, evsel, |
|---|
| 1938 | | - PERF_RECORD_NAMESPACES, stdout); |
|---|
| 1939 | | - perf_event__fprintf(event, stdout); |
|---|
| 1940 | | - ret = 0; |
|---|
| 1941 | | -out: |
|---|
| 1942 | | - thread__put(thread); |
|---|
| 1943 | | - return ret; |
|---|
| 2281 | + return print_event(tool, event, sample, machine, event->namespaces.pid, |
|---|
| 2282 | + event->namespaces.tid); |
|---|
| 2283 | +} |
|---|
| 2284 | + |
|---|
| 2285 | +static int process_cgroup_event(struct perf_tool *tool, |
|---|
| 2286 | + union perf_event *event, |
|---|
| 2287 | + struct perf_sample *sample, |
|---|
| 2288 | + struct machine *machine) |
|---|
| 2289 | +{ |
|---|
| 2290 | + if (perf_event__process_cgroup(tool, event, sample, machine) < 0) |
|---|
| 2291 | + return -1; |
|---|
| 2292 | + |
|---|
| 2293 | + return print_event(tool, event, sample, machine, sample->pid, |
|---|
| 2294 | + sample->tid); |
|---|
| 1944 | 2295 | } |
|---|
| 1945 | 2296 | |
|---|
| 1946 | 2297 | static int process_fork_event(struct perf_tool *tool, |
|---|
| .. | .. |
|---|
| 1948 | 2299 | struct perf_sample *sample, |
|---|
| 1949 | 2300 | struct machine *machine) |
|---|
| 1950 | 2301 | { |
|---|
| 1951 | | - struct thread *thread; |
|---|
| 1952 | | - struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 1953 | | - struct perf_session *session = script->session; |
|---|
| 1954 | | - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
|---|
| 1955 | | - |
|---|
| 1956 | 2302 | if (perf_event__process_fork(tool, event, sample, machine) < 0) |
|---|
| 1957 | 2303 | return -1; |
|---|
| 1958 | 2304 | |
|---|
| 1959 | | - thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid); |
|---|
| 1960 | | - if (thread == NULL) { |
|---|
| 1961 | | - pr_debug("problem processing FORK event, skipping it.\n"); |
|---|
| 1962 | | - return -1; |
|---|
| 1963 | | - } |
|---|
| 1964 | | - |
|---|
| 1965 | | - if (!evsel->attr.sample_id_all) { |
|---|
| 1966 | | - sample->cpu = 0; |
|---|
| 1967 | | - sample->time = event->fork.time; |
|---|
| 1968 | | - sample->tid = event->fork.tid; |
|---|
| 1969 | | - sample->pid = event->fork.pid; |
|---|
| 1970 | | - } |
|---|
| 1971 | | - perf_sample__fprintf_start(sample, thread, evsel, |
|---|
| 1972 | | - PERF_RECORD_FORK, stdout); |
|---|
| 1973 | | - perf_event__fprintf(event, stdout); |
|---|
| 1974 | | - thread__put(thread); |
|---|
| 1975 | | - |
|---|
| 1976 | | - return 0; |
|---|
| 2305 | + return print_event_with_time(tool, event, sample, machine, |
|---|
| 2306 | + event->fork.pid, event->fork.tid, |
|---|
| 2307 | + event->fork.time); |
|---|
| 1977 | 2308 | } |
|---|
| 1978 | 2309 | static int process_exit_event(struct perf_tool *tool, |
|---|
| 1979 | 2310 | union perf_event *event, |
|---|
| 1980 | 2311 | struct perf_sample *sample, |
|---|
| 1981 | 2312 | struct machine *machine) |
|---|
| 1982 | 2313 | { |
|---|
| 1983 | | - int err = 0; |
|---|
| 1984 | | - struct thread *thread; |
|---|
| 1985 | | - struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 1986 | | - struct perf_session *session = script->session; |
|---|
| 1987 | | - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
|---|
| 1988 | | - |
|---|
| 1989 | | - thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid); |
|---|
| 1990 | | - if (thread == NULL) { |
|---|
| 1991 | | - pr_debug("problem processing EXIT event, skipping it.\n"); |
|---|
| 2314 | + /* Print before 'exit' deletes anything */ |
|---|
| 2315 | + if (print_event_with_time(tool, event, sample, machine, event->fork.pid, |
|---|
| 2316 | + event->fork.tid, event->fork.time)) |
|---|
| 1992 | 2317 | return -1; |
|---|
| 1993 | | - } |
|---|
| 1994 | 2318 | |
|---|
| 1995 | | - if (!evsel->attr.sample_id_all) { |
|---|
| 1996 | | - sample->cpu = 0; |
|---|
| 1997 | | - sample->time = 0; |
|---|
| 1998 | | - sample->tid = event->fork.tid; |
|---|
| 1999 | | - sample->pid = event->fork.pid; |
|---|
| 2000 | | - } |
|---|
| 2001 | | - perf_sample__fprintf_start(sample, thread, evsel, |
|---|
| 2002 | | - PERF_RECORD_EXIT, stdout); |
|---|
| 2003 | | - perf_event__fprintf(event, stdout); |
|---|
| 2004 | | - |
|---|
| 2005 | | - if (perf_event__process_exit(tool, event, sample, machine) < 0) |
|---|
| 2006 | | - err = -1; |
|---|
| 2007 | | - |
|---|
| 2008 | | - thread__put(thread); |
|---|
| 2009 | | - return err; |
|---|
| 2319 | + return perf_event__process_exit(tool, event, sample, machine); |
|---|
| 2010 | 2320 | } |
|---|
| 2011 | 2321 | |
|---|
| 2012 | 2322 | static int process_mmap_event(struct perf_tool *tool, |
|---|
| .. | .. |
|---|
| 2014 | 2324 | struct perf_sample *sample, |
|---|
| 2015 | 2325 | struct machine *machine) |
|---|
| 2016 | 2326 | { |
|---|
| 2017 | | - struct thread *thread; |
|---|
| 2018 | | - struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 2019 | | - struct perf_session *session = script->session; |
|---|
| 2020 | | - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
|---|
| 2021 | | - |
|---|
| 2022 | 2327 | if (perf_event__process_mmap(tool, event, sample, machine) < 0) |
|---|
| 2023 | 2328 | return -1; |
|---|
| 2024 | 2329 | |
|---|
| 2025 | | - thread = machine__findnew_thread(machine, event->mmap.pid, event->mmap.tid); |
|---|
| 2026 | | - if (thread == NULL) { |
|---|
| 2027 | | - pr_debug("problem processing MMAP event, skipping it.\n"); |
|---|
| 2028 | | - return -1; |
|---|
| 2029 | | - } |
|---|
| 2030 | | - |
|---|
| 2031 | | - if (!evsel->attr.sample_id_all) { |
|---|
| 2032 | | - sample->cpu = 0; |
|---|
| 2033 | | - sample->time = 0; |
|---|
| 2034 | | - sample->tid = event->mmap.tid; |
|---|
| 2035 | | - sample->pid = event->mmap.pid; |
|---|
| 2036 | | - } |
|---|
| 2037 | | - perf_sample__fprintf_start(sample, thread, evsel, |
|---|
| 2038 | | - PERF_RECORD_MMAP, stdout); |
|---|
| 2039 | | - perf_event__fprintf(event, stdout); |
|---|
| 2040 | | - thread__put(thread); |
|---|
| 2041 | | - return 0; |
|---|
| 2330 | + return print_event(tool, event, sample, machine, event->mmap.pid, |
|---|
| 2331 | + event->mmap.tid); |
|---|
| 2042 | 2332 | } |
|---|
| 2043 | 2333 | |
|---|
| 2044 | 2334 | static int process_mmap2_event(struct perf_tool *tool, |
|---|
| .. | .. |
|---|
| 2046 | 2336 | struct perf_sample *sample, |
|---|
| 2047 | 2337 | struct machine *machine) |
|---|
| 2048 | 2338 | { |
|---|
| 2049 | | - struct thread *thread; |
|---|
| 2050 | | - struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 2051 | | - struct perf_session *session = script->session; |
|---|
| 2052 | | - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
|---|
| 2053 | | - |
|---|
| 2054 | 2339 | if (perf_event__process_mmap2(tool, event, sample, machine) < 0) |
|---|
| 2055 | 2340 | return -1; |
|---|
| 2056 | 2341 | |
|---|
| 2057 | | - thread = machine__findnew_thread(machine, event->mmap2.pid, event->mmap2.tid); |
|---|
| 2058 | | - if (thread == NULL) { |
|---|
| 2059 | | - pr_debug("problem processing MMAP2 event, skipping it.\n"); |
|---|
| 2060 | | - return -1; |
|---|
| 2061 | | - } |
|---|
| 2062 | | - |
|---|
| 2063 | | - if (!evsel->attr.sample_id_all) { |
|---|
| 2064 | | - sample->cpu = 0; |
|---|
| 2065 | | - sample->time = 0; |
|---|
| 2066 | | - sample->tid = event->mmap2.tid; |
|---|
| 2067 | | - sample->pid = event->mmap2.pid; |
|---|
| 2068 | | - } |
|---|
| 2069 | | - perf_sample__fprintf_start(sample, thread, evsel, |
|---|
| 2070 | | - PERF_RECORD_MMAP2, stdout); |
|---|
| 2071 | | - perf_event__fprintf(event, stdout); |
|---|
| 2072 | | - thread__put(thread); |
|---|
| 2073 | | - return 0; |
|---|
| 2342 | + return print_event(tool, event, sample, machine, event->mmap2.pid, |
|---|
| 2343 | + event->mmap2.tid); |
|---|
| 2074 | 2344 | } |
|---|
| 2075 | 2345 | |
|---|
| 2076 | 2346 | static int process_switch_event(struct perf_tool *tool, |
|---|
| .. | .. |
|---|
| 2078 | 2348 | struct perf_sample *sample, |
|---|
| 2079 | 2349 | struct machine *machine) |
|---|
| 2080 | 2350 | { |
|---|
| 2081 | | - struct thread *thread; |
|---|
| 2082 | 2351 | struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 2083 | | - struct perf_session *session = script->session; |
|---|
| 2084 | | - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
|---|
| 2085 | 2352 | |
|---|
| 2086 | 2353 | if (perf_event__process_switch(tool, event, sample, machine) < 0) |
|---|
| 2087 | 2354 | return -1; |
|---|
| 2088 | 2355 | |
|---|
| 2089 | | - thread = machine__findnew_thread(machine, sample->pid, |
|---|
| 2090 | | - sample->tid); |
|---|
| 2091 | | - if (thread == NULL) { |
|---|
| 2092 | | - pr_debug("problem processing SWITCH event, skipping it.\n"); |
|---|
| 2093 | | - return -1; |
|---|
| 2094 | | - } |
|---|
| 2356 | + if (scripting_ops && scripting_ops->process_switch && !filter_cpu(sample)) |
|---|
| 2357 | + scripting_ops->process_switch(event, sample, machine); |
|---|
| 2095 | 2358 | |
|---|
| 2096 | | - perf_sample__fprintf_start(sample, thread, evsel, |
|---|
| 2097 | | - PERF_RECORD_SWITCH, stdout); |
|---|
| 2098 | | - perf_event__fprintf(event, stdout); |
|---|
| 2099 | | - thread__put(thread); |
|---|
| 2100 | | - return 0; |
|---|
| 2359 | + if (!script->show_switch_events) |
|---|
| 2360 | + return 0; |
|---|
| 2361 | + |
|---|
| 2362 | + return print_event(tool, event, sample, machine, sample->pid, |
|---|
| 2363 | + sample->tid); |
|---|
| 2101 | 2364 | } |
|---|
| 2102 | 2365 | |
|---|
| 2103 | 2366 | static int |
|---|
| .. | .. |
|---|
| 2106 | 2369 | struct perf_sample *sample, |
|---|
| 2107 | 2370 | struct machine *machine) |
|---|
| 2108 | 2371 | { |
|---|
| 2109 | | - struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 2110 | | - struct perf_session *session = script->session; |
|---|
| 2111 | | - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
|---|
| 2112 | | - struct thread *thread; |
|---|
| 2113 | | - |
|---|
| 2114 | | - thread = machine__findnew_thread(machine, sample->pid, |
|---|
| 2115 | | - sample->tid); |
|---|
| 2116 | | - if (thread == NULL) |
|---|
| 2117 | | - return -1; |
|---|
| 2118 | | - |
|---|
| 2119 | | - perf_sample__fprintf_start(sample, thread, evsel, |
|---|
| 2120 | | - PERF_RECORD_LOST, stdout); |
|---|
| 2121 | | - perf_event__fprintf(event, stdout); |
|---|
| 2122 | | - thread__put(thread); |
|---|
| 2123 | | - return 0; |
|---|
| 2372 | + return print_event(tool, event, sample, machine, sample->pid, |
|---|
| 2373 | + sample->tid); |
|---|
| 2124 | 2374 | } |
|---|
| 2125 | 2375 | |
|---|
| 2126 | 2376 | static int |
|---|
| .. | .. |
|---|
| 2129 | 2379 | struct ordered_events *oe __maybe_unused) |
|---|
| 2130 | 2380 | |
|---|
| 2131 | 2381 | { |
|---|
| 2132 | | - perf_event__fprintf(event, stdout); |
|---|
| 2382 | + perf_event__fprintf(event, NULL, stdout); |
|---|
| 2133 | 2383 | return 0; |
|---|
| 2384 | +} |
|---|
| 2385 | + |
|---|
| 2386 | +static int |
|---|
| 2387 | +process_bpf_events(struct perf_tool *tool __maybe_unused, |
|---|
| 2388 | + union perf_event *event, |
|---|
| 2389 | + struct perf_sample *sample, |
|---|
| 2390 | + struct machine *machine) |
|---|
| 2391 | +{ |
|---|
| 2392 | + if (machine__process_ksymbol(machine, event, sample) < 0) |
|---|
| 2393 | + return -1; |
|---|
| 2394 | + |
|---|
| 2395 | + return print_event(tool, event, sample, machine, sample->pid, |
|---|
| 2396 | + sample->tid); |
|---|
| 2397 | +} |
|---|
| 2398 | + |
|---|
| 2399 | +static int process_text_poke_events(struct perf_tool *tool, |
|---|
| 2400 | + union perf_event *event, |
|---|
| 2401 | + struct perf_sample *sample, |
|---|
| 2402 | + struct machine *machine) |
|---|
| 2403 | +{ |
|---|
| 2404 | + if (perf_event__process_text_poke(tool, event, sample, machine) < 0) |
|---|
| 2405 | + return -1; |
|---|
| 2406 | + |
|---|
| 2407 | + return print_event(tool, event, sample, machine, sample->pid, |
|---|
| 2408 | + sample->tid); |
|---|
| 2134 | 2409 | } |
|---|
| 2135 | 2410 | |
|---|
| 2136 | 2411 | static void sig_handler(int sig __maybe_unused) |
|---|
| .. | .. |
|---|
| 2140 | 2415 | |
|---|
| 2141 | 2416 | static void perf_script__fclose_per_event_dump(struct perf_script *script) |
|---|
| 2142 | 2417 | { |
|---|
| 2143 | | - struct perf_evlist *evlist = script->session->evlist; |
|---|
| 2144 | | - struct perf_evsel *evsel; |
|---|
| 2418 | + struct evlist *evlist = script->session->evlist; |
|---|
| 2419 | + struct evsel *evsel; |
|---|
| 2145 | 2420 | |
|---|
| 2146 | 2421 | evlist__for_each_entry(evlist, evsel) { |
|---|
| 2147 | 2422 | if (!evsel->priv) |
|---|
| 2148 | 2423 | break; |
|---|
| 2149 | | - perf_evsel_script__delete(evsel->priv); |
|---|
| 2424 | + evsel_script__delete(evsel->priv); |
|---|
| 2150 | 2425 | evsel->priv = NULL; |
|---|
| 2151 | 2426 | } |
|---|
| 2152 | 2427 | } |
|---|
| 2153 | 2428 | |
|---|
| 2154 | 2429 | static int perf_script__fopen_per_event_dump(struct perf_script *script) |
|---|
| 2155 | 2430 | { |
|---|
| 2156 | | - struct perf_evsel *evsel; |
|---|
| 2431 | + struct evsel *evsel; |
|---|
| 2157 | 2432 | |
|---|
| 2158 | 2433 | evlist__for_each_entry(script->session->evlist, evsel) { |
|---|
| 2159 | 2434 | /* |
|---|
| .. | .. |
|---|
| 2166 | 2441 | if (evsel->priv != NULL) |
|---|
| 2167 | 2442 | continue; |
|---|
| 2168 | 2443 | |
|---|
| 2169 | | - evsel->priv = perf_evsel_script__new(evsel, script->session->data); |
|---|
| 2444 | + evsel->priv = evsel_script__new(evsel, script->session->data); |
|---|
| 2170 | 2445 | if (evsel->priv == NULL) |
|---|
| 2171 | 2446 | goto out_err_fclose; |
|---|
| 2172 | 2447 | } |
|---|
| .. | .. |
|---|
| 2180 | 2455 | |
|---|
| 2181 | 2456 | static int perf_script__setup_per_event_dump(struct perf_script *script) |
|---|
| 2182 | 2457 | { |
|---|
| 2183 | | - struct perf_evsel *evsel; |
|---|
| 2184 | | - static struct perf_evsel_script es_stdout; |
|---|
| 2458 | + struct evsel *evsel; |
|---|
| 2185 | 2459 | |
|---|
| 2186 | 2460 | if (script->per_event_dump) |
|---|
| 2187 | 2461 | return perf_script__fopen_per_event_dump(script); |
|---|
| .. | .. |
|---|
| 2196 | 2470 | |
|---|
| 2197 | 2471 | static void perf_script__exit_per_event_dump_stats(struct perf_script *script) |
|---|
| 2198 | 2472 | { |
|---|
| 2199 | | - struct perf_evsel *evsel; |
|---|
| 2473 | + struct evsel *evsel; |
|---|
| 2200 | 2474 | |
|---|
| 2201 | 2475 | evlist__for_each_entry(script->session->evlist, evsel) { |
|---|
| 2202 | | - struct perf_evsel_script *es = evsel->priv; |
|---|
| 2476 | + struct evsel_script *es = evsel->priv; |
|---|
| 2203 | 2477 | |
|---|
| 2204 | | - perf_evsel_script__fprintf(es, stdout); |
|---|
| 2205 | | - perf_evsel_script__delete(es); |
|---|
| 2478 | + evsel_script__fprintf(es, stdout); |
|---|
| 2479 | + evsel_script__delete(es); |
|---|
| 2206 | 2480 | evsel->priv = NULL; |
|---|
| 2207 | 2481 | } |
|---|
| 2482 | +} |
|---|
| 2483 | + |
|---|
| 2484 | +static void perf_script__exit(struct perf_script *script) |
|---|
| 2485 | +{ |
|---|
| 2486 | + perf_thread_map__put(script->threads); |
|---|
| 2487 | + perf_cpu_map__put(script->cpus); |
|---|
| 2208 | 2488 | } |
|---|
| 2209 | 2489 | |
|---|
| 2210 | 2490 | static int __cmd_script(struct perf_script *script) |
|---|
| .. | .. |
|---|
| 2225 | 2505 | script->tool.mmap = process_mmap_event; |
|---|
| 2226 | 2506 | script->tool.mmap2 = process_mmap2_event; |
|---|
| 2227 | 2507 | } |
|---|
| 2228 | | - if (script->show_switch_events) |
|---|
| 2508 | + if (script->show_switch_events || (scripting_ops && scripting_ops->process_switch)) |
|---|
| 2229 | 2509 | script->tool.context_switch = process_switch_event; |
|---|
| 2230 | 2510 | if (script->show_namespace_events) |
|---|
| 2231 | 2511 | script->tool.namespaces = process_namespaces_event; |
|---|
| 2512 | + if (script->show_cgroup_events) |
|---|
| 2513 | + script->tool.cgroup = process_cgroup_event; |
|---|
| 2232 | 2514 | if (script->show_lost_events) |
|---|
| 2233 | 2515 | script->tool.lost = process_lost_event; |
|---|
| 2234 | 2516 | if (script->show_round_events) { |
|---|
| 2235 | 2517 | script->tool.ordered_events = false; |
|---|
| 2236 | 2518 | script->tool.finished_round = process_finished_round_event; |
|---|
| 2519 | + } |
|---|
| 2520 | + if (script->show_bpf_events) { |
|---|
| 2521 | + script->tool.ksymbol = process_bpf_events; |
|---|
| 2522 | + script->tool.bpf = process_bpf_events; |
|---|
| 2523 | + } |
|---|
| 2524 | + if (script->show_text_poke_events) { |
|---|
| 2525 | + script->tool.ksymbol = process_bpf_events; |
|---|
| 2526 | + script->tool.text_poke = process_text_poke_events; |
|---|
| 2237 | 2527 | } |
|---|
| 2238 | 2528 | |
|---|
| 2239 | 2529 | if (perf_script__setup_per_event_dump(script)) { |
|---|
| .. | .. |
|---|
| 2255 | 2545 | struct script_spec { |
|---|
| 2256 | 2546 | struct list_head node; |
|---|
| 2257 | 2547 | struct scripting_ops *ops; |
|---|
| 2258 | | - char spec[0]; |
|---|
| 2548 | + char spec[]; |
|---|
| 2259 | 2549 | }; |
|---|
| 2260 | 2550 | |
|---|
| 2261 | 2551 | static LIST_HEAD(script_specs); |
|---|
| .. | .. |
|---|
| 2418 | 2708 | pr_warning("Overriding previous field request for %s events.\n", |
|---|
| 2419 | 2709 | event_type(type)); |
|---|
| 2420 | 2710 | |
|---|
| 2711 | + /* Don't override defaults for +- */ |
|---|
| 2712 | + if (strchr(tok, '+') || strchr(tok, '-')) |
|---|
| 2713 | + goto parse; |
|---|
| 2714 | + |
|---|
| 2421 | 2715 | output[type].fields = 0; |
|---|
| 2422 | 2716 | output[type].user_set = true; |
|---|
| 2423 | 2717 | output[type].wildcard_set = false; |
|---|
| .. | .. |
|---|
| 2486 | 2780 | pr_warning("\'%s\' not valid for %s events. Ignoring.\n", |
|---|
| 2487 | 2781 | all_output_options[i].str, event_type(j)); |
|---|
| 2488 | 2782 | } else { |
|---|
| 2489 | | - if (change == REMOVE) |
|---|
| 2783 | + if (change == REMOVE) { |
|---|
| 2490 | 2784 | output[j].fields &= ~all_output_options[i].field; |
|---|
| 2491 | | - else |
|---|
| 2785 | + output[j].user_set_fields &= ~all_output_options[i].field; |
|---|
| 2786 | + output[j].user_unset_fields |= all_output_options[i].field; |
|---|
| 2787 | + } else { |
|---|
| 2492 | 2788 | output[j].fields |= all_output_options[i].field; |
|---|
| 2789 | + output[j].user_set_fields |= all_output_options[i].field; |
|---|
| 2790 | + output[j].user_unset_fields &= ~all_output_options[i].field; |
|---|
| 2791 | + } |
|---|
| 2792 | + output[j].user_set = true; |
|---|
| 2793 | + output[j].wildcard_set = true; |
|---|
| 2493 | 2794 | } |
|---|
| 2494 | 2795 | } |
|---|
| 2495 | 2796 | } else { |
|---|
| .. | .. |
|---|
| 2500 | 2801 | rc = -EINVAL; |
|---|
| 2501 | 2802 | goto out; |
|---|
| 2502 | 2803 | } |
|---|
| 2503 | | - output[type].fields |= all_output_options[i].field; |
|---|
| 2804 | + if (change == REMOVE) |
|---|
| 2805 | + output[type].fields &= ~all_output_options[i].field; |
|---|
| 2806 | + else |
|---|
| 2807 | + output[type].fields |= all_output_options[i].field; |
|---|
| 2808 | + output[type].user_set = true; |
|---|
| 2809 | + output[type].wildcard_set = true; |
|---|
| 2504 | 2810 | } |
|---|
| 2505 | 2811 | } |
|---|
| 2506 | 2812 | |
|---|
| .. | .. |
|---|
| 2620 | 2926 | return -1; |
|---|
| 2621 | 2927 | |
|---|
| 2622 | 2928 | while (fgets(line, sizeof(line), fp)) { |
|---|
| 2623 | | - p = ltrim(line); |
|---|
| 2929 | + p = skip_spaces(line); |
|---|
| 2624 | 2930 | if (strlen(p) == 0) |
|---|
| 2625 | 2931 | continue; |
|---|
| 2626 | 2932 | if (*p != '#') |
|---|
| .. | .. |
|---|
| 2629 | 2935 | if (strlen(p) && *p == '!') |
|---|
| 2630 | 2936 | continue; |
|---|
| 2631 | 2937 | |
|---|
| 2632 | | - p = ltrim(p); |
|---|
| 2938 | + p = skip_spaces(p); |
|---|
| 2633 | 2939 | if (strlen(p) && p[strlen(p) - 1] == '\n') |
|---|
| 2634 | 2940 | p[strlen(p) - 1] = '\0'; |
|---|
| 2635 | 2941 | |
|---|
| 2636 | 2942 | if (!strncmp(p, "description:", strlen("description:"))) { |
|---|
| 2637 | 2943 | p += strlen("description:"); |
|---|
| 2638 | | - desc->half_liner = strdup(ltrim(p)); |
|---|
| 2944 | + desc->half_liner = strdup(skip_spaces(p)); |
|---|
| 2639 | 2945 | continue; |
|---|
| 2640 | 2946 | } |
|---|
| 2641 | 2947 | |
|---|
| 2642 | 2948 | if (!strncmp(p, "args:", strlen("args:"))) { |
|---|
| 2643 | 2949 | p += strlen("args:"); |
|---|
| 2644 | | - desc->args = strdup(ltrim(p)); |
|---|
| 2950 | + desc->args = strdup(skip_spaces(p)); |
|---|
| 2645 | 2951 | continue; |
|---|
| 2646 | 2952 | } |
|---|
| 2647 | 2953 | } |
|---|
| .. | .. |
|---|
| 2737 | 3043 | { |
|---|
| 2738 | 3044 | char filename[MAXPATHLEN], evname[128]; |
|---|
| 2739 | 3045 | char line[BUFSIZ], *p; |
|---|
| 2740 | | - struct perf_evsel *pos; |
|---|
| 3046 | + struct evsel *pos; |
|---|
| 2741 | 3047 | int match, len; |
|---|
| 2742 | 3048 | FILE *fp; |
|---|
| 2743 | 3049 | |
|---|
| .. | .. |
|---|
| 2748 | 3054 | return -1; |
|---|
| 2749 | 3055 | |
|---|
| 2750 | 3056 | while (fgets(line, sizeof(line), fp)) { |
|---|
| 2751 | | - p = ltrim(line); |
|---|
| 3057 | + p = skip_spaces(line); |
|---|
| 2752 | 3058 | if (*p == '#') |
|---|
| 2753 | 3059 | continue; |
|---|
| 2754 | 3060 | |
|---|
| .. | .. |
|---|
| 2758 | 3064 | break; |
|---|
| 2759 | 3065 | |
|---|
| 2760 | 3066 | p += 2; |
|---|
| 2761 | | - p = ltrim(p); |
|---|
| 3067 | + p = skip_spaces(p); |
|---|
| 2762 | 3068 | len = strcspn(p, " \t"); |
|---|
| 2763 | 3069 | if (!len) |
|---|
| 2764 | 3070 | break; |
|---|
| .. | .. |
|---|
| 2767 | 3073 | |
|---|
| 2768 | 3074 | match = 0; |
|---|
| 2769 | 3075 | evlist__for_each_entry(session->evlist, pos) { |
|---|
| 2770 | | - if (!strcmp(perf_evsel__name(pos), evname)) { |
|---|
| 3076 | + if (!strcmp(evsel__name(pos), evname)) { |
|---|
| 2771 | 3077 | match = 1; |
|---|
| 2772 | 3078 | break; |
|---|
| 2773 | 3079 | } |
|---|
| .. | .. |
|---|
| 2791 | 3097 | * will list all statically runnable scripts, select one, execute it and |
|---|
| 2792 | 3098 | * show the output in a perf browser. |
|---|
| 2793 | 3099 | */ |
|---|
| 2794 | | -int find_scripts(char **scripts_array, char **scripts_path_array) |
|---|
| 3100 | +int find_scripts(char **scripts_array, char **scripts_path_array, int num, |
|---|
| 3101 | + int pathlen) |
|---|
| 2795 | 3102 | { |
|---|
| 2796 | 3103 | struct dirent *script_dirent, *lang_dirent; |
|---|
| 2797 | 3104 | char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; |
|---|
| 2798 | 3105 | DIR *scripts_dir, *lang_dir; |
|---|
| 2799 | 3106 | struct perf_session *session; |
|---|
| 2800 | 3107 | struct perf_data data = { |
|---|
| 2801 | | - .file = { |
|---|
| 2802 | | - .path = input_name, |
|---|
| 2803 | | - }, |
|---|
| 2804 | | - .mode = PERF_DATA_MODE_READ, |
|---|
| 3108 | + .path = input_name, |
|---|
| 3109 | + .mode = PERF_DATA_MODE_READ, |
|---|
| 2805 | 3110 | }; |
|---|
| 2806 | 3111 | char *temp; |
|---|
| 2807 | 3112 | int i = 0; |
|---|
| 2808 | 3113 | |
|---|
| 2809 | 3114 | session = perf_session__new(&data, false, NULL); |
|---|
| 2810 | | - if (!session) |
|---|
| 2811 | | - return -1; |
|---|
| 3115 | + if (IS_ERR(session)) |
|---|
| 3116 | + return PTR_ERR(session); |
|---|
| 2812 | 3117 | |
|---|
| 2813 | 3118 | snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path()); |
|---|
| 2814 | 3119 | |
|---|
| .. | .. |
|---|
| 2838 | 3143 | /* Skip those real time scripts: xxxtop.p[yl] */ |
|---|
| 2839 | 3144 | if (strstr(script_dirent->d_name, "top.")) |
|---|
| 2840 | 3145 | continue; |
|---|
| 2841 | | - sprintf(scripts_path_array[i], "%s/%s", lang_path, |
|---|
| 3146 | + if (i >= num) |
|---|
| 3147 | + break; |
|---|
| 3148 | + snprintf(scripts_path_array[i], pathlen, "%s/%s", |
|---|
| 3149 | + lang_path, |
|---|
| 2842 | 3150 | script_dirent->d_name); |
|---|
| 2843 | 3151 | temp = strchr(script_dirent->d_name, '.'); |
|---|
| 2844 | 3152 | snprintf(scripts_array[i], |
|---|
| .. | .. |
|---|
| 2885 | 3193 | __script_root = get_script_root(script_dirent, suffix); |
|---|
| 2886 | 3194 | if (__script_root && !strcmp(script_root, __script_root)) { |
|---|
| 2887 | 3195 | free(__script_root); |
|---|
| 2888 | | - closedir(lang_dir); |
|---|
| 2889 | 3196 | closedir(scripts_dir); |
|---|
| 2890 | 3197 | scnprintf(script_path, MAXPATHLEN, "%s/%s", |
|---|
| 2891 | 3198 | lang_path, script_dirent->d_name); |
|---|
| 3199 | + closedir(lang_dir); |
|---|
| 2892 | 3200 | return strdup(script_path); |
|---|
| 2893 | 3201 | } |
|---|
| 2894 | 3202 | free(__script_root); |
|---|
| .. | .. |
|---|
| 2950 | 3258 | static void script__setup_sample_type(struct perf_script *script) |
|---|
| 2951 | 3259 | { |
|---|
| 2952 | 3260 | struct perf_session *session = script->session; |
|---|
| 2953 | | - u64 sample_type = perf_evlist__combined_sample_type(session->evlist); |
|---|
| 3261 | + u64 sample_type = evlist__combined_sample_type(session->evlist); |
|---|
| 2954 | 3262 | |
|---|
| 2955 | 3263 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) { |
|---|
| 2956 | 3264 | if ((sample_type & PERF_SAMPLE_REGS_USER) && |
|---|
| .. | .. |
|---|
| 2962 | 3270 | else |
|---|
| 2963 | 3271 | callchain_param.record_mode = CALLCHAIN_FP; |
|---|
| 2964 | 3272 | } |
|---|
| 3273 | + |
|---|
| 3274 | + if (script->stitch_lbr && (callchain_param.record_mode != CALLCHAIN_LBR)) { |
|---|
| 3275 | + pr_warning("Can't find LBR callchain. Switch off --stitch-lbr.\n" |
|---|
| 3276 | + "Please apply --call-graph lbr when recording.\n"); |
|---|
| 3277 | + script->stitch_lbr = false; |
|---|
| 3278 | + } |
|---|
| 2965 | 3279 | } |
|---|
| 2966 | 3280 | |
|---|
| 2967 | | -static int process_stat_round_event(struct perf_tool *tool __maybe_unused, |
|---|
| 2968 | | - union perf_event *event, |
|---|
| 2969 | | - struct perf_session *session) |
|---|
| 3281 | +static int process_stat_round_event(struct perf_session *session, |
|---|
| 3282 | + union perf_event *event) |
|---|
| 2970 | 3283 | { |
|---|
| 2971 | | - struct stat_round_event *round = &event->stat_round; |
|---|
| 2972 | | - struct perf_evsel *counter; |
|---|
| 3284 | + struct perf_record_stat_round *round = &event->stat_round; |
|---|
| 3285 | + struct evsel *counter; |
|---|
| 2973 | 3286 | |
|---|
| 2974 | 3287 | evlist__for_each_entry(session->evlist, counter) { |
|---|
| 2975 | 3288 | perf_stat_process_counter(&stat_config, counter); |
|---|
| .. | .. |
|---|
| 2980 | 3293 | return 0; |
|---|
| 2981 | 3294 | } |
|---|
| 2982 | 3295 | |
|---|
| 2983 | | -static int process_stat_config_event(struct perf_tool *tool __maybe_unused, |
|---|
| 2984 | | - union perf_event *event, |
|---|
| 2985 | | - struct perf_session *session __maybe_unused) |
|---|
| 3296 | +static int process_stat_config_event(struct perf_session *session __maybe_unused, |
|---|
| 3297 | + union perf_event *event) |
|---|
| 2986 | 3298 | { |
|---|
| 2987 | 3299 | perf_event__read_stat_config(&stat_config, &event->stat_config); |
|---|
| 2988 | 3300 | return 0; |
|---|
| .. | .. |
|---|
| 2990 | 3302 | |
|---|
| 2991 | 3303 | static int set_maps(struct perf_script *script) |
|---|
| 2992 | 3304 | { |
|---|
| 2993 | | - struct perf_evlist *evlist = script->session->evlist; |
|---|
| 3305 | + struct evlist *evlist = script->session->evlist; |
|---|
| 2994 | 3306 | |
|---|
| 2995 | 3307 | if (!script->cpus || !script->threads) |
|---|
| 2996 | 3308 | return 0; |
|---|
| .. | .. |
|---|
| 2998 | 3310 | if (WARN_ONCE(script->allocated, "stats double allocation\n")) |
|---|
| 2999 | 3311 | return -EINVAL; |
|---|
| 3000 | 3312 | |
|---|
| 3001 | | - perf_evlist__set_maps(evlist, script->cpus, script->threads); |
|---|
| 3313 | + perf_evlist__set_maps(&evlist->core, script->cpus, script->threads); |
|---|
| 3002 | 3314 | |
|---|
| 3003 | 3315 | if (perf_evlist__alloc_stats(evlist, true)) |
|---|
| 3004 | 3316 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 3008 | 3320 | } |
|---|
| 3009 | 3321 | |
|---|
| 3010 | 3322 | static |
|---|
| 3011 | | -int process_thread_map_event(struct perf_tool *tool, |
|---|
| 3012 | | - union perf_event *event, |
|---|
| 3013 | | - struct perf_session *session __maybe_unused) |
|---|
| 3323 | +int process_thread_map_event(struct perf_session *session, |
|---|
| 3324 | + union perf_event *event) |
|---|
| 3014 | 3325 | { |
|---|
| 3326 | + struct perf_tool *tool = session->tool; |
|---|
| 3015 | 3327 | struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 3016 | 3328 | |
|---|
| 3017 | 3329 | if (script->threads) { |
|---|
| .. | .. |
|---|
| 3027 | 3339 | } |
|---|
| 3028 | 3340 | |
|---|
| 3029 | 3341 | static |
|---|
| 3030 | | -int process_cpu_map_event(struct perf_tool *tool __maybe_unused, |
|---|
| 3031 | | - union perf_event *event, |
|---|
| 3032 | | - struct perf_session *session __maybe_unused) |
|---|
| 3342 | +int process_cpu_map_event(struct perf_session *session, |
|---|
| 3343 | + union perf_event *event) |
|---|
| 3033 | 3344 | { |
|---|
| 3345 | + struct perf_tool *tool = session->tool; |
|---|
| 3034 | 3346 | struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| 3035 | 3347 | |
|---|
| 3036 | 3348 | if (script->cpus) { |
|---|
| .. | .. |
|---|
| 3045 | 3357 | return set_maps(script); |
|---|
| 3046 | 3358 | } |
|---|
| 3047 | 3359 | |
|---|
| 3048 | | -static int process_feature_event(struct perf_tool *tool, |
|---|
| 3049 | | - union perf_event *event, |
|---|
| 3050 | | - struct perf_session *session) |
|---|
| 3360 | +static int process_feature_event(struct perf_session *session, |
|---|
| 3361 | + union perf_event *event) |
|---|
| 3051 | 3362 | { |
|---|
| 3052 | 3363 | if (event->feat.feat_id < HEADER_LAST_FEATURE) |
|---|
| 3053 | | - return perf_event__process_feature(tool, event, session); |
|---|
| 3364 | + return perf_event__process_feature(session, event); |
|---|
| 3054 | 3365 | return 0; |
|---|
| 3055 | 3366 | } |
|---|
| 3056 | 3367 | |
|---|
| 3057 | 3368 | #ifdef HAVE_AUXTRACE_SUPPORT |
|---|
| 3058 | | -static int perf_script__process_auxtrace_info(struct perf_tool *tool, |
|---|
| 3059 | | - union perf_event *event, |
|---|
| 3060 | | - struct perf_session *session) |
|---|
| 3369 | +static int perf_script__process_auxtrace_info(struct perf_session *session, |
|---|
| 3370 | + union perf_event *event) |
|---|
| 3061 | 3371 | { |
|---|
| 3062 | | - int ret = perf_event__process_auxtrace_info(tool, event, session); |
|---|
| 3372 | + struct perf_tool *tool = session->tool; |
|---|
| 3373 | + |
|---|
| 3374 | + int ret = perf_event__process_auxtrace_info(session, event); |
|---|
| 3063 | 3375 | |
|---|
| 3064 | 3376 | if (ret == 0) { |
|---|
| 3065 | 3377 | struct perf_script *script = container_of(tool, struct perf_script, tool); |
|---|
| .. | .. |
|---|
| 3073 | 3385 | #define perf_script__process_auxtrace_info 0 |
|---|
| 3074 | 3386 | #endif |
|---|
| 3075 | 3387 | |
|---|
| 3388 | +static int parse_insn_trace(const struct option *opt __maybe_unused, |
|---|
| 3389 | + const char *str __maybe_unused, |
|---|
| 3390 | + int unset __maybe_unused) |
|---|
| 3391 | +{ |
|---|
| 3392 | + parse_output_fields(NULL, "+insn,-event,-period", 0); |
|---|
| 3393 | + itrace_parse_synth_opts(opt, "i0ns", 0); |
|---|
| 3394 | + symbol_conf.nanosecs = true; |
|---|
| 3395 | + return 0; |
|---|
| 3396 | +} |
|---|
| 3397 | + |
|---|
| 3398 | +static int parse_xed(const struct option *opt __maybe_unused, |
|---|
| 3399 | + const char *str __maybe_unused, |
|---|
| 3400 | + int unset __maybe_unused) |
|---|
| 3401 | +{ |
|---|
| 3402 | + if (isatty(1)) |
|---|
| 3403 | + force_pager("xed -F insn: -A -64 | less"); |
|---|
| 3404 | + else |
|---|
| 3405 | + force_pager("xed -F insn: -A -64"); |
|---|
| 3406 | + return 0; |
|---|
| 3407 | +} |
|---|
| 3408 | + |
|---|
| 3409 | +static int parse_call_trace(const struct option *opt __maybe_unused, |
|---|
| 3410 | + const char *str __maybe_unused, |
|---|
| 3411 | + int unset __maybe_unused) |
|---|
| 3412 | +{ |
|---|
| 3413 | + parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent", 0); |
|---|
| 3414 | + itrace_parse_synth_opts(opt, "cewp", 0); |
|---|
| 3415 | + symbol_conf.nanosecs = true; |
|---|
| 3416 | + symbol_conf.pad_output_len_dso = 50; |
|---|
| 3417 | + return 0; |
|---|
| 3418 | +} |
|---|
| 3419 | + |
|---|
| 3420 | +static int parse_callret_trace(const struct option *opt __maybe_unused, |
|---|
| 3421 | + const char *str __maybe_unused, |
|---|
| 3422 | + int unset __maybe_unused) |
|---|
| 3423 | +{ |
|---|
| 3424 | + parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent,+flags", 0); |
|---|
| 3425 | + itrace_parse_synth_opts(opt, "crewp", 0); |
|---|
| 3426 | + symbol_conf.nanosecs = true; |
|---|
| 3427 | + return 0; |
|---|
| 3428 | +} |
|---|
| 3429 | + |
|---|
| 3076 | 3430 | int cmd_script(int argc, const char **argv) |
|---|
| 3077 | 3431 | { |
|---|
| 3078 | 3432 | bool show_full_info = false; |
|---|
| .. | .. |
|---|
| 3082 | 3436 | char *rec_script_path = NULL; |
|---|
| 3083 | 3437 | char *rep_script_path = NULL; |
|---|
| 3084 | 3438 | struct perf_session *session; |
|---|
| 3085 | | - struct itrace_synth_opts itrace_synth_opts = { .set = false, }; |
|---|
| 3439 | + struct itrace_synth_opts itrace_synth_opts = { |
|---|
| 3440 | + .set = false, |
|---|
| 3441 | + .default_no_sample = true, |
|---|
| 3442 | + }; |
|---|
| 3443 | + struct utsname uts; |
|---|
| 3086 | 3444 | char *script_path = NULL; |
|---|
| 3087 | 3445 | const char **__argv; |
|---|
| 3088 | 3446 | int i, j, err = 0; |
|---|
| .. | .. |
|---|
| 3093 | 3451 | .mmap2 = perf_event__process_mmap2, |
|---|
| 3094 | 3452 | .comm = perf_event__process_comm, |
|---|
| 3095 | 3453 | .namespaces = perf_event__process_namespaces, |
|---|
| 3454 | + .cgroup = perf_event__process_cgroup, |
|---|
| 3096 | 3455 | .exit = perf_event__process_exit, |
|---|
| 3097 | 3456 | .fork = perf_event__process_fork, |
|---|
| 3098 | 3457 | .attr = process_attr, |
|---|
| .. | .. |
|---|
| 3151 | 3510 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
|---|
| 3152 | 3511 | "addr,symoff,srcline,period,iregs,uregs,brstack," |
|---|
| 3153 | 3512 | "brstacksym,flags,bpf-output,brstackinsn,brstackoff," |
|---|
| 3154 | | - "callindent,insn,insnlen,synth,phys_addr,metric,misc", |
|---|
| 3513 | + "callindent,insn,insnlen,synth,phys_addr,metric,misc,ipc,tod", |
|---|
| 3155 | 3514 | parse_output_fields), |
|---|
| 3156 | 3515 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
|---|
| 3157 | 3516 | "system-wide collection from all CPUs"), |
|---|
| 3158 | 3517 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
|---|
| 3159 | 3518 | "only consider these symbols"), |
|---|
| 3519 | + OPT_CALLBACK_OPTARG(0, "insn-trace", &itrace_synth_opts, NULL, NULL, |
|---|
| 3520 | + "Decode instructions from itrace", parse_insn_trace), |
|---|
| 3521 | + OPT_CALLBACK_OPTARG(0, "xed", NULL, NULL, NULL, |
|---|
| 3522 | + "Run xed disassembler on output", parse_xed), |
|---|
| 3523 | + OPT_CALLBACK_OPTARG(0, "call-trace", &itrace_synth_opts, NULL, NULL, |
|---|
| 3524 | + "Decode calls from from itrace", parse_call_trace), |
|---|
| 3525 | + OPT_CALLBACK_OPTARG(0, "call-ret-trace", &itrace_synth_opts, NULL, NULL, |
|---|
| 3526 | + "Decode calls and returns from itrace", parse_callret_trace), |
|---|
| 3527 | + OPT_STRING(0, "graph-function", &symbol_conf.graph_function, "symbol[,symbol...]", |
|---|
| 3528 | + "Only print symbols and callees with --call-trace/--call-ret-trace"), |
|---|
| 3160 | 3529 | OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]", |
|---|
| 3161 | 3530 | "Stop display of callgraph at these symbols"), |
|---|
| 3162 | 3531 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
|---|
| .. | .. |
|---|
| 3170 | 3539 | "Set the maximum stack depth when parsing the callchain, " |
|---|
| 3171 | 3540 | "anything beyond the specified depth will be ignored. " |
|---|
| 3172 | 3541 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), |
|---|
| 3542 | + OPT_BOOLEAN(0, "reltime", &reltime, "Show time stamps relative to start"), |
|---|
| 3543 | + OPT_BOOLEAN(0, "deltatime", &deltatime, "Show time stamps relative to previous event"), |
|---|
| 3173 | 3544 | OPT_BOOLEAN('I', "show-info", &show_full_info, |
|---|
| 3174 | 3545 | "display extended information from perf.data file"), |
|---|
| 3175 | 3546 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, |
|---|
| .. | .. |
|---|
| 3182 | 3553 | "Show context switch events (if recorded)"), |
|---|
| 3183 | 3554 | OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events, |
|---|
| 3184 | 3555 | "Show namespace events (if recorded)"), |
|---|
| 3556 | + OPT_BOOLEAN('\0', "show-cgroup-events", &script.show_cgroup_events, |
|---|
| 3557 | + "Show cgroup events (if recorded)"), |
|---|
| 3185 | 3558 | OPT_BOOLEAN('\0', "show-lost-events", &script.show_lost_events, |
|---|
| 3186 | 3559 | "Show lost events (if recorded)"), |
|---|
| 3187 | 3560 | OPT_BOOLEAN('\0', "show-round-events", &script.show_round_events, |
|---|
| 3188 | 3561 | "Show round events (if recorded)"), |
|---|
| 3562 | + OPT_BOOLEAN('\0', "show-bpf-events", &script.show_bpf_events, |
|---|
| 3563 | + "Show bpf related events (if recorded)"), |
|---|
| 3564 | + OPT_BOOLEAN('\0', "show-text-poke-events", &script.show_text_poke_events, |
|---|
| 3565 | + "Show text poke related events (if recorded)"), |
|---|
| 3189 | 3566 | OPT_BOOLEAN('\0', "per-event-dump", &script.per_event_dump, |
|---|
| 3190 | 3567 | "Dump trace output to files named by the monitored events"), |
|---|
| 3191 | 3568 | OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), |
|---|
| 3192 | 3569 | OPT_INTEGER(0, "max-blocks", &max_blocks, |
|---|
| 3193 | 3570 | "Maximum number of code blocks to dump with brstackinsn"), |
|---|
| 3194 | | - OPT_BOOLEAN(0, "ns", &nanosecs, |
|---|
| 3571 | + OPT_BOOLEAN(0, "ns", &symbol_conf.nanosecs, |
|---|
| 3195 | 3572 | "Use 9 decimal places when displaying time"), |
|---|
| 3196 | 3573 | OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", |
|---|
| 3197 | | - "Instruction Tracing options", |
|---|
| 3574 | + "Instruction Tracing options\n" ITRACE_HELP, |
|---|
| 3198 | 3575 | itrace_parse_synth_opts), |
|---|
| 3199 | 3576 | OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename, |
|---|
| 3200 | 3577 | "Show full source file name path for source lines"), |
|---|
| .. | .. |
|---|
| 3206 | 3583 | "Time span of interest (start,stop)"), |
|---|
| 3207 | 3584 | OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, |
|---|
| 3208 | 3585 | "Show inline function"), |
|---|
| 3586 | + OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", |
|---|
| 3587 | + "guest mount directory under which every guest os" |
|---|
| 3588 | + " instance has a subdir"), |
|---|
| 3589 | + OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, |
|---|
| 3590 | + "file", "file saving guest os vmlinux"), |
|---|
| 3591 | + OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, |
|---|
| 3592 | + "file", "file saving guest os /proc/kallsyms"), |
|---|
| 3593 | + OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, |
|---|
| 3594 | + "file", "file saving guest os /proc/modules"), |
|---|
| 3595 | + OPT_BOOLEAN('\0', "stitch-lbr", &script.stitch_lbr, |
|---|
| 3596 | + "Enable LBR callgraph stitching approach"), |
|---|
| 3597 | + OPTS_EVSWITCH(&script.evswitch), |
|---|
| 3209 | 3598 | OPT_END() |
|---|
| 3210 | 3599 | }; |
|---|
| 3211 | 3600 | const char * const script_subcommands[] = { "record", "report", NULL }; |
|---|
| .. | .. |
|---|
| 3225 | 3614 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, |
|---|
| 3226 | 3615 | PARSE_OPT_STOP_AT_NON_OPTION); |
|---|
| 3227 | 3616 | |
|---|
| 3228 | | - data.file.path = input_name; |
|---|
| 3229 | | - data.force = symbol_conf.force; |
|---|
| 3617 | + if (symbol_conf.guestmount || |
|---|
| 3618 | + symbol_conf.default_guest_vmlinux_name || |
|---|
| 3619 | + symbol_conf.default_guest_kallsyms || |
|---|
| 3620 | + symbol_conf.default_guest_modules) { |
|---|
| 3621 | + /* |
|---|
| 3622 | + * Enable guest sample processing. |
|---|
| 3623 | + */ |
|---|
| 3624 | + perf_guest = true; |
|---|
| 3625 | + } |
|---|
| 3626 | + |
|---|
| 3627 | + data.path = input_name; |
|---|
| 3628 | + data.force = symbol_conf.force; |
|---|
| 3230 | 3629 | |
|---|
| 3231 | 3630 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { |
|---|
| 3232 | 3631 | rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); |
|---|
| .. | .. |
|---|
| 3244 | 3643 | } |
|---|
| 3245 | 3644 | } |
|---|
| 3246 | 3645 | |
|---|
| 3247 | | - if (itrace_synth_opts.callchain && |
|---|
| 3646 | + if (reltime && deltatime) { |
|---|
| 3647 | + fprintf(stderr, |
|---|
| 3648 | + "reltime and deltatime - the two don't get along well. " |
|---|
| 3649 | + "Please limit to --reltime or --deltatime.\n"); |
|---|
| 3650 | + return -1; |
|---|
| 3651 | + } |
|---|
| 3652 | + |
|---|
| 3653 | + if ((itrace_synth_opts.callchain || itrace_synth_opts.add_callchain) && |
|---|
| 3248 | 3654 | itrace_synth_opts.callchain_sz > scripting_max_stack) |
|---|
| 3249 | 3655 | scripting_max_stack = itrace_synth_opts.callchain_sz; |
|---|
| 3250 | 3656 | |
|---|
| .. | .. |
|---|
| 3390 | 3796 | exit(-1); |
|---|
| 3391 | 3797 | } |
|---|
| 3392 | 3798 | |
|---|
| 3393 | | - if (!script_name) |
|---|
| 3799 | + if (!script_name) { |
|---|
| 3394 | 3800 | setup_pager(); |
|---|
| 3801 | + use_browser = 0; |
|---|
| 3802 | + } |
|---|
| 3395 | 3803 | |
|---|
| 3396 | 3804 | session = perf_session__new(&data, false, &script.tool); |
|---|
| 3397 | | - if (session == NULL) |
|---|
| 3398 | | - return -1; |
|---|
| 3805 | + if (IS_ERR(session)) |
|---|
| 3806 | + return PTR_ERR(session); |
|---|
| 3399 | 3807 | |
|---|
| 3400 | 3808 | if (header || header_only) { |
|---|
| 3401 | 3809 | script.tool.show_feat_hdr = SHOW_FEAT_HEADER; |
|---|
| .. | .. |
|---|
| 3409 | 3817 | if (symbol__init(&session->header.env) < 0) |
|---|
| 3410 | 3818 | goto out_delete; |
|---|
| 3411 | 3819 | |
|---|
| 3820 | + uname(&uts); |
|---|
| 3821 | + if (data.is_pipe) { /* Assume pipe_mode indicates native_arch */ |
|---|
| 3822 | + native_arch = true; |
|---|
| 3823 | + } else if (session->header.env.arch) { |
|---|
| 3824 | + if (!strcmp(uts.machine, session->header.env.arch)) |
|---|
| 3825 | + native_arch = true; |
|---|
| 3826 | + else if (!strcmp(uts.machine, "x86_64") && |
|---|
| 3827 | + !strcmp(session->header.env.arch, "i386")) |
|---|
| 3828 | + native_arch = true; |
|---|
| 3829 | + } |
|---|
| 3830 | + |
|---|
| 3412 | 3831 | script.session = session; |
|---|
| 3413 | 3832 | script__setup_sample_type(&script); |
|---|
| 3414 | 3833 | |
|---|
| 3415 | | - if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) |
|---|
| 3834 | + if ((output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) || |
|---|
| 3835 | + symbol_conf.graph_function) |
|---|
| 3416 | 3836 | itrace_synth_opts.thread_stack = true; |
|---|
| 3417 | 3837 | |
|---|
| 3418 | 3838 | session->itrace_synth_opts = &itrace_synth_opts; |
|---|
| .. | .. |
|---|
| 3449 | 3869 | goto out_delete; |
|---|
| 3450 | 3870 | } |
|---|
| 3451 | 3871 | |
|---|
| 3452 | | - input = open(data.file.path, O_RDONLY); /* input_name */ |
|---|
| 3872 | + input = open(data.path, O_RDONLY); /* input_name */ |
|---|
| 3453 | 3873 | if (input < 0) { |
|---|
| 3454 | 3874 | err = -errno; |
|---|
| 3455 | 3875 | perror("failed to open file"); |
|---|
| .. | .. |
|---|
| 3492 | 3912 | if (err < 0) |
|---|
| 3493 | 3913 | goto out_delete; |
|---|
| 3494 | 3914 | |
|---|
| 3495 | | - script.ptime_range = perf_time__range_alloc(script.time_str, |
|---|
| 3496 | | - &script.range_size); |
|---|
| 3497 | | - if (!script.ptime_range) { |
|---|
| 3498 | | - err = -ENOMEM; |
|---|
| 3915 | + if (script.time_str) { |
|---|
| 3916 | + err = perf_time__parse_for_ranges_reltime(script.time_str, session, |
|---|
| 3917 | + &script.ptime_range, |
|---|
| 3918 | + &script.range_size, |
|---|
| 3919 | + &script.range_num, |
|---|
| 3920 | + reltime); |
|---|
| 3921 | + if (err < 0) |
|---|
| 3922 | + goto out_delete; |
|---|
| 3923 | + |
|---|
| 3924 | + itrace_synth_opts__set_time_range(&itrace_synth_opts, |
|---|
| 3925 | + script.ptime_range, |
|---|
| 3926 | + script.range_num); |
|---|
| 3927 | + } |
|---|
| 3928 | + |
|---|
| 3929 | + err = evswitch__init(&script.evswitch, session->evlist, stderr); |
|---|
| 3930 | + if (err) |
|---|
| 3499 | 3931 | goto out_delete; |
|---|
| 3500 | | - } |
|---|
| 3501 | 3932 | |
|---|
| 3502 | | - /* needs to be parsed after looking up reference time */ |
|---|
| 3503 | | - if (perf_time__parse_str(script.ptime_range, script.time_str) != 0) { |
|---|
| 3504 | | - if (session->evlist->first_sample_time == 0 && |
|---|
| 3505 | | - session->evlist->last_sample_time == 0) { |
|---|
| 3506 | | - pr_err("HINT: no first/last sample time found in perf data.\n" |
|---|
| 3507 | | - "Please use latest perf binary to execute 'perf record'\n" |
|---|
| 3508 | | - "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n"); |
|---|
| 3509 | | - err = -EINVAL; |
|---|
| 3510 | | - goto out_delete; |
|---|
| 3511 | | - } |
|---|
| 3512 | | - |
|---|
| 3513 | | - script.range_num = perf_time__percent_parse_str( |
|---|
| 3514 | | - script.ptime_range, script.range_size, |
|---|
| 3515 | | - script.time_str, |
|---|
| 3516 | | - session->evlist->first_sample_time, |
|---|
| 3517 | | - session->evlist->last_sample_time); |
|---|
| 3518 | | - |
|---|
| 3519 | | - if (script.range_num < 0) { |
|---|
| 3520 | | - pr_err("Invalid time string\n"); |
|---|
| 3521 | | - err = -EINVAL; |
|---|
| 3522 | | - goto out_delete; |
|---|
| 3523 | | - } |
|---|
| 3524 | | - } else { |
|---|
| 3525 | | - script.range_num = 1; |
|---|
| 3526 | | - } |
|---|
| 3933 | + if (zstd_init(&(session->zstd_data), 0) < 0) |
|---|
| 3934 | + pr_warning("Decompression initialization failed. Reported data may be incomplete.\n"); |
|---|
| 3527 | 3935 | |
|---|
| 3528 | 3936 | err = __cmd_script(&script); |
|---|
| 3529 | 3937 | |
|---|
| 3530 | 3938 | flush_scripting(); |
|---|
| 3531 | 3939 | |
|---|
| 3532 | 3940 | out_delete: |
|---|
| 3533 | | - zfree(&script.ptime_range); |
|---|
| 3941 | + if (script.ptime_range) { |
|---|
| 3942 | + itrace_synth_opts__clear_time_range(&itrace_synth_opts); |
|---|
| 3943 | + zfree(&script.ptime_range); |
|---|
| 3944 | + } |
|---|
| 3534 | 3945 | |
|---|
| 3535 | 3946 | perf_evlist__free_stats(session->evlist); |
|---|
| 3536 | 3947 | perf_session__delete(session); |
|---|
| 3948 | + perf_script__exit(&script); |
|---|
| 3537 | 3949 | |
|---|
| 3538 | 3950 | if (script_started) |
|---|
| 3539 | 3951 | cleanup_scripting(); |
|---|