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