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