diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2018-08-20 12:05:17 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2018-08-20 12:05:17 -0400 |
| commit | 415d2b3392d7a80903e0f97f051201aa02bf20e9 (patch) | |
| tree | 47492d2386a0e7f00ef645313cb44ae4960b7e7e /tools/perf | |
| parent | 4f65245f2d178b9cba48350620d76faa4a098841 (diff) | |
| parent | b8e759b8f6dab1c473c30ac12709095d0b81078e (diff) | |
Merge branch 'for-4.19/cougar' into for-linus
New device support for hid-cougar
Diffstat (limited to 'tools/perf')
67 files changed, 1245 insertions, 477 deletions
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 2549c34a7895..11300dbe35c5 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt | |||
| @@ -124,7 +124,11 @@ The available PMUs and their raw parameters can be listed with | |||
| 124 | For example the raw event "LSD.UOPS" core pmu event above could | 124 | For example the raw event "LSD.UOPS" core pmu event above could |
| 125 | be specified as | 125 | be specified as |
| 126 | 126 | ||
| 127 | perf stat -e cpu/event=0xa8,umask=0x1,name=LSD.UOPS_CYCLES,cmask=1/ ... | 127 | perf stat -e cpu/event=0xa8,umask=0x1,name=LSD.UOPS_CYCLES,cmask=0x1/ ... |
| 128 | |||
| 129 | or using extended name syntax | ||
| 130 | |||
| 131 | perf stat -e cpu/event=0xa8,umask=0x1,cmask=0x1,name=\'LSD.UOPS_CYCLES:cmask=0x1\'/ ... | ||
| 128 | 132 | ||
| 129 | PER SOCKET PMUS | 133 | PER SOCKET PMUS |
| 130 | --------------- | 134 | --------------- |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index cc37b3a4be76..04168da4268e 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
| @@ -57,6 +57,9 @@ OPTIONS | |||
| 57 | FP mode, "dwarf" for DWARF mode, "lbr" for LBR mode and | 57 | FP mode, "dwarf" for DWARF mode, "lbr" for LBR mode and |
| 58 | "no" for disable callgraph. | 58 | "no" for disable callgraph. |
| 59 | - 'stack-size': user stack size for dwarf mode | 59 | - 'stack-size': user stack size for dwarf mode |
| 60 | - 'name' : User defined event name. Single quotes (') may be used to | ||
| 61 | escape symbols in the name from parsing by shell and tool | ||
| 62 | like this: name=\'CPU_CLK_UNHALTED.THREAD:cmask=0x1\'. | ||
| 60 | 63 | ||
| 61 | See the linkperf:perf-list[1] man page for more parameters. | 64 | See the linkperf:perf-list[1] man page for more parameters. |
| 62 | 65 | ||
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt index 51ec2d20068a..0fb9eda3cbca 100644 --- a/tools/perf/Documentation/perf-script-python.txt +++ b/tools/perf/Documentation/perf-script-python.txt | |||
| @@ -610,6 +610,32 @@ Various utility functions for use with perf script: | |||
| 610 | nsecs_str(nsecs) - returns printable string in the form secs.nsecs | 610 | nsecs_str(nsecs) - returns printable string in the form secs.nsecs |
| 611 | avg(total, n) - returns average given a sum and a total number of values | 611 | avg(total, n) - returns average given a sum and a total number of values |
| 612 | 612 | ||
| 613 | SUPPORTED FIELDS | ||
| 614 | ---------------- | ||
| 615 | |||
| 616 | Currently supported fields: | ||
| 617 | |||
| 618 | ev_name, comm, pid, tid, cpu, ip, time, period, phys_addr, addr, | ||
| 619 | symbol, dso, time_enabled, time_running, values, callchain, | ||
| 620 | brstack, brstacksym, datasrc, datasrc_decode, iregs, uregs, | ||
| 621 | weight, transaction, raw_buf, attr. | ||
| 622 | |||
| 623 | Some fields have sub items: | ||
| 624 | |||
| 625 | brstack: | ||
| 626 | from, to, from_dsoname, to_dsoname, mispred, | ||
| 627 | predicted, in_tx, abort, cycles. | ||
| 628 | |||
| 629 | brstacksym: | ||
| 630 | items: from, to, pred, in_tx, abort (converted string) | ||
| 631 | |||
| 632 | For example, | ||
| 633 | We can use this code to print brstack "from", "to", "cycles". | ||
| 634 | |||
| 635 | if 'brstack' in dict: | ||
| 636 | for entry in dict['brstack']: | ||
| 637 | print "from %s, to %s, cycles %s" % (entry["from"], entry["to"], entry["cycles"]) | ||
| 638 | |||
| 613 | SEE ALSO | 639 | SEE ALSO |
| 614 | -------- | 640 | -------- |
| 615 | linkperf:perf-script[1] | 641 | linkperf:perf-script[1] |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 3a822f308e6d..b10a90b6a718 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
| @@ -178,6 +178,9 @@ Print count deltas for fixed number of times. | |||
| 178 | This option should be used together with "-I" option. | 178 | This option should be used together with "-I" option. |
| 179 | example: 'perf stat -I 1000 --interval-count 2 -e cycles -a' | 179 | example: 'perf stat -I 1000 --interval-count 2 -e cycles -a' |
| 180 | 180 | ||
| 181 | --interval-clear:: | ||
| 182 | Clear the screen before next interval. | ||
| 183 | |||
| 181 | --timeout msecs:: | 184 | --timeout msecs:: |
| 182 | Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms). | 185 | Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms). |
| 183 | This option is not supported with the "-I" option. | 186 | This option is not supported with the "-I" option. |
| @@ -310,20 +313,38 @@ Users who wants to get the actual value can apply --no-metric-only. | |||
| 310 | EXAMPLES | 313 | EXAMPLES |
| 311 | -------- | 314 | -------- |
| 312 | 315 | ||
| 313 | $ perf stat -- make -j | 316 | $ perf stat -- make |
| 317 | |||
| 318 | Performance counter stats for 'make': | ||
| 319 | |||
| 320 | 83723.452481 task-clock:u (msec) # 1.004 CPUs utilized | ||
| 321 | 0 context-switches:u # 0.000 K/sec | ||
| 322 | 0 cpu-migrations:u # 0.000 K/sec | ||
| 323 | 3,228,188 page-faults:u # 0.039 M/sec | ||
| 324 | 229,570,665,834 cycles:u # 2.742 GHz | ||
| 325 | 313,163,853,778 instructions:u # 1.36 insn per cycle | ||
| 326 | 69,704,684,856 branches:u # 832.559 M/sec | ||
| 327 | 2,078,861,393 branch-misses:u # 2.98% of all branches | ||
| 328 | |||
| 329 | 83.409183620 seconds time elapsed | ||
| 330 | |||
| 331 | 74.684747000 seconds user | ||
| 332 | 8.739217000 seconds sys | ||
| 333 | |||
| 334 | TIMINGS | ||
| 335 | ------- | ||
| 336 | As displayed in the example above we can display 3 types of timings. | ||
| 337 | We always display the time the counters were enabled/alive: | ||
| 338 | |||
| 339 | 83.409183620 seconds time elapsed | ||
| 314 | 340 | ||
| 315 | Performance counter stats for 'make -j': | 341 | For workload sessions we also display time the workloads spent in |
| 342 | user/system lands: | ||
| 316 | 343 | ||
| 317 | 8117.370256 task clock ticks # 11.281 CPU utilization factor | 344 | 74.684747000 seconds user |
| 318 | 678 context switches # 0.000 M/sec | 345 | 8.739217000 seconds sys |
| 319 | 133 CPU migrations # 0.000 M/sec | ||
| 320 | 235724 pagefaults # 0.029 M/sec | ||
| 321 | 24821162526 CPU cycles # 3057.784 M/sec | ||
| 322 | 18687303457 instructions # 2302.138 M/sec | ||
| 323 | 172158895 cache references # 21.209 M/sec | ||
| 324 | 27075259 cache misses # 3.335 M/sec | ||
| 325 | 346 | ||
| 326 | Wall-clock time elapsed: 719.554352 msecs | 347 | Those times are the very same as displayed by the 'time' tool. |
| 327 | 348 | ||
| 328 | CSV FORMAT | 349 | CSV FORMAT |
| 329 | ---------- | 350 | ---------- |
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index c6f373508a4f..82657c01a3b8 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c | |||
| @@ -189,7 +189,7 @@ out_error: | |||
| 189 | return -1; | 189 | return -1; |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | int perf_env__lookup_objdump(struct perf_env *env) | 192 | int perf_env__lookup_objdump(struct perf_env *env, const char **path) |
| 193 | { | 193 | { |
| 194 | /* | 194 | /* |
| 195 | * For live mode, env->arch will be NULL and we can use | 195 | * For live mode, env->arch will be NULL and we can use |
| @@ -198,5 +198,5 @@ int perf_env__lookup_objdump(struct perf_env *env) | |||
| 198 | if (env->arch == NULL) | 198 | if (env->arch == NULL) |
| 199 | return 0; | 199 | return 0; |
| 200 | 200 | ||
| 201 | return perf_env__lookup_binutils_path(env, "objdump", &objdump_path); | 201 | return perf_env__lookup_binutils_path(env, "objdump", path); |
| 202 | } | 202 | } |
diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h index 2d875baa92e6..2167001b18c5 100644 --- a/tools/perf/arch/common.h +++ b/tools/perf/arch/common.h | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #include "../util/env.h" | 5 | #include "../util/env.h" |
| 6 | 6 | ||
| 7 | extern const char *objdump_path; | 7 | int perf_env__lookup_objdump(struct perf_env *env, const char **path); |
| 8 | |||
| 9 | int perf_env__lookup_objdump(struct perf_env *env); | ||
| 10 | 8 | ||
| 11 | #endif /* ARCH_PERF_COMMON_H */ | 9 | #endif /* ARCH_PERF_COMMON_H */ |
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index 3598b8b75d27..ef5d59a5742e 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c | |||
| @@ -243,7 +243,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) | |||
| 243 | u64 ip; | 243 | u64 ip; |
| 244 | u64 skip_slot = -1; | 244 | u64 skip_slot = -1; |
| 245 | 245 | ||
| 246 | if (chain->nr < 3) | 246 | if (!chain || chain->nr < 3) |
| 247 | return skip_slot; | 247 | return skip_slot; |
| 248 | 248 | ||
| 249 | ip = chain->ips[2]; | 249 | ip = chain->ips[2]; |
diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl index 4dfe42666d0c..f0b1709a5ffb 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | |||
| @@ -341,6 +341,8 @@ | |||
| 341 | 330 common pkey_alloc __x64_sys_pkey_alloc | 341 | 330 common pkey_alloc __x64_sys_pkey_alloc |
| 342 | 331 common pkey_free __x64_sys_pkey_free | 342 | 331 common pkey_free __x64_sys_pkey_free |
| 343 | 332 common statx __x64_sys_statx | 343 | 332 common statx __x64_sys_statx |
| 344 | 333 common io_pgetevents __x64_sys_io_pgetevents | ||
| 345 | 334 common rseq __x64_sys_rseq | ||
| 344 | 346 | ||
| 345 | # | 347 | # |
| 346 | # x32-specific system call numbers start at 512 to avoid cache impact | 348 | # x32-specific system call numbers start at 512 to avoid cache impact |
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 63eb49082774..44195514b19e 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c | |||
| @@ -1098,7 +1098,7 @@ static void *worker_thread(void *__tdata) | |||
| 1098 | u8 *global_data; | 1098 | u8 *global_data; |
| 1099 | u8 *process_data; | 1099 | u8 *process_data; |
| 1100 | u8 *thread_data; | 1100 | u8 *thread_data; |
| 1101 | u64 bytes_done; | 1101 | u64 bytes_done, secs; |
| 1102 | long work_done; | 1102 | long work_done; |
| 1103 | u32 l; | 1103 | u32 l; |
| 1104 | struct rusage rusage; | 1104 | struct rusage rusage; |
| @@ -1254,7 +1254,8 @@ static void *worker_thread(void *__tdata) | |||
| 1254 | timersub(&stop, &start0, &diff); | 1254 | timersub(&stop, &start0, &diff); |
| 1255 | td->runtime_ns = diff.tv_sec * NSEC_PER_SEC; | 1255 | td->runtime_ns = diff.tv_sec * NSEC_PER_SEC; |
| 1256 | td->runtime_ns += diff.tv_usec * NSEC_PER_USEC; | 1256 | td->runtime_ns += diff.tv_usec * NSEC_PER_USEC; |
| 1257 | td->speed_gbs = bytes_done / (td->runtime_ns / NSEC_PER_SEC) / 1e9; | 1257 | secs = td->runtime_ns / NSEC_PER_SEC; |
| 1258 | td->speed_gbs = secs ? bytes_done / secs / 1e9 : 0; | ||
| 1258 | 1259 | ||
| 1259 | getrusage(RUSAGE_THREAD, &rusage); | 1260 | getrusage(RUSAGE_THREAD, &rusage); |
| 1260 | td->system_time_ns = rusage.ru_stime.tv_sec * NSEC_PER_SEC; | 1261 | td->system_time_ns = rusage.ru_stime.tv_sec * NSEC_PER_SEC; |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index da5704240239..8180319285af 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -40,9 +40,8 @@ | |||
| 40 | struct perf_annotate { | 40 | struct perf_annotate { |
| 41 | struct perf_tool tool; | 41 | struct perf_tool tool; |
| 42 | struct perf_session *session; | 42 | struct perf_session *session; |
| 43 | struct annotation_options opts; | ||
| 43 | bool use_tui, use_stdio, use_stdio2, use_gtk; | 44 | bool use_tui, use_stdio, use_stdio2, use_gtk; |
| 44 | bool full_paths; | ||
| 45 | bool print_line; | ||
| 46 | bool skip_missing; | 45 | bool skip_missing; |
| 47 | bool has_br_stack; | 46 | bool has_br_stack; |
| 48 | bool group_set; | 47 | bool group_set; |
| @@ -162,12 +161,12 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, | |||
| 162 | hist__account_cycles(sample->branch_stack, al, sample, false); | 161 | hist__account_cycles(sample->branch_stack, al, sample, false); |
| 163 | 162 | ||
| 164 | bi = he->branch_info; | 163 | bi = he->branch_info; |
| 165 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); | 164 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); |
| 166 | 165 | ||
| 167 | if (err) | 166 | if (err) |
| 168 | goto out; | 167 | goto out; |
| 169 | 168 | ||
| 170 | err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); | 169 | err = addr_map_symbol__inc_samples(&bi->to, sample, evsel); |
| 171 | 170 | ||
| 172 | out: | 171 | out: |
| 173 | return err; | 172 | return err; |
| @@ -249,7 +248,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
| 249 | if (he == NULL) | 248 | if (he == NULL) |
| 250 | return -ENOMEM; | 249 | return -ENOMEM; |
| 251 | 250 | ||
| 252 | ret = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); | 251 | ret = hist_entry__inc_addr_samples(he, sample, evsel, al->addr); |
| 253 | hists__inc_nr_samples(hists, true); | 252 | hists__inc_nr_samples(hists, true); |
| 254 | return ret; | 253 | return ret; |
| 255 | } | 254 | } |
| @@ -284,15 +283,23 @@ out_put: | |||
| 284 | return ret; | 283 | return ret; |
| 285 | } | 284 | } |
| 286 | 285 | ||
| 286 | static int process_feature_event(struct perf_tool *tool, | ||
| 287 | union perf_event *event, | ||
| 288 | struct perf_session *session) | ||
| 289 | { | ||
| 290 | if (event->feat.feat_id < HEADER_LAST_FEATURE) | ||
| 291 | return perf_event__process_feature(tool, event, session); | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 287 | static int hist_entry__tty_annotate(struct hist_entry *he, | 295 | static int hist_entry__tty_annotate(struct hist_entry *he, |
| 288 | struct perf_evsel *evsel, | 296 | struct perf_evsel *evsel, |
| 289 | struct perf_annotate *ann) | 297 | struct perf_annotate *ann) |
| 290 | { | 298 | { |
| 291 | if (!ann->use_stdio2) | 299 | if (!ann->use_stdio2) |
| 292 | return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, | 300 | return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, &ann->opts); |
| 293 | ann->print_line, ann->full_paths, 0, 0); | 301 | |
| 294 | return symbol__tty_annotate2(he->ms.sym, he->ms.map, evsel, | 302 | return symbol__tty_annotate2(he->ms.sym, he->ms.map, evsel, &ann->opts); |
| 295 | ann->print_line, ann->full_paths); | ||
| 296 | } | 303 | } |
| 297 | 304 | ||
| 298 | static void hists__find_annotations(struct hists *hists, | 305 | static void hists__find_annotations(struct hists *hists, |
| @@ -343,7 +350,7 @@ find_next: | |||
| 343 | /* skip missing symbols */ | 350 | /* skip missing symbols */ |
| 344 | nd = rb_next(nd); | 351 | nd = rb_next(nd); |
| 345 | } else if (use_browser == 1) { | 352 | } else if (use_browser == 1) { |
| 346 | key = hist_entry__tui_annotate(he, evsel, NULL); | 353 | key = hist_entry__tui_annotate(he, evsel, NULL, &ann->opts); |
| 347 | 354 | ||
| 348 | switch (key) { | 355 | switch (key) { |
| 349 | case -1: | 356 | case -1: |
| @@ -390,8 +397,9 @@ static int __cmd_annotate(struct perf_annotate *ann) | |||
| 390 | goto out; | 397 | goto out; |
| 391 | } | 398 | } |
| 392 | 399 | ||
| 393 | if (!objdump_path) { | 400 | if (!ann->opts.objdump_path) { |
| 394 | ret = perf_env__lookup_objdump(&session->header.env); | 401 | ret = perf_env__lookup_objdump(&session->header.env, |
| 402 | &ann->opts.objdump_path); | ||
| 395 | if (ret) | 403 | if (ret) |
| 396 | goto out; | 404 | goto out; |
| 397 | } | 405 | } |
| @@ -472,10 +480,11 @@ int cmd_annotate(int argc, const char **argv) | |||
| 472 | .attr = perf_event__process_attr, | 480 | .attr = perf_event__process_attr, |
| 473 | .build_id = perf_event__process_build_id, | 481 | .build_id = perf_event__process_build_id, |
| 474 | .tracing_data = perf_event__process_tracing_data, | 482 | .tracing_data = perf_event__process_tracing_data, |
| 475 | .feature = perf_event__process_feature, | 483 | .feature = process_feature_event, |
| 476 | .ordered_events = true, | 484 | .ordered_events = true, |
| 477 | .ordering_requires_timestamps = true, | 485 | .ordering_requires_timestamps = true, |
| 478 | }, | 486 | }, |
| 487 | .opts = annotation__default_options, | ||
| 479 | }; | 488 | }; |
| 480 | struct perf_data data = { | 489 | struct perf_data data = { |
| 481 | .mode = PERF_DATA_MODE_READ, | 490 | .mode = PERF_DATA_MODE_READ, |
| @@ -503,9 +512,9 @@ int cmd_annotate(int argc, const char **argv) | |||
| 503 | "file", "vmlinux pathname"), | 512 | "file", "vmlinux pathname"), |
| 504 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, | 513 | OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, |
| 505 | "load module symbols - WARNING: use only with -k and LIVE kernel"), | 514 | "load module symbols - WARNING: use only with -k and LIVE kernel"), |
| 506 | OPT_BOOLEAN('l', "print-line", &annotate.print_line, | 515 | OPT_BOOLEAN('l', "print-line", &annotate.opts.print_lines, |
| 507 | "print matching source lines (may be slow)"), | 516 | "print matching source lines (may be slow)"), |
| 508 | OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, | 517 | OPT_BOOLEAN('P', "full-paths", &annotate.opts.full_path, |
| 509 | "Don't shorten the displayed pathnames"), | 518 | "Don't shorten the displayed pathnames"), |
| 510 | OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, | 519 | OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, |
| 511 | "Skip symbols that cannot be annotated"), | 520 | "Skip symbols that cannot be annotated"), |
| @@ -516,13 +525,13 @@ int cmd_annotate(int argc, const char **argv) | |||
| 516 | OPT_CALLBACK(0, "symfs", NULL, "directory", | 525 | OPT_CALLBACK(0, "symfs", NULL, "directory", |
| 517 | "Look for files with symbols relative to this directory", | 526 | "Look for files with symbols relative to this directory", |
| 518 | symbol__config_symfs), | 527 | symbol__config_symfs), |
| 519 | OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, | 528 | OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src, |
| 520 | "Interleave source code with assembly code (default)"), | 529 | "Interleave source code with assembly code (default)"), |
| 521 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | 530 | OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw, |
| 522 | "Display raw encoding of assembly instructions (default)"), | 531 | "Display raw encoding of assembly instructions (default)"), |
| 523 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 532 | OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style", |
| 524 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 533 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
| 525 | OPT_STRING(0, "objdump", &objdump_path, "path", | 534 | OPT_STRING(0, "objdump", &annotate.opts.objdump_path, "path", |
| 526 | "objdump binary to use for disassembly and annotations"), | 535 | "objdump binary to use for disassembly and annotations"), |
| 527 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, | 536 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, |
| 528 | "Show event group information together"), | 537 | "Show event group information together"), |
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 2126bfbcb385..6a8738f7ead3 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c | |||
| @@ -56,16 +56,16 @@ struct c2c_hist_entry { | |||
| 56 | 56 | ||
| 57 | struct compute_stats cstats; | 57 | struct compute_stats cstats; |
| 58 | 58 | ||
| 59 | unsigned long paddr; | ||
| 60 | unsigned long paddr_cnt; | ||
| 61 | bool paddr_zero; | ||
| 62 | char *nodestr; | ||
| 63 | |||
| 59 | /* | 64 | /* |
| 60 | * must be at the end, | 65 | * must be at the end, |
| 61 | * because of its callchain dynamic entry | 66 | * because of its callchain dynamic entry |
| 62 | */ | 67 | */ |
| 63 | struct hist_entry he; | 68 | struct hist_entry he; |
| 64 | |||
| 65 | unsigned long paddr; | ||
| 66 | unsigned long paddr_cnt; | ||
| 67 | bool paddr_zero; | ||
| 68 | char *nodestr; | ||
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | static char const *coalesce_default = "pid,iaddr"; | 71 | static char const *coalesce_default = "pid,iaddr"; |
| @@ -1976,7 +1976,7 @@ static int filter_cb(struct hist_entry *he) | |||
| 1976 | c2c_he = container_of(he, struct c2c_hist_entry, he); | 1976 | c2c_he = container_of(he, struct c2c_hist_entry, he); |
| 1977 | 1977 | ||
| 1978 | if (c2c.show_src && !he->srcline) | 1978 | if (c2c.show_src && !he->srcline) |
| 1979 | he->srcline = hist_entry__get_srcline(he); | 1979 | he->srcline = hist_entry__srcline(he); |
| 1980 | 1980 | ||
| 1981 | calc_width(c2c_he); | 1981 | calc_width(c2c_he); |
| 1982 | 1982 | ||
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 72e2ca096bf5..2b1ef704169f 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
| @@ -1438,8 +1438,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, | |||
| 1438 | goto out; | 1438 | goto out; |
| 1439 | } | 1439 | } |
| 1440 | 1440 | ||
| 1441 | symbol_conf.nr_events = kvm->evlist->nr_entries; | ||
| 1442 | |||
| 1443 | if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0) | 1441 | if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0) |
| 1444 | usage_with_options(live_usage, live_options); | 1442 | usage_with_options(live_usage, live_options); |
| 1445 | 1443 | ||
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c0065923a525..99de91698de1 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -81,8 +81,7 @@ static int parse_probe_event(const char *str) | |||
| 81 | params.target_used = true; | 81 | params.target_used = true; |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | if (params.nsi) | 84 | pev->nsi = nsinfo__get(params.nsi); |
| 85 | pev->nsi = nsinfo__get(params.nsi); | ||
| 86 | 85 | ||
| 87 | /* Parse a perf-probe command into event */ | 86 | /* Parse a perf-probe command into event */ |
| 88 | ret = parse_perf_probe_command(str, pev); | 87 | ret = parse_perf_probe_command(str, pev); |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ad978e3ee2b8..c04dc7b53797 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -71,6 +71,7 @@ struct report { | |||
| 71 | bool group_set; | 71 | bool group_set; |
| 72 | int max_stack; | 72 | int max_stack; |
| 73 | struct perf_read_values show_threads_values; | 73 | struct perf_read_values show_threads_values; |
| 74 | struct annotation_options annotation_opts; | ||
| 74 | const char *pretty_printing_style; | 75 | const char *pretty_printing_style; |
| 75 | const char *cpu_list; | 76 | const char *cpu_list; |
| 76 | const char *symbol_filter_str; | 77 | const char *symbol_filter_str; |
| @@ -136,26 +137,25 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, | |||
| 136 | 137 | ||
| 137 | if (sort__mode == SORT_MODE__BRANCH) { | 138 | if (sort__mode == SORT_MODE__BRANCH) { |
| 138 | bi = he->branch_info; | 139 | bi = he->branch_info; |
| 139 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); | 140 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); |
| 140 | if (err) | 141 | if (err) |
| 141 | goto out; | 142 | goto out; |
| 142 | 143 | ||
| 143 | err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); | 144 | err = addr_map_symbol__inc_samples(&bi->to, sample, evsel); |
| 144 | 145 | ||
| 145 | } else if (rep->mem_mode) { | 146 | } else if (rep->mem_mode) { |
| 146 | mi = he->mem_info; | 147 | mi = he->mem_info; |
| 147 | err = addr_map_symbol__inc_samples(&mi->daddr, sample, evsel->idx); | 148 | err = addr_map_symbol__inc_samples(&mi->daddr, sample, evsel); |
| 148 | if (err) | 149 | if (err) |
| 149 | goto out; | 150 | goto out; |
| 150 | 151 | ||
| 151 | err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); | 152 | err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr); |
| 152 | 153 | ||
| 153 | } else if (symbol_conf.cumulate_callchain) { | 154 | } else if (symbol_conf.cumulate_callchain) { |
| 154 | if (single) | 155 | if (single) |
| 155 | err = hist_entry__inc_addr_samples(he, sample, evsel->idx, | 156 | err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr); |
| 156 | al->addr); | ||
| 157 | } else { | 157 | } else { |
| 158 | err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); | 158 | err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | out: | 161 | out: |
| @@ -181,11 +181,11 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, | |||
| 181 | rep->nonany_branch_mode); | 181 | rep->nonany_branch_mode); |
| 182 | 182 | ||
| 183 | bi = he->branch_info; | 183 | bi = he->branch_info; |
| 184 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); | 184 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); |
| 185 | if (err) | 185 | if (err) |
| 186 | goto out; | 186 | goto out; |
| 187 | 187 | ||
| 188 | err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); | 188 | err = addr_map_symbol__inc_samples(&bi->to, sample, evsel); |
| 189 | 189 | ||
| 190 | branch_type_count(&rep->brtype_stat, &bi->flags, | 190 | branch_type_count(&rep->brtype_stat, &bi->flags, |
| 191 | bi->from.addr, bi->to.addr); | 191 | bi->from.addr, bi->to.addr); |
| @@ -217,7 +217,8 @@ static int process_feature_event(struct perf_tool *tool, | |||
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | /* | 219 | /* |
| 220 | * All features are received, we can force the | 220 | * (feat_id = HEADER_LAST_FEATURE) is the end marker which |
| 221 | * means all features are received, now we can force the | ||
| 221 | * group if needed. | 222 | * group if needed. |
| 222 | */ | 223 | */ |
| 223 | setup_forced_leader(rep, session->evlist); | 224 | setup_forced_leader(rep, session->evlist); |
| @@ -561,7 +562,7 @@ static int report__browse_hists(struct report *rep) | |||
| 561 | ret = perf_evlist__tui_browse_hists(evlist, help, NULL, | 562 | ret = perf_evlist__tui_browse_hists(evlist, help, NULL, |
| 562 | rep->min_percent, | 563 | rep->min_percent, |
| 563 | &session->header.env, | 564 | &session->header.env, |
| 564 | true); | 565 | true, &rep->annotation_opts); |
| 565 | /* | 566 | /* |
| 566 | * Usually "ret" is the last pressed key, and we only | 567 | * Usually "ret" is the last pressed key, and we only |
| 567 | * care if the key notifies us to switch data file. | 568 | * care if the key notifies us to switch data file. |
| @@ -946,12 +947,6 @@ parse_percent_limit(const struct option *opt, const char *str, | |||
| 946 | return 0; | 947 | return 0; |
| 947 | } | 948 | } |
| 948 | 949 | ||
| 949 | #define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent" | ||
| 950 | |||
| 951 | const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" | ||
| 952 | CALLCHAIN_REPORT_HELP | ||
| 953 | "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; | ||
| 954 | |||
| 955 | int cmd_report(int argc, const char **argv) | 950 | int cmd_report(int argc, const char **argv) |
| 956 | { | 951 | { |
| 957 | struct perf_session *session; | 952 | struct perf_session *session; |
| @@ -960,6 +955,10 @@ int cmd_report(int argc, const char **argv) | |||
| 960 | bool has_br_stack = false; | 955 | bool has_br_stack = false; |
| 961 | int branch_mode = -1; | 956 | int branch_mode = -1; |
| 962 | bool branch_call_mode = false; | 957 | bool branch_call_mode = false; |
| 958 | #define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent" | ||
| 959 | const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" | ||
| 960 | CALLCHAIN_REPORT_HELP | ||
| 961 | "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; | ||
| 963 | char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; | 962 | char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; |
| 964 | const char * const report_usage[] = { | 963 | const char * const report_usage[] = { |
| 965 | "perf report [<options>]", | 964 | "perf report [<options>]", |
| @@ -989,6 +988,7 @@ int cmd_report(int argc, const char **argv) | |||
| 989 | .max_stack = PERF_MAX_STACK_DEPTH, | 988 | .max_stack = PERF_MAX_STACK_DEPTH, |
| 990 | .pretty_printing_style = "normal", | 989 | .pretty_printing_style = "normal", |
| 991 | .socket_filter = -1, | 990 | .socket_filter = -1, |
| 991 | .annotation_opts = annotation__default_options, | ||
| 992 | }; | 992 | }; |
| 993 | const struct option options[] = { | 993 | const struct option options[] = { |
| 994 | OPT_STRING('i', "input", &input_name, "file", | 994 | OPT_STRING('i', "input", &input_name, "file", |
| @@ -1078,11 +1078,11 @@ int cmd_report(int argc, const char **argv) | |||
| 1078 | "list of cpus to profile"), | 1078 | "list of cpus to profile"), |
| 1079 | OPT_BOOLEAN('I', "show-info", &report.show_full_info, | 1079 | OPT_BOOLEAN('I', "show-info", &report.show_full_info, |
| 1080 | "Display extended information about perf.data file"), | 1080 | "Display extended information about perf.data file"), |
| 1081 | OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, | 1081 | OPT_BOOLEAN(0, "source", &report.annotation_opts.annotate_src, |
| 1082 | "Interleave source code with assembly code (default)"), | 1082 | "Interleave source code with assembly code (default)"), |
| 1083 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | 1083 | OPT_BOOLEAN(0, "asm-raw", &report.annotation_opts.show_asm_raw, |
| 1084 | "Display raw encoding of assembly instructions (default)"), | 1084 | "Display raw encoding of assembly instructions (default)"), |
| 1085 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1085 | OPT_STRING('M', "disassembler-style", &report.annotation_opts.disassembler_style, "disassembler style", |
| 1086 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 1086 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
| 1087 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | 1087 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, |
| 1088 | "Show a column with the sum of periods"), | 1088 | "Show a column with the sum of periods"), |
| @@ -1093,7 +1093,7 @@ int cmd_report(int argc, const char **argv) | |||
| 1093 | parse_branch_mode), | 1093 | parse_branch_mode), |
| 1094 | OPT_BOOLEAN(0, "branch-history", &branch_call_mode, | 1094 | OPT_BOOLEAN(0, "branch-history", &branch_call_mode, |
| 1095 | "add last branch records to call history"), | 1095 | "add last branch records to call history"), |
| 1096 | OPT_STRING(0, "objdump", &objdump_path, "path", | 1096 | OPT_STRING(0, "objdump", &report.annotation_opts.objdump_path, "path", |
| 1097 | "objdump binary to use for disassembly and annotations"), | 1097 | "objdump binary to use for disassembly and annotations"), |
| 1098 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, | 1098 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, |
| 1099 | "Disable symbol demangling"), | 1099 | "Disable symbol demangling"), |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 4dfdee668b0c..cbf39dab19c1 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
| @@ -2143,7 +2143,7 @@ static void save_task_callchain(struct perf_sched *sched, | |||
| 2143 | return; | 2143 | return; |
| 2144 | } | 2144 | } |
| 2145 | 2145 | ||
| 2146 | if (!symbol_conf.use_callchain || sample->callchain == NULL) | 2146 | if (!sched->show_callchain || sample->callchain == NULL) |
| 2147 | return; | 2147 | return; |
| 2148 | 2148 | ||
| 2149 | if (thread__resolve_callchain(thread, cursor, evsel, sample, | 2149 | if (thread__resolve_callchain(thread, cursor, evsel, sample, |
| @@ -2271,10 +2271,11 @@ static struct thread *get_idle_thread(int cpu) | |||
| 2271 | return idle_threads[cpu]; | 2271 | return idle_threads[cpu]; |
| 2272 | } | 2272 | } |
| 2273 | 2273 | ||
| 2274 | static void save_idle_callchain(struct idle_thread_runtime *itr, | 2274 | static void save_idle_callchain(struct perf_sched *sched, |
| 2275 | struct idle_thread_runtime *itr, | ||
| 2275 | struct perf_sample *sample) | 2276 | struct perf_sample *sample) |
| 2276 | { | 2277 | { |
| 2277 | if (!symbol_conf.use_callchain || sample->callchain == NULL) | 2278 | if (!sched->show_callchain || sample->callchain == NULL) |
| 2278 | return; | 2279 | return; |
| 2279 | 2280 | ||
| 2280 | callchain_cursor__copy(&itr->cursor, &callchain_cursor); | 2281 | callchain_cursor__copy(&itr->cursor, &callchain_cursor); |
| @@ -2320,7 +2321,7 @@ static struct thread *timehist_get_thread(struct perf_sched *sched, | |||
| 2320 | 2321 | ||
| 2321 | /* copy task callchain when entering to idle */ | 2322 | /* copy task callchain when entering to idle */ |
| 2322 | if (perf_evsel__intval(evsel, sample, "next_pid") == 0) | 2323 | if (perf_evsel__intval(evsel, sample, "next_pid") == 0) |
| 2323 | save_idle_callchain(itr, sample); | 2324 | save_idle_callchain(sched, itr, sample); |
| 2324 | } | 2325 | } |
| 2325 | } | 2326 | } |
| 2326 | 2327 | ||
| @@ -2849,7 +2850,7 @@ static void timehist_print_summary(struct perf_sched *sched, | |||
| 2849 | printf(" CPU %2d idle entire time window\n", i); | 2850 | printf(" CPU %2d idle entire time window\n", i); |
| 2850 | } | 2851 | } |
| 2851 | 2852 | ||
| 2852 | if (sched->idle_hist && symbol_conf.use_callchain) { | 2853 | if (sched->idle_hist && sched->show_callchain) { |
| 2853 | callchain_param.mode = CHAIN_FOLDED; | 2854 | callchain_param.mode = CHAIN_FOLDED; |
| 2854 | callchain_param.value = CCVAL_PERIOD; | 2855 | callchain_param.value = CCVAL_PERIOD; |
| 2855 | 2856 | ||
| @@ -2933,8 +2934,7 @@ static int timehist_check_attr(struct perf_sched *sched, | |||
| 2933 | return -1; | 2934 | return -1; |
| 2934 | } | 2935 | } |
| 2935 | 2936 | ||
| 2936 | if (sched->show_callchain && | 2937 | if (sched->show_callchain && !evsel__has_callchain(evsel)) { |
| 2937 | !(evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN)) { | ||
| 2938 | pr_info("Samples do not have callchains.\n"); | 2938 | pr_info("Samples do not have callchains.\n"); |
| 2939 | sched->show_callchain = 0; | 2939 | sched->show_callchain = 0; |
| 2940 | symbol_conf.use_callchain = 0; | 2940 | symbol_conf.use_callchain = 0; |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index cefc8813e91e..568ddfac3213 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -180,6 +180,18 @@ static struct { | |||
| 180 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE | 180 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE |
| 181 | }, | 181 | }, |
| 182 | 182 | ||
| 183 | [PERF_TYPE_HW_CACHE] = { | ||
| 184 | .user_set = false, | ||
| 185 | |||
| 186 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | | ||
| 187 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | ||
| 188 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | ||
| 189 | PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET | | ||
| 190 | PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD, | ||
| 191 | |||
| 192 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, | ||
| 193 | }, | ||
| 194 | |||
| 183 | [PERF_TYPE_RAW] = { | 195 | [PERF_TYPE_RAW] = { |
| 184 | .user_set = false, | 196 | .user_set = false, |
| 185 | 197 | ||
| @@ -517,7 +529,7 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
| 517 | 529 | ||
| 518 | evlist__for_each_entry(session->evlist, evsel) { | 530 | evlist__for_each_entry(session->evlist, evsel) { |
| 519 | not_pipe = true; | 531 | not_pipe = true; |
| 520 | if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { | 532 | if (evsel__has_callchain(evsel)) { |
| 521 | use_callchain = true; | 533 | use_callchain = true; |
| 522 | break; | 534 | break; |
| 523 | } | 535 | } |
| @@ -532,22 +544,18 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
| 532 | */ | 544 | */ |
| 533 | if (symbol_conf.use_callchain && | 545 | if (symbol_conf.use_callchain && |
| 534 | !output[PERF_TYPE_TRACEPOINT].user_set) { | 546 | !output[PERF_TYPE_TRACEPOINT].user_set) { |
| 535 | struct perf_event_attr *attr; | ||
| 536 | |||
| 537 | j = PERF_TYPE_TRACEPOINT; | 547 | j = PERF_TYPE_TRACEPOINT; |
| 538 | 548 | ||
| 539 | evlist__for_each_entry(session->evlist, evsel) { | 549 | evlist__for_each_entry(session->evlist, evsel) { |
| 540 | if (evsel->attr.type != j) | 550 | if (evsel->attr.type != j) |
| 541 | continue; | 551 | continue; |
| 542 | 552 | ||
| 543 | attr = &evsel->attr; | 553 | if (evsel__has_callchain(evsel)) { |
| 544 | |||
| 545 | if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
| 546 | output[j].fields |= PERF_OUTPUT_IP; | 554 | output[j].fields |= PERF_OUTPUT_IP; |
| 547 | output[j].fields |= PERF_OUTPUT_SYM; | 555 | output[j].fields |= PERF_OUTPUT_SYM; |
| 548 | output[j].fields |= PERF_OUTPUT_SYMOFFSET; | 556 | output[j].fields |= PERF_OUTPUT_SYMOFFSET; |
| 549 | output[j].fields |= PERF_OUTPUT_DSO; | 557 | output[j].fields |= PERF_OUTPUT_DSO; |
| 550 | set_print_ip_opts(attr); | 558 | set_print_ip_opts(&evsel->attr); |
| 551 | goto out; | 559 | goto out; |
| 552 | } | 560 | } |
| 553 | } | 561 | } |
| @@ -610,7 +618,7 @@ static int perf_sample__fprintf_start(struct perf_sample *sample, | |||
| 610 | if (PRINT_FIELD(COMM)) { | 618 | if (PRINT_FIELD(COMM)) { |
| 611 | if (latency_format) | 619 | if (latency_format) |
| 612 | printed += fprintf(fp, "%8.8s ", thread__comm_str(thread)); | 620 | printed += fprintf(fp, "%8.8s ", thread__comm_str(thread)); |
| 613 | else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) | 621 | else if (PRINT_FIELD(IP) && evsel__has_callchain(evsel) && symbol_conf.use_callchain) |
| 614 | printed += fprintf(fp, "%s ", thread__comm_str(thread)); | 622 | printed += fprintf(fp, "%s ", thread__comm_str(thread)); |
| 615 | else | 623 | else |
| 616 | printed += fprintf(fp, "%16s ", thread__comm_str(thread)); | 624 | printed += fprintf(fp, "%16s ", thread__comm_str(thread)); |
| @@ -1826,6 +1834,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, | |||
| 1826 | struct perf_evlist *evlist; | 1834 | struct perf_evlist *evlist; |
| 1827 | struct perf_evsel *evsel, *pos; | 1835 | struct perf_evsel *evsel, *pos; |
| 1828 | int err; | 1836 | int err; |
| 1837 | static struct perf_evsel_script *es; | ||
| 1829 | 1838 | ||
| 1830 | err = perf_event__process_attr(tool, event, pevlist); | 1839 | err = perf_event__process_attr(tool, event, pevlist); |
| 1831 | if (err) | 1840 | if (err) |
| @@ -1834,6 +1843,19 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, | |||
| 1834 | evlist = *pevlist; | 1843 | evlist = *pevlist; |
| 1835 | evsel = perf_evlist__last(*pevlist); | 1844 | evsel = perf_evlist__last(*pevlist); |
| 1836 | 1845 | ||
| 1846 | if (!evsel->priv) { | ||
| 1847 | if (scr->per_event_dump) { | ||
| 1848 | evsel->priv = perf_evsel_script__new(evsel, | ||
| 1849 | scr->session->data); | ||
| 1850 | } else { | ||
| 1851 | es = zalloc(sizeof(*es)); | ||
| 1852 | if (!es) | ||
| 1853 | return -ENOMEM; | ||
| 1854 | es->fp = stdout; | ||
| 1855 | evsel->priv = es; | ||
| 1856 | } | ||
| 1857 | } | ||
| 1858 | |||
| 1837 | if (evsel->attr.type >= PERF_TYPE_MAX && | 1859 | if (evsel->attr.type >= PERF_TYPE_MAX && |
| 1838 | evsel->attr.type != PERF_TYPE_SYNTH) | 1860 | evsel->attr.type != PERF_TYPE_SYNTH) |
| 1839 | return 0; | 1861 | return 0; |
| @@ -3022,6 +3044,15 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused, | |||
| 3022 | return set_maps(script); | 3044 | return set_maps(script); |
| 3023 | } | 3045 | } |
| 3024 | 3046 | ||
| 3047 | static int process_feature_event(struct perf_tool *tool, | ||
| 3048 | union perf_event *event, | ||
| 3049 | struct perf_session *session) | ||
| 3050 | { | ||
| 3051 | if (event->feat.feat_id < HEADER_LAST_FEATURE) | ||
| 3052 | return perf_event__process_feature(tool, event, session); | ||
| 3053 | return 0; | ||
| 3054 | } | ||
| 3055 | |||
| 3025 | #ifdef HAVE_AUXTRACE_SUPPORT | 3056 | #ifdef HAVE_AUXTRACE_SUPPORT |
| 3026 | static int perf_script__process_auxtrace_info(struct perf_tool *tool, | 3057 | static int perf_script__process_auxtrace_info(struct perf_tool *tool, |
| 3027 | union perf_event *event, | 3058 | union perf_event *event, |
| @@ -3066,7 +3097,7 @@ int cmd_script(int argc, const char **argv) | |||
| 3066 | .attr = process_attr, | 3097 | .attr = process_attr, |
| 3067 | .event_update = perf_event__process_event_update, | 3098 | .event_update = perf_event__process_event_update, |
| 3068 | .tracing_data = perf_event__process_tracing_data, | 3099 | .tracing_data = perf_event__process_tracing_data, |
| 3069 | .feature = perf_event__process_feature, | 3100 | .feature = process_feature_event, |
| 3070 | .build_id = perf_event__process_build_id, | 3101 | .build_id = perf_event__process_build_id, |
| 3071 | .id_index = perf_event__process_id_index, | 3102 | .id_index = perf_event__process_id_index, |
| 3072 | .auxtrace_info = perf_script__process_auxtrace_info, | 3103 | .auxtrace_info = perf_script__process_auxtrace_info, |
| @@ -3117,8 +3148,9 @@ int cmd_script(int argc, const char **argv) | |||
| 3117 | "+field to add and -field to remove." | 3148 | "+field to add and -field to remove." |
| 3118 | "Valid types: hw,sw,trace,raw,synth. " | 3149 | "Valid types: hw,sw,trace,raw,synth. " |
| 3119 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 3150 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
| 3120 | "addr,symoff,period,iregs,uregs,brstack,brstacksym,flags," | 3151 | "addr,symoff,srcline,period,iregs,uregs,brstack," |
| 3121 | "bpf-output,callindent,insn,insnlen,brstackinsn,synth,phys_addr", | 3152 | "brstacksym,flags,bpf-output,brstackinsn,brstackoff," |
| 3153 | "callindent,insn,insnlen,synth,phys_addr,metric,misc", | ||
| 3122 | parse_output_fields), | 3154 | parse_output_fields), |
| 3123 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 3155 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
| 3124 | "system-wide collection from all CPUs"), | 3156 | "system-wide collection from all CPUs"), |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a4f662a462c6..22547a490e1f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -65,6 +65,7 @@ | |||
| 65 | #include "util/tool.h" | 65 | #include "util/tool.h" |
| 66 | #include "util/string2.h" | 66 | #include "util/string2.h" |
| 67 | #include "util/metricgroup.h" | 67 | #include "util/metricgroup.h" |
| 68 | #include "util/top.h" | ||
| 68 | #include "asm/bug.h" | 69 | #include "asm/bug.h" |
| 69 | 70 | ||
| 70 | #include <linux/time64.h> | 71 | #include <linux/time64.h> |
| @@ -80,6 +81,9 @@ | |||
| 80 | #include <sys/stat.h> | 81 | #include <sys/stat.h> |
| 81 | #include <sys/wait.h> | 82 | #include <sys/wait.h> |
| 82 | #include <unistd.h> | 83 | #include <unistd.h> |
| 84 | #include <sys/time.h> | ||
| 85 | #include <sys/resource.h> | ||
| 86 | #include <sys/wait.h> | ||
| 83 | 87 | ||
| 84 | #include "sane_ctype.h" | 88 | #include "sane_ctype.h" |
| 85 | 89 | ||
| @@ -141,6 +145,8 @@ static struct target target = { | |||
| 141 | 145 | ||
| 142 | typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); | 146 | typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); |
| 143 | 147 | ||
| 148 | #define METRIC_ONLY_LEN 20 | ||
| 149 | |||
| 144 | static int run_count = 1; | 150 | static int run_count = 1; |
| 145 | static bool no_inherit = false; | 151 | static bool no_inherit = false; |
| 146 | static volatile pid_t child_pid = -1; | 152 | static volatile pid_t child_pid = -1; |
| @@ -170,11 +176,15 @@ static struct cpu_map *aggr_map; | |||
| 170 | static aggr_get_id_t aggr_get_id; | 176 | static aggr_get_id_t aggr_get_id; |
| 171 | static bool append_file; | 177 | static bool append_file; |
| 172 | static bool interval_count; | 178 | static bool interval_count; |
| 179 | static bool interval_clear; | ||
| 173 | static const char *output_name; | 180 | static const char *output_name; |
| 174 | static int output_fd; | 181 | static int output_fd; |
| 175 | static int print_free_counters_hint; | 182 | static int print_free_counters_hint; |
| 176 | static int print_mixed_hw_group_error; | 183 | static int print_mixed_hw_group_error; |
| 177 | static u64 *walltime_run; | 184 | static u64 *walltime_run; |
| 185 | static bool ru_display = false; | ||
| 186 | static struct rusage ru_data; | ||
| 187 | static unsigned int metric_only_len = METRIC_ONLY_LEN; | ||
| 178 | 188 | ||
| 179 | struct perf_stat { | 189 | struct perf_stat { |
| 180 | bool record; | 190 | bool record; |
| @@ -726,7 +736,7 @@ try_again: | |||
| 726 | break; | 736 | break; |
| 727 | } | 737 | } |
| 728 | } | 738 | } |
| 729 | waitpid(child_pid, &status, 0); | 739 | wait4(child_pid, &status, 0, &ru_data); |
| 730 | 740 | ||
| 731 | if (workload_exec_errno) { | 741 | if (workload_exec_errno) { |
| 732 | const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); | 742 | const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); |
| @@ -962,8 +972,6 @@ static void print_metric_csv(void *ctx, | |||
| 962 | fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit); | 972 | fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit); |
| 963 | } | 973 | } |
| 964 | 974 | ||
| 965 | #define METRIC_ONLY_LEN 20 | ||
| 966 | |||
| 967 | /* Filter out some columns that don't work well in metrics only mode */ | 975 | /* Filter out some columns that don't work well in metrics only mode */ |
| 968 | 976 | ||
| 969 | static bool valid_only_metric(const char *unit) | 977 | static bool valid_only_metric(const char *unit) |
| @@ -994,22 +1002,20 @@ static void print_metric_only(void *ctx, const char *color, const char *fmt, | |||
| 994 | { | 1002 | { |
| 995 | struct outstate *os = ctx; | 1003 | struct outstate *os = ctx; |
| 996 | FILE *out = os->fh; | 1004 | FILE *out = os->fh; |
| 997 | int n; | 1005 | char buf[1024], str[1024]; |
| 998 | char buf[1024]; | 1006 | unsigned mlen = metric_only_len; |
| 999 | unsigned mlen = METRIC_ONLY_LEN; | ||
| 1000 | 1007 | ||
| 1001 | if (!valid_only_metric(unit)) | 1008 | if (!valid_only_metric(unit)) |
| 1002 | return; | 1009 | return; |
| 1003 | unit = fixunit(buf, os->evsel, unit); | 1010 | unit = fixunit(buf, os->evsel, unit); |
| 1004 | if (color) | ||
| 1005 | n = color_fprintf(out, color, fmt, val); | ||
| 1006 | else | ||
| 1007 | n = fprintf(out, fmt, val); | ||
| 1008 | if (n > METRIC_ONLY_LEN) | ||
| 1009 | n = METRIC_ONLY_LEN; | ||
| 1010 | if (mlen < strlen(unit)) | 1011 | if (mlen < strlen(unit)) |
| 1011 | mlen = strlen(unit) + 1; | 1012 | mlen = strlen(unit) + 1; |
| 1012 | fprintf(out, "%*s", mlen - n, ""); | 1013 | |
| 1014 | if (color) | ||
| 1015 | mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1; | ||
| 1016 | |||
| 1017 | color_snprintf(str, sizeof(str), color ?: "", fmt, val); | ||
| 1018 | fprintf(out, "%*s ", mlen, str); | ||
| 1013 | } | 1019 | } |
| 1014 | 1020 | ||
| 1015 | static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, | 1021 | static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, |
| @@ -1049,7 +1055,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused, | |||
| 1049 | if (csv_output) | 1055 | if (csv_output) |
| 1050 | fprintf(os->fh, "%s%s", unit, csv_sep); | 1056 | fprintf(os->fh, "%s%s", unit, csv_sep); |
| 1051 | else | 1057 | else |
| 1052 | fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit); | 1058 | fprintf(os->fh, "%*s ", metric_only_len, unit); |
| 1053 | } | 1059 | } |
| 1054 | 1060 | ||
| 1055 | static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) | 1061 | static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) |
| @@ -1699,9 +1705,12 @@ static void print_interval(char *prefix, struct timespec *ts) | |||
| 1699 | FILE *output = stat_config.output; | 1705 | FILE *output = stat_config.output; |
| 1700 | static int num_print_interval; | 1706 | static int num_print_interval; |
| 1701 | 1707 | ||
| 1708 | if (interval_clear) | ||
| 1709 | puts(CONSOLE_CLEAR); | ||
| 1710 | |||
| 1702 | sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); | 1711 | sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); |
| 1703 | 1712 | ||
| 1704 | if (num_print_interval == 0 && !csv_output) { | 1713 | if ((num_print_interval == 0 && !csv_output) || interval_clear) { |
| 1705 | switch (stat_config.aggr_mode) { | 1714 | switch (stat_config.aggr_mode) { |
| 1706 | case AGGR_SOCKET: | 1715 | case AGGR_SOCKET: |
| 1707 | fprintf(output, "# time socket cpus"); | 1716 | fprintf(output, "# time socket cpus"); |
| @@ -1714,7 +1723,7 @@ static void print_interval(char *prefix, struct timespec *ts) | |||
| 1714 | fprintf(output, " counts %*s events\n", unit_width, "unit"); | 1723 | fprintf(output, " counts %*s events\n", unit_width, "unit"); |
| 1715 | break; | 1724 | break; |
| 1716 | case AGGR_NONE: | 1725 | case AGGR_NONE: |
| 1717 | fprintf(output, "# time CPU"); | 1726 | fprintf(output, "# time CPU "); |
| 1718 | if (!metric_only) | 1727 | if (!metric_only) |
| 1719 | fprintf(output, " counts %*s events\n", unit_width, "unit"); | 1728 | fprintf(output, " counts %*s events\n", unit_width, "unit"); |
| 1720 | break; | 1729 | break; |
| @@ -1733,7 +1742,7 @@ static void print_interval(char *prefix, struct timespec *ts) | |||
| 1733 | } | 1742 | } |
| 1734 | } | 1743 | } |
| 1735 | 1744 | ||
| 1736 | if (num_print_interval == 0 && metric_only) | 1745 | if ((num_print_interval == 0 && metric_only) || interval_clear) |
| 1737 | print_metric_headers(" ", true); | 1746 | print_metric_headers(" ", true); |
| 1738 | if (++num_print_interval == 25) | 1747 | if (++num_print_interval == 25) |
| 1739 | num_print_interval = 0; | 1748 | num_print_interval = 0; |
| @@ -1804,6 +1813,11 @@ static void print_table(FILE *output, int precision, double avg) | |||
| 1804 | fprintf(output, "\n%*s# Final result:\n", indent, ""); | 1813 | fprintf(output, "\n%*s# Final result:\n", indent, ""); |
| 1805 | } | 1814 | } |
| 1806 | 1815 | ||
| 1816 | static double timeval2double(struct timeval *t) | ||
| 1817 | { | ||
| 1818 | return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC; | ||
| 1819 | } | ||
| 1820 | |||
| 1807 | static void print_footer(void) | 1821 | static void print_footer(void) |
| 1808 | { | 1822 | { |
| 1809 | double avg = avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC; | 1823 | double avg = avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC; |
| @@ -1815,6 +1829,15 @@ static void print_footer(void) | |||
| 1815 | 1829 | ||
| 1816 | if (run_count == 1) { | 1830 | if (run_count == 1) { |
| 1817 | fprintf(output, " %17.9f seconds time elapsed", avg); | 1831 | fprintf(output, " %17.9f seconds time elapsed", avg); |
| 1832 | |||
| 1833 | if (ru_display) { | ||
| 1834 | double ru_utime = timeval2double(&ru_data.ru_utime); | ||
| 1835 | double ru_stime = timeval2double(&ru_data.ru_stime); | ||
| 1836 | |||
| 1837 | fprintf(output, "\n\n"); | ||
| 1838 | fprintf(output, " %17.9f seconds user\n", ru_utime); | ||
| 1839 | fprintf(output, " %17.9f seconds sys\n", ru_stime); | ||
| 1840 | } | ||
| 1818 | } else { | 1841 | } else { |
| 1819 | double sd = stddev_stats(&walltime_nsecs_stats) / NSEC_PER_SEC; | 1842 | double sd = stddev_stats(&walltime_nsecs_stats) / NSEC_PER_SEC; |
| 1820 | /* | 1843 | /* |
| @@ -2038,6 +2061,8 @@ static const struct option stat_options[] = { | |||
| 2038 | "(overhead is possible for values <= 100ms)"), | 2061 | "(overhead is possible for values <= 100ms)"), |
| 2039 | OPT_INTEGER(0, "interval-count", &stat_config.times, | 2062 | OPT_INTEGER(0, "interval-count", &stat_config.times, |
| 2040 | "print counts for fixed number of times"), | 2063 | "print counts for fixed number of times"), |
| 2064 | OPT_BOOLEAN(0, "interval-clear", &interval_clear, | ||
| 2065 | "clear screen in between new interval"), | ||
| 2041 | OPT_UINTEGER(0, "timeout", &stat_config.timeout, | 2066 | OPT_UINTEGER(0, "timeout", &stat_config.timeout, |
| 2042 | "stop workload and print counts after a timeout period in ms (>= 10ms)"), | 2067 | "stop workload and print counts after a timeout period in ms (>= 10ms)"), |
| 2043 | OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, | 2068 | OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, |
| @@ -2417,14 +2442,13 @@ static int add_default_attributes(void) | |||
| 2417 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | | 2442 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | |
| 2418 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | 2443 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, |
| 2419 | }; | 2444 | }; |
| 2445 | struct parse_events_error errinfo; | ||
| 2420 | 2446 | ||
| 2421 | /* Set attrs if no event is selected and !null_run: */ | 2447 | /* Set attrs if no event is selected and !null_run: */ |
| 2422 | if (null_run) | 2448 | if (null_run) |
| 2423 | return 0; | 2449 | return 0; |
| 2424 | 2450 | ||
| 2425 | if (transaction_run) { | 2451 | if (transaction_run) { |
| 2426 | struct parse_events_error errinfo; | ||
| 2427 | |||
| 2428 | if (pmu_have_event("cpu", "cycles-ct") && | 2452 | if (pmu_have_event("cpu", "cycles-ct") && |
| 2429 | pmu_have_event("cpu", "el-start")) | 2453 | pmu_have_event("cpu", "el-start")) |
| 2430 | err = parse_events(evsel_list, transaction_attrs, | 2454 | err = parse_events(evsel_list, transaction_attrs, |
| @@ -2435,6 +2459,7 @@ static int add_default_attributes(void) | |||
| 2435 | &errinfo); | 2459 | &errinfo); |
| 2436 | if (err) { | 2460 | if (err) { |
| 2437 | fprintf(stderr, "Cannot set up transaction events\n"); | 2461 | fprintf(stderr, "Cannot set up transaction events\n"); |
| 2462 | parse_events_print_error(&errinfo, transaction_attrs); | ||
| 2438 | return -1; | 2463 | return -1; |
| 2439 | } | 2464 | } |
| 2440 | return 0; | 2465 | return 0; |
| @@ -2460,10 +2485,11 @@ static int add_default_attributes(void) | |||
| 2460 | pmu_have_event("msr", "smi")) { | 2485 | pmu_have_event("msr", "smi")) { |
| 2461 | if (!force_metric_only) | 2486 | if (!force_metric_only) |
| 2462 | metric_only = true; | 2487 | metric_only = true; |
| 2463 | err = parse_events(evsel_list, smi_cost_attrs, NULL); | 2488 | err = parse_events(evsel_list, smi_cost_attrs, &errinfo); |
| 2464 | } else { | 2489 | } else { |
| 2465 | fprintf(stderr, "To measure SMI cost, it needs " | 2490 | fprintf(stderr, "To measure SMI cost, it needs " |
| 2466 | "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); | 2491 | "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); |
| 2492 | parse_events_print_error(&errinfo, smi_cost_attrs); | ||
| 2467 | return -1; | 2493 | return -1; |
| 2468 | } | 2494 | } |
| 2469 | if (err) { | 2495 | if (err) { |
| @@ -2498,12 +2524,13 @@ static int add_default_attributes(void) | |||
| 2498 | if (topdown_attrs[0] && str) { | 2524 | if (topdown_attrs[0] && str) { |
| 2499 | if (warn) | 2525 | if (warn) |
| 2500 | arch_topdown_group_warn(); | 2526 | arch_topdown_group_warn(); |
| 2501 | err = parse_events(evsel_list, str, NULL); | 2527 | err = parse_events(evsel_list, str, &errinfo); |
| 2502 | if (err) { | 2528 | if (err) { |
| 2503 | fprintf(stderr, | 2529 | fprintf(stderr, |
| 2504 | "Cannot set up top down events %s: %d\n", | 2530 | "Cannot set up top down events %s: %d\n", |
| 2505 | str, err); | 2531 | str, err); |
| 2506 | free(str); | 2532 | free(str); |
| 2533 | parse_events_print_error(&errinfo, str); | ||
| 2507 | return -1; | 2534 | return -1; |
| 2508 | } | 2535 | } |
| 2509 | } else { | 2536 | } else { |
| @@ -2950,6 +2977,13 @@ int cmd_stat(int argc, const char **argv) | |||
| 2950 | 2977 | ||
| 2951 | setup_system_wide(argc); | 2978 | setup_system_wide(argc); |
| 2952 | 2979 | ||
| 2980 | /* | ||
| 2981 | * Display user/system times only for single | ||
| 2982 | * run and when there's specified tracee. | ||
| 2983 | */ | ||
| 2984 | if ((run_count == 1) && target__none(&target)) | ||
| 2985 | ru_display = true; | ||
| 2986 | |||
| 2953 | if (run_count < 0) { | 2987 | if (run_count < 0) { |
| 2954 | pr_err("Run count must be a positive number\n"); | 2988 | pr_err("Run count must be a positive number\n"); |
| 2955 | parse_options_usage(stat_usage, stat_options, "r", 1); | 2989 | parse_options_usage(stat_usage, stat_options, "r", 1); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7a349fcd3864..ffdc2769ff9f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -123,14 +123,9 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) | |||
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | notes = symbol__annotation(sym); | 125 | notes = symbol__annotation(sym); |
| 126 | if (notes->src != NULL) { | ||
| 127 | pthread_mutex_lock(¬es->lock); | ||
| 128 | goto out_assign; | ||
| 129 | } | ||
| 130 | |||
| 131 | pthread_mutex_lock(¬es->lock); | 126 | pthread_mutex_lock(¬es->lock); |
| 132 | 127 | ||
| 133 | if (symbol__alloc_hist(sym) < 0) { | 128 | if (!symbol__hists(sym, top->evlist->nr_entries)) { |
| 134 | pthread_mutex_unlock(¬es->lock); | 129 | pthread_mutex_unlock(¬es->lock); |
| 135 | pr_err("Not enough memory for annotating '%s' symbol!\n", | 130 | pr_err("Not enough memory for annotating '%s' symbol!\n", |
| 136 | sym->name); | 131 | sym->name); |
| @@ -138,9 +133,8 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) | |||
| 138 | return err; | 133 | return err; |
| 139 | } | 134 | } |
| 140 | 135 | ||
| 141 | err = symbol__annotate(sym, map, evsel, 0, NULL); | 136 | err = symbol__annotate(sym, map, evsel, 0, &top->annotation_opts, NULL); |
| 142 | if (err == 0) { | 137 | if (err == 0) { |
| 143 | out_assign: | ||
| 144 | top->sym_filter_entry = he; | 138 | top->sym_filter_entry = he; |
| 145 | } else { | 139 | } else { |
| 146 | char msg[BUFSIZ]; | 140 | char msg[BUFSIZ]; |
| @@ -188,7 +182,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) | |||
| 188 | static void perf_top__record_precise_ip(struct perf_top *top, | 182 | static void perf_top__record_precise_ip(struct perf_top *top, |
| 189 | struct hist_entry *he, | 183 | struct hist_entry *he, |
| 190 | struct perf_sample *sample, | 184 | struct perf_sample *sample, |
| 191 | int counter, u64 ip) | 185 | struct perf_evsel *evsel, u64 ip) |
| 192 | { | 186 | { |
| 193 | struct annotation *notes; | 187 | struct annotation *notes; |
| 194 | struct symbol *sym = he->ms.sym; | 188 | struct symbol *sym = he->ms.sym; |
| @@ -204,7 +198,7 @@ static void perf_top__record_precise_ip(struct perf_top *top, | |||
| 204 | if (pthread_mutex_trylock(¬es->lock)) | 198 | if (pthread_mutex_trylock(¬es->lock)) |
| 205 | return; | 199 | return; |
| 206 | 200 | ||
| 207 | err = hist_entry__inc_addr_samples(he, sample, counter, ip); | 201 | err = hist_entry__inc_addr_samples(he, sample, evsel, ip); |
| 208 | 202 | ||
| 209 | pthread_mutex_unlock(¬es->lock); | 203 | pthread_mutex_unlock(¬es->lock); |
| 210 | 204 | ||
| @@ -249,10 +243,9 @@ static void perf_top__show_details(struct perf_top *top) | |||
| 249 | goto out_unlock; | 243 | goto out_unlock; |
| 250 | 244 | ||
| 251 | printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); | 245 | printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); |
| 252 | printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); | 246 | printf(" Events Pcnt (>=%d%%)\n", top->annotation_opts.min_pcnt); |
| 253 | 247 | ||
| 254 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, | 248 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, &top->annotation_opts); |
| 255 | 0, top->sym_pcnt_filter, top->print_entries, 4); | ||
| 256 | 249 | ||
| 257 | if (top->evlist->enabled) { | 250 | if (top->evlist->enabled) { |
| 258 | if (top->zero) | 251 | if (top->zero) |
| @@ -412,7 +405,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top) | |||
| 412 | 405 | ||
| 413 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); | 406 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); |
| 414 | 407 | ||
| 415 | fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter); | 408 | fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->annotation_opts.min_pcnt); |
| 416 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); | 409 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); |
| 417 | fprintf(stdout, "\t[S] stop annotation.\n"); | 410 | fprintf(stdout, "\t[S] stop annotation.\n"); |
| 418 | 411 | ||
| @@ -515,7 +508,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) | |||
| 515 | prompt_integer(&top->count_filter, "Enter display event count filter"); | 508 | prompt_integer(&top->count_filter, "Enter display event count filter"); |
| 516 | break; | 509 | break; |
| 517 | case 'F': | 510 | case 'F': |
| 518 | prompt_percent(&top->sym_pcnt_filter, | 511 | prompt_percent(&top->annotation_opts.min_pcnt, |
| 519 | "Enter details display event filter (percent)"); | 512 | "Enter details display event filter (percent)"); |
| 520 | break; | 513 | break; |
| 521 | case 'K': | 514 | case 'K': |
| @@ -613,7 +606,8 @@ static void *display_thread_tui(void *arg) | |||
| 613 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, | 606 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, |
| 614 | top->min_percent, | 607 | top->min_percent, |
| 615 | &top->session->header.env, | 608 | &top->session->header.env, |
| 616 | !top->record_opts.overwrite); | 609 | !top->record_opts.overwrite, |
| 610 | &top->annotation_opts); | ||
| 617 | 611 | ||
| 618 | done = 1; | 612 | done = 1; |
| 619 | return NULL; | 613 | return NULL; |
| @@ -691,7 +685,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, | |||
| 691 | struct perf_evsel *evsel = iter->evsel; | 685 | struct perf_evsel *evsel = iter->evsel; |
| 692 | 686 | ||
| 693 | if (perf_hpp_list.sym && single) | 687 | if (perf_hpp_list.sym && single) |
| 694 | perf_top__record_precise_ip(top, he, iter->sample, evsel->idx, al->addr); | 688 | perf_top__record_precise_ip(top, he, iter->sample, evsel, al->addr); |
| 695 | 689 | ||
| 696 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, | 690 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, |
| 697 | !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); | 691 | !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); |
| @@ -1083,8 +1077,9 @@ static int __cmd_top(struct perf_top *top) | |||
| 1083 | if (top->session == NULL) | 1077 | if (top->session == NULL) |
| 1084 | return -1; | 1078 | return -1; |
| 1085 | 1079 | ||
| 1086 | if (!objdump_path) { | 1080 | if (!top->annotation_opts.objdump_path) { |
| 1087 | ret = perf_env__lookup_objdump(&top->session->header.env); | 1081 | ret = perf_env__lookup_objdump(&top->session->header.env, |
| 1082 | &top->annotation_opts.objdump_path); | ||
| 1088 | if (ret) | 1083 | if (ret) |
| 1089 | goto out_delete; | 1084 | goto out_delete; |
| 1090 | } | 1085 | } |
| @@ -1265,7 +1260,7 @@ int cmd_top(int argc, const char **argv) | |||
| 1265 | .overwrite = 1, | 1260 | .overwrite = 1, |
| 1266 | }, | 1261 | }, |
| 1267 | .max_stack = sysctl__max_stack(), | 1262 | .max_stack = sysctl__max_stack(), |
| 1268 | .sym_pcnt_filter = 5, | 1263 | .annotation_opts = annotation__default_options, |
| 1269 | .nr_threads_synthesize = UINT_MAX, | 1264 | .nr_threads_synthesize = UINT_MAX, |
| 1270 | }; | 1265 | }; |
| 1271 | struct record_opts *opts = &top.record_opts; | 1266 | struct record_opts *opts = &top.record_opts; |
| @@ -1347,15 +1342,15 @@ int cmd_top(int argc, const char **argv) | |||
| 1347 | "only consider symbols in these comms"), | 1342 | "only consider symbols in these comms"), |
| 1348 | OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | 1343 | OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
| 1349 | "only consider these symbols"), | 1344 | "only consider these symbols"), |
| 1350 | OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, | 1345 | OPT_BOOLEAN(0, "source", &top.annotation_opts.annotate_src, |
| 1351 | "Interleave source code with assembly code (default)"), | 1346 | "Interleave source code with assembly code (default)"), |
| 1352 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | 1347 | OPT_BOOLEAN(0, "asm-raw", &top.annotation_opts.show_asm_raw, |
| 1353 | "Display raw encoding of assembly instructions (default)"), | 1348 | "Display raw encoding of assembly instructions (default)"), |
| 1354 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, | 1349 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, |
| 1355 | "Enable kernel symbol demangling"), | 1350 | "Enable kernel symbol demangling"), |
| 1356 | OPT_STRING(0, "objdump", &objdump_path, "path", | 1351 | OPT_STRING(0, "objdump", &top.annotation_opts.objdump_path, "path", |
| 1357 | "objdump binary to use for disassembly and annotations"), | 1352 | "objdump binary to use for disassembly and annotations"), |
| 1358 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1353 | OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style", |
| 1359 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 1354 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
| 1360 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), | 1355 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), |
| 1361 | OPT_CALLBACK(0, "percent-limit", &top, "percent", | 1356 | OPT_CALLBACK(0, "percent-limit", &top, "percent", |
| @@ -1391,6 +1386,9 @@ int cmd_top(int argc, const char **argv) | |||
| 1391 | if (status < 0) | 1386 | if (status < 0) |
| 1392 | return status; | 1387 | return status; |
| 1393 | 1388 | ||
| 1389 | top.annotation_opts.min_pcnt = 5; | ||
| 1390 | top.annotation_opts.context = 4; | ||
| 1391 | |||
| 1394 | top.evlist = perf_evlist__new(); | 1392 | top.evlist = perf_evlist__new(); |
| 1395 | if (top.evlist == NULL) | 1393 | if (top.evlist == NULL) |
| 1396 | return -ENOMEM; | 1394 | return -ENOMEM; |
| @@ -1468,8 +1466,6 @@ int cmd_top(int argc, const char **argv) | |||
| 1468 | goto out_delete_evlist; | 1466 | goto out_delete_evlist; |
| 1469 | } | 1467 | } |
| 1470 | 1468 | ||
| 1471 | symbol_conf.nr_events = top.evlist->nr_entries; | ||
| 1472 | |||
| 1473 | if (top.delay_secs < 1) | 1469 | if (top.delay_secs < 1) |
| 1474 | top.delay_secs = 1; | 1470 | top.delay_secs = 1; |
| 1475 | 1471 | ||
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 560aed7da36a..6a748eca2edb 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -2491,7 +2491,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
| 2491 | * to override an explicitely set --max-stack global setting. | 2491 | * to override an explicitely set --max-stack global setting. |
| 2492 | */ | 2492 | */ |
| 2493 | evlist__for_each_entry(evlist, evsel) { | 2493 | evlist__for_each_entry(evlist, evsel) { |
| 2494 | if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) && | 2494 | if (evsel__has_callchain(evsel) && |
| 2495 | evsel->attr.sample_max_stack == 0) | 2495 | evsel->attr.sample_max_stack == 0) |
| 2496 | evsel->attr.sample_max_stack = trace->max_stack; | 2496 | evsel->attr.sample_max_stack = trace->max_stack; |
| 2497 | } | 2497 | } |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 51c81509a315..a11cb006f968 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include "util/env.h" | 12 | #include "util/env.h" |
| 13 | #include <subcmd/exec-cmd.h> | 13 | #include <subcmd/exec-cmd.h> |
| 14 | #include "util/config.h" | 14 | #include "util/config.h" |
| 15 | #include "util/quote.h" | ||
| 16 | #include <subcmd/run-command.h> | 15 | #include <subcmd/run-command.h> |
| 17 | #include "util/parse-events.h" | 16 | #include "util/parse-events.h" |
| 18 | #include <subcmd/parse-options.h> | 17 | #include <subcmd/parse-options.h> |
diff --git a/tools/perf/scripts/python/bin/powerpc-hcalls-record b/tools/perf/scripts/python/bin/powerpc-hcalls-record new file mode 100644 index 000000000000..b7402aa9147d --- /dev/null +++ b/tools/perf/scripts/python/bin/powerpc-hcalls-record | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | perf record -e "{powerpc:hcall_entry,powerpc:hcall_exit}" $@ | ||
diff --git a/tools/perf/scripts/python/bin/powerpc-hcalls-report b/tools/perf/scripts/python/bin/powerpc-hcalls-report new file mode 100644 index 000000000000..dd32ad7465f6 --- /dev/null +++ b/tools/perf/scripts/python/bin/powerpc-hcalls-report | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/powerpc-hcalls.py | ||
diff --git a/tools/perf/scripts/python/powerpc-hcalls.py b/tools/perf/scripts/python/powerpc-hcalls.py new file mode 100644 index 000000000000..00e0e7476e55 --- /dev/null +++ b/tools/perf/scripts/python/powerpc-hcalls.py | |||
| @@ -0,0 +1,200 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | # | ||
| 3 | # Copyright (C) 2018 Ravi Bangoria, IBM Corporation | ||
| 4 | # | ||
| 5 | # Hypervisor call statisics | ||
| 6 | |||
| 7 | import os | ||
| 8 | import sys | ||
| 9 | |||
| 10 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | ||
| 11 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | ||
| 12 | |||
| 13 | from perf_trace_context import * | ||
| 14 | from Core import * | ||
| 15 | from Util import * | ||
| 16 | |||
| 17 | # output: { | ||
| 18 | # opcode: { | ||
| 19 | # 'min': minimum time nsec | ||
| 20 | # 'max': maximum time nsec | ||
| 21 | # 'time': average time nsec | ||
| 22 | # 'cnt': counter | ||
| 23 | # } ... | ||
| 24 | # } | ||
| 25 | output = {} | ||
| 26 | |||
| 27 | # d_enter: { | ||
| 28 | # cpu: { | ||
| 29 | # opcode: nsec | ||
| 30 | # } ... | ||
| 31 | # } | ||
| 32 | d_enter = {} | ||
| 33 | |||
| 34 | hcall_table = { | ||
| 35 | 4: 'H_REMOVE', | ||
| 36 | 8: 'H_ENTER', | ||
| 37 | 12: 'H_READ', | ||
| 38 | 16: 'H_CLEAR_MOD', | ||
| 39 | 20: 'H_CLEAR_REF', | ||
| 40 | 24: 'H_PROTECT', | ||
| 41 | 28: 'H_GET_TCE', | ||
| 42 | 32: 'H_PUT_TCE', | ||
| 43 | 36: 'H_SET_SPRG0', | ||
| 44 | 40: 'H_SET_DABR', | ||
| 45 | 44: 'H_PAGE_INIT', | ||
| 46 | 48: 'H_SET_ASR', | ||
| 47 | 52: 'H_ASR_ON', | ||
| 48 | 56: 'H_ASR_OFF', | ||
| 49 | 60: 'H_LOGICAL_CI_LOAD', | ||
| 50 | 64: 'H_LOGICAL_CI_STORE', | ||
| 51 | 68: 'H_LOGICAL_CACHE_LOAD', | ||
| 52 | 72: 'H_LOGICAL_CACHE_STORE', | ||
| 53 | 76: 'H_LOGICAL_ICBI', | ||
| 54 | 80: 'H_LOGICAL_DCBF', | ||
| 55 | 84: 'H_GET_TERM_CHAR', | ||
| 56 | 88: 'H_PUT_TERM_CHAR', | ||
| 57 | 92: 'H_REAL_TO_LOGICAL', | ||
| 58 | 96: 'H_HYPERVISOR_DATA', | ||
| 59 | 100: 'H_EOI', | ||
| 60 | 104: 'H_CPPR', | ||
| 61 | 108: 'H_IPI', | ||
| 62 | 112: 'H_IPOLL', | ||
| 63 | 116: 'H_XIRR', | ||
| 64 | 120: 'H_MIGRATE_DMA', | ||
| 65 | 124: 'H_PERFMON', | ||
| 66 | 220: 'H_REGISTER_VPA', | ||
| 67 | 224: 'H_CEDE', | ||
| 68 | 228: 'H_CONFER', | ||
| 69 | 232: 'H_PROD', | ||
| 70 | 236: 'H_GET_PPP', | ||
| 71 | 240: 'H_SET_PPP', | ||
| 72 | 244: 'H_PURR', | ||
| 73 | 248: 'H_PIC', | ||
| 74 | 252: 'H_REG_CRQ', | ||
| 75 | 256: 'H_FREE_CRQ', | ||
| 76 | 260: 'H_VIO_SIGNAL', | ||
| 77 | 264: 'H_SEND_CRQ', | ||
| 78 | 272: 'H_COPY_RDMA', | ||
| 79 | 276: 'H_REGISTER_LOGICAL_LAN', | ||
| 80 | 280: 'H_FREE_LOGICAL_LAN', | ||
| 81 | 284: 'H_ADD_LOGICAL_LAN_BUFFER', | ||
| 82 | 288: 'H_SEND_LOGICAL_LAN', | ||
| 83 | 292: 'H_BULK_REMOVE', | ||
| 84 | 304: 'H_MULTICAST_CTRL', | ||
| 85 | 308: 'H_SET_XDABR', | ||
| 86 | 312: 'H_STUFF_TCE', | ||
| 87 | 316: 'H_PUT_TCE_INDIRECT', | ||
| 88 | 332: 'H_CHANGE_LOGICAL_LAN_MAC', | ||
| 89 | 336: 'H_VTERM_PARTNER_INFO', | ||
| 90 | 340: 'H_REGISTER_VTERM', | ||
| 91 | 344: 'H_FREE_VTERM', | ||
| 92 | 348: 'H_RESET_EVENTS', | ||
| 93 | 352: 'H_ALLOC_RESOURCE', | ||
| 94 | 356: 'H_FREE_RESOURCE', | ||
| 95 | 360: 'H_MODIFY_QP', | ||
| 96 | 364: 'H_QUERY_QP', | ||
| 97 | 368: 'H_REREGISTER_PMR', | ||
| 98 | 372: 'H_REGISTER_SMR', | ||
| 99 | 376: 'H_QUERY_MR', | ||
| 100 | 380: 'H_QUERY_MW', | ||
| 101 | 384: 'H_QUERY_HCA', | ||
| 102 | 388: 'H_QUERY_PORT', | ||
| 103 | 392: 'H_MODIFY_PORT', | ||
| 104 | 396: 'H_DEFINE_AQP1', | ||
| 105 | 400: 'H_GET_TRACE_BUFFER', | ||
| 106 | 404: 'H_DEFINE_AQP0', | ||
| 107 | 408: 'H_RESIZE_MR', | ||
| 108 | 412: 'H_ATTACH_MCQP', | ||
| 109 | 416: 'H_DETACH_MCQP', | ||
| 110 | 420: 'H_CREATE_RPT', | ||
| 111 | 424: 'H_REMOVE_RPT', | ||
| 112 | 428: 'H_REGISTER_RPAGES', | ||
| 113 | 432: 'H_DISABLE_AND_GETC', | ||
| 114 | 436: 'H_ERROR_DATA', | ||
| 115 | 440: 'H_GET_HCA_INFO', | ||
| 116 | 444: 'H_GET_PERF_COUNT', | ||
| 117 | 448: 'H_MANAGE_TRACE', | ||
| 118 | 468: 'H_FREE_LOGICAL_LAN_BUFFER', | ||
| 119 | 472: 'H_POLL_PENDING', | ||
| 120 | 484: 'H_QUERY_INT_STATE', | ||
| 121 | 580: 'H_ILLAN_ATTRIBUTES', | ||
| 122 | 592: 'H_MODIFY_HEA_QP', | ||
| 123 | 596: 'H_QUERY_HEA_QP', | ||
| 124 | 600: 'H_QUERY_HEA', | ||
| 125 | 604: 'H_QUERY_HEA_PORT', | ||
| 126 | 608: 'H_MODIFY_HEA_PORT', | ||
| 127 | 612: 'H_REG_BCMC', | ||
| 128 | 616: 'H_DEREG_BCMC', | ||
| 129 | 620: 'H_REGISTER_HEA_RPAGES', | ||
| 130 | 624: 'H_DISABLE_AND_GET_HEA', | ||
| 131 | 628: 'H_GET_HEA_INFO', | ||
| 132 | 632: 'H_ALLOC_HEA_RESOURCE', | ||
| 133 | 644: 'H_ADD_CONN', | ||
| 134 | 648: 'H_DEL_CONN', | ||
| 135 | 664: 'H_JOIN', | ||
| 136 | 676: 'H_VASI_STATE', | ||
| 137 | 688: 'H_ENABLE_CRQ', | ||
| 138 | 696: 'H_GET_EM_PARMS', | ||
| 139 | 720: 'H_SET_MPP', | ||
| 140 | 724: 'H_GET_MPP', | ||
| 141 | 748: 'H_HOME_NODE_ASSOCIATIVITY', | ||
| 142 | 756: 'H_BEST_ENERGY', | ||
| 143 | 764: 'H_XIRR_X', | ||
| 144 | 768: 'H_RANDOM', | ||
| 145 | 772: 'H_COP', | ||
| 146 | 788: 'H_GET_MPP_X', | ||
| 147 | 796: 'H_SET_MODE', | ||
| 148 | 61440: 'H_RTAS', | ||
| 149 | } | ||
| 150 | |||
| 151 | def hcall_table_lookup(opcode): | ||
| 152 | if (hcall_table.has_key(opcode)): | ||
| 153 | return hcall_table[opcode] | ||
| 154 | else: | ||
| 155 | return opcode | ||
| 156 | |||
| 157 | print_ptrn = '%-28s%10s%10s%10s%10s' | ||
| 158 | |||
| 159 | def trace_end(): | ||
| 160 | print print_ptrn % ('hcall', 'count', 'min(ns)', 'max(ns)', 'avg(ns)') | ||
| 161 | print '-' * 68 | ||
| 162 | for opcode in output: | ||
| 163 | h_name = hcall_table_lookup(opcode) | ||
| 164 | time = output[opcode]['time'] | ||
| 165 | cnt = output[opcode]['cnt'] | ||
| 166 | min_t = output[opcode]['min'] | ||
| 167 | max_t = output[opcode]['max'] | ||
| 168 | |||
| 169 | print print_ptrn % (h_name, cnt, min_t, max_t, time/cnt) | ||
| 170 | |||
| 171 | def powerpc__hcall_exit(name, context, cpu, sec, nsec, pid, comm, callchain, | ||
| 172 | opcode, retval): | ||
| 173 | if (d_enter.has_key(cpu) and d_enter[cpu].has_key(opcode)): | ||
| 174 | diff = nsecs(sec, nsec) - d_enter[cpu][opcode] | ||
| 175 | |||
| 176 | if (output.has_key(opcode)): | ||
| 177 | output[opcode]['time'] += diff | ||
| 178 | output[opcode]['cnt'] += 1 | ||
| 179 | if (output[opcode]['min'] > diff): | ||
| 180 | output[opcode]['min'] = diff | ||
| 181 | if (output[opcode]['max'] < diff): | ||
| 182 | output[opcode]['max'] = diff | ||
| 183 | else: | ||
| 184 | output[opcode] = { | ||
| 185 | 'time': diff, | ||
| 186 | 'cnt': 1, | ||
| 187 | 'min': diff, | ||
| 188 | 'max': diff, | ||
| 189 | } | ||
| 190 | |||
| 191 | del d_enter[cpu][opcode] | ||
| 192 | # else: | ||
| 193 | # print "Can't find matching hcall_enter event. Ignoring sample" | ||
| 194 | |||
| 195 | def powerpc__hcall_entry(event_name, context, cpu, sec, nsec, pid, comm, | ||
| 196 | callchain, opcode): | ||
| 197 | if (d_enter.has_key(cpu)): | ||
| 198 | d_enter[cpu][opcode] = nsecs(sec, nsec) | ||
| 199 | else: | ||
| 200 | d_enter[cpu] = {opcode: nsecs(sec, nsec)} | ||
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index afa4ce21ba7c..4892bd2dc33e 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
| @@ -560,6 +560,7 @@ static int do_test_code_reading(bool try_kcore) | |||
| 560 | pid = getpid(); | 560 | pid = getpid(); |
| 561 | 561 | ||
| 562 | machine = machine__new_host(); | 562 | machine = machine__new_host(); |
| 563 | machine->env = &perf_env; | ||
| 563 | 564 | ||
| 564 | ret = machine__create_kernel_maps(machine); | 565 | ret = machine__create_kernel_maps(machine); |
| 565 | if (ret < 0) { | 566 | if (ret < 0) { |
diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c index 8e57d46109de..148dd31cc201 100644 --- a/tools/perf/tests/kmod-path.c +++ b/tools/perf/tests/kmod-path.c | |||
| @@ -127,6 +127,22 @@ int test__kmod_path__parse(struct test *t __maybe_unused, int subtest __maybe_un | |||
| 127 | M("[vdso]", PERF_RECORD_MISC_KERNEL, false); | 127 | M("[vdso]", PERF_RECORD_MISC_KERNEL, false); |
| 128 | M("[vdso]", PERF_RECORD_MISC_USER, false); | 128 | M("[vdso]", PERF_RECORD_MISC_USER, false); |
| 129 | 129 | ||
| 130 | T("[vdso32]", true , true , false, false, "[vdso32]", NULL); | ||
| 131 | T("[vdso32]", false , true , false, false, NULL , NULL); | ||
| 132 | T("[vdso32]", true , false , false, false, "[vdso32]", NULL); | ||
| 133 | T("[vdso32]", false , false , false, false, NULL , NULL); | ||
| 134 | M("[vdso32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); | ||
| 135 | M("[vdso32]", PERF_RECORD_MISC_KERNEL, false); | ||
| 136 | M("[vdso32]", PERF_RECORD_MISC_USER, false); | ||
| 137 | |||
| 138 | T("[vdsox32]", true , true , false, false, "[vdsox32]", NULL); | ||
| 139 | T("[vdsox32]", false , true , false, false, NULL , NULL); | ||
| 140 | T("[vdsox32]", true , false , false, false, "[vdsox32]", NULL); | ||
| 141 | T("[vdsox32]", false , false , false, false, NULL , NULL); | ||
| 142 | M("[vdsox32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); | ||
| 143 | M("[vdsox32]", PERF_RECORD_MISC_KERNEL, false); | ||
| 144 | M("[vdsox32]", PERF_RECORD_MISC_USER, false); | ||
| 145 | |||
| 130 | /* path alloc_name alloc_ext kmod comp name ext */ | 146 | /* path alloc_name alloc_ext kmod comp name ext */ |
| 131 | T("[vsyscall]", true , true , false, false, "[vsyscall]", NULL); | 147 | T("[vsyscall]", true , true , false, false, "[vsyscall]", NULL); |
| 132 | T("[vsyscall]", false , true , false, false, NULL , NULL); | 148 | T("[vsyscall]", false , true , false, false, NULL , NULL); |
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index b9ebe15afb13..61211918bfba 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
| @@ -499,7 +499,7 @@ static int test__checkevent_pmu_partial_time_callgraph(struct perf_evlist *evlis | |||
| 499 | * while this test executes only parse events method. | 499 | * while this test executes only parse events method. |
| 500 | */ | 500 | */ |
| 501 | TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); | 501 | TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); |
| 502 | TEST_ASSERT_VAL("wrong callgraph", !(PERF_SAMPLE_CALLCHAIN & evsel->attr.sample_type)); | 502 | TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel)); |
| 503 | TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); | 503 | TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); |
| 504 | 504 | ||
| 505 | /* cpu/config=2,call-graph=no,time=0,period=2000/ */ | 505 | /* cpu/config=2,call-graph=no,time=0,period=2000/ */ |
| @@ -512,7 +512,7 @@ static int test__checkevent_pmu_partial_time_callgraph(struct perf_evlist *evlis | |||
| 512 | * while this test executes only parse events method. | 512 | * while this test executes only parse events method. |
| 513 | */ | 513 | */ |
| 514 | TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); | 514 | TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); |
| 515 | TEST_ASSERT_VAL("wrong callgraph", !(PERF_SAMPLE_CALLCHAIN & evsel->attr.sample_type)); | 515 | TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel)); |
| 516 | TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); | 516 | TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); |
| 517 | 517 | ||
| 518 | return 0; | 518 | return 0; |
| @@ -1309,6 +1309,11 @@ static int test__checkevent_config_cache(struct perf_evlist *evlist) | |||
| 1309 | return 0; | 1309 | return 0; |
| 1310 | } | 1310 | } |
| 1311 | 1311 | ||
| 1312 | static bool test__intel_pt_valid(void) | ||
| 1313 | { | ||
| 1314 | return !!perf_pmu__find("intel_pt"); | ||
| 1315 | } | ||
| 1316 | |||
| 1312 | static int test__intel_pt(struct perf_evlist *evlist) | 1317 | static int test__intel_pt(struct perf_evlist *evlist) |
| 1313 | { | 1318 | { |
| 1314 | struct perf_evsel *evsel = perf_evlist__first(evlist); | 1319 | struct perf_evsel *evsel = perf_evlist__first(evlist); |
| @@ -1375,6 +1380,7 @@ struct evlist_test { | |||
| 1375 | const char *name; | 1380 | const char *name; |
| 1376 | __u32 type; | 1381 | __u32 type; |
| 1377 | const int id; | 1382 | const int id; |
| 1383 | bool (*valid)(void); | ||
| 1378 | int (*check)(struct perf_evlist *evlist); | 1384 | int (*check)(struct perf_evlist *evlist); |
| 1379 | }; | 1385 | }; |
| 1380 | 1386 | ||
| @@ -1648,6 +1654,7 @@ static struct evlist_test test__events[] = { | |||
| 1648 | }, | 1654 | }, |
| 1649 | { | 1655 | { |
| 1650 | .name = "intel_pt//u", | 1656 | .name = "intel_pt//u", |
| 1657 | .valid = test__intel_pt_valid, | ||
| 1651 | .check = test__intel_pt, | 1658 | .check = test__intel_pt, |
| 1652 | .id = 52, | 1659 | .id = 52, |
| 1653 | }, | 1660 | }, |
| @@ -1686,17 +1693,24 @@ static struct terms_test test__terms[] = { | |||
| 1686 | 1693 | ||
| 1687 | static int test_event(struct evlist_test *e) | 1694 | static int test_event(struct evlist_test *e) |
| 1688 | { | 1695 | { |
| 1696 | struct parse_events_error err = { .idx = 0, }; | ||
| 1689 | struct perf_evlist *evlist; | 1697 | struct perf_evlist *evlist; |
| 1690 | int ret; | 1698 | int ret; |
| 1691 | 1699 | ||
| 1700 | if (e->valid && !e->valid()) { | ||
| 1701 | pr_debug("... SKIP"); | ||
| 1702 | return 0; | ||
| 1703 | } | ||
| 1704 | |||
| 1692 | evlist = perf_evlist__new(); | 1705 | evlist = perf_evlist__new(); |
| 1693 | if (evlist == NULL) | 1706 | if (evlist == NULL) |
| 1694 | return -ENOMEM; | 1707 | return -ENOMEM; |
| 1695 | 1708 | ||
| 1696 | ret = parse_events(evlist, e->name, NULL); | 1709 | ret = parse_events(evlist, e->name, &err); |
| 1697 | if (ret) { | 1710 | if (ret) { |
| 1698 | pr_debug("failed to parse event '%s', err %d\n", | 1711 | pr_debug("failed to parse event '%s', err %d, str '%s'\n", |
| 1699 | e->name, ret); | 1712 | e->name, ret, err.str); |
| 1713 | parse_events_print_error(&err, e->name); | ||
| 1700 | } else { | 1714 | } else { |
| 1701 | ret = e->check(evlist); | 1715 | ret = e->check(evlist); |
| 1702 | } | 1716 | } |
| @@ -1714,10 +1728,11 @@ static int test_events(struct evlist_test *events, unsigned cnt) | |||
| 1714 | for (i = 0; i < cnt; i++) { | 1728 | for (i = 0; i < cnt; i++) { |
| 1715 | struct evlist_test *e = &events[i]; | 1729 | struct evlist_test *e = &events[i]; |
| 1716 | 1730 | ||
| 1717 | pr_debug("running test %d '%s'\n", e->id, e->name); | 1731 | pr_debug("running test %d '%s'", e->id, e->name); |
| 1718 | ret1 = test_event(e); | 1732 | ret1 = test_event(e); |
| 1719 | if (ret1) | 1733 | if (ret1) |
| 1720 | ret2 = ret1; | 1734 | ret2 = ret1; |
| 1735 | pr_debug("\n"); | ||
| 1721 | } | 1736 | } |
| 1722 | 1737 | ||
| 1723 | return ret2; | 1738 | return ret2; |
| @@ -1799,7 +1814,7 @@ static int test_pmu_events(void) | |||
| 1799 | } | 1814 | } |
| 1800 | 1815 | ||
| 1801 | while (!ret && (ent = readdir(dir))) { | 1816 | while (!ret && (ent = readdir(dir))) { |
| 1802 | struct evlist_test e; | 1817 | struct evlist_test e = { .id = 0, }; |
| 1803 | char name[2 * NAME_MAX + 1 + 12 + 3]; | 1818 | char name[2 * NAME_MAX + 1 + 12 + 3]; |
| 1804 | 1819 | ||
| 1805 | /* Names containing . are special and cannot be used directly */ | 1820 | /* Names containing . are special and cannot be used directly */ |
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c index 5d2df65ada6a..40ab72149ce1 100644 --- a/tools/perf/tests/python-use.c +++ b/tools/perf/tests/python-use.c | |||
| @@ -7,8 +7,7 @@ | |||
| 7 | #include <stdlib.h> | 7 | #include <stdlib.h> |
| 8 | #include <linux/compiler.h> | 8 | #include <linux/compiler.h> |
| 9 | #include "tests.h" | 9 | #include "tests.h" |
| 10 | 10 | #include "util/debug.h" | |
| 11 | extern int verbose; | ||
| 12 | 11 | ||
| 13 | int test__python_use(struct test *test __maybe_unused, int subtest __maybe_unused) | 12 | int test__python_use(struct test *test __maybe_unused, int subtest __maybe_unused) |
| 14 | { | 13 | { |
diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index 650b208f700f..263057039693 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | . $(dirname $0)/lib/probe.sh | 11 | . $(dirname $0)/lib/probe.sh |
| 12 | 12 | ||
| 13 | libc=$(grep -w libc /proc/self/maps | head -1 | sed -r 's/.*[[:space:]](\/.*)/\1/g') | 13 | libc=$(grep -w libc /proc/self/maps | head -1 | sed -r 's/.*[[:space:]](\/.*)/\1/g') |
| 14 | nm -g $libc 2>/dev/null | fgrep -q inet_pton || exit 254 | 14 | nm -Dg $libc 2>/dev/null | fgrep -q inet_pton || exit 254 |
| 15 | 15 | ||
| 16 | trace_libc_inet_pton_backtrace() { | 16 | trace_libc_inet_pton_backtrace() { |
| 17 | idx=0 | 17 | idx=0 |
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index 40e30a26b23c..9497d02f69e6 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c | |||
| @@ -45,6 +45,7 @@ static int session_write_header(char *path) | |||
| 45 | 45 | ||
| 46 | perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); | 46 | perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); |
| 47 | perf_header__set_feat(&session->header, HEADER_NRCPUS); | 47 | perf_header__set_feat(&session->header, HEADER_NRCPUS); |
| 48 | perf_header__set_feat(&session->header, HEADER_ARCH); | ||
| 48 | 49 | ||
| 49 | session->header.data_size += DATA_SIZE; | 50 | session->header.data_size += DATA_SIZE; |
| 50 | 51 | ||
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 8be40fa903aa..3b4f1c10ff57 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
| @@ -29,6 +29,7 @@ struct annotate_browser { | |||
| 29 | struct rb_node *curr_hot; | 29 | struct rb_node *curr_hot; |
| 30 | struct annotation_line *selection; | 30 | struct annotation_line *selection; |
| 31 | struct arch *arch; | 31 | struct arch *arch; |
| 32 | struct annotation_options *opts; | ||
| 32 | bool searching_backwards; | 33 | bool searching_backwards; |
| 33 | char search_bf[128]; | 34 | char search_bf[128]; |
| 34 | }; | 35 | }; |
| @@ -410,7 +411,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, | |||
| 410 | notes = symbol__annotation(dl->ops.target.sym); | 411 | notes = symbol__annotation(dl->ops.target.sym); |
| 411 | pthread_mutex_lock(¬es->lock); | 412 | pthread_mutex_lock(¬es->lock); |
| 412 | 413 | ||
| 413 | if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) { | 414 | if (!symbol__hists(dl->ops.target.sym, evsel->evlist->nr_entries)) { |
| 414 | pthread_mutex_unlock(¬es->lock); | 415 | pthread_mutex_unlock(¬es->lock); |
| 415 | ui__warning("Not enough memory for annotating '%s' symbol!\n", | 416 | ui__warning("Not enough memory for annotating '%s' symbol!\n", |
| 416 | dl->ops.target.sym->name); | 417 | dl->ops.target.sym->name); |
| @@ -418,7 +419,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, | |||
| 418 | } | 419 | } |
| 419 | 420 | ||
| 420 | pthread_mutex_unlock(¬es->lock); | 421 | pthread_mutex_unlock(¬es->lock); |
| 421 | symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt); | 422 | symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts); |
| 422 | sym_title(ms->sym, ms->map, title, sizeof(title)); | 423 | sym_title(ms->sym, ms->map, title, sizeof(title)); |
| 423 | ui_browser__show_title(&browser->b, title); | 424 | ui_browser__show_title(&browser->b, title); |
| 424 | return true; | 425 | return true; |
| @@ -817,24 +818,27 @@ out: | |||
| 817 | } | 818 | } |
| 818 | 819 | ||
| 819 | int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, | 820 | int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, |
| 820 | struct hist_browser_timer *hbt) | 821 | struct hist_browser_timer *hbt, |
| 822 | struct annotation_options *opts) | ||
| 821 | { | 823 | { |
| 822 | return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt); | 824 | return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts); |
| 823 | } | 825 | } |
| 824 | 826 | ||
| 825 | int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, | 827 | int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, |
| 826 | struct hist_browser_timer *hbt) | 828 | struct hist_browser_timer *hbt, |
| 829 | struct annotation_options *opts) | ||
| 827 | { | 830 | { |
| 828 | /* reset abort key so that it can get Ctrl-C as a key */ | 831 | /* reset abort key so that it can get Ctrl-C as a key */ |
| 829 | SLang_reset_tty(); | 832 | SLang_reset_tty(); |
| 830 | SLang_init_tty(0, 0, 0); | 833 | SLang_init_tty(0, 0, 0); |
| 831 | 834 | ||
| 832 | return map_symbol__tui_annotate(&he->ms, evsel, hbt); | 835 | return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts); |
| 833 | } | 836 | } |
| 834 | 837 | ||
| 835 | int symbol__tui_annotate(struct symbol *sym, struct map *map, | 838 | int symbol__tui_annotate(struct symbol *sym, struct map *map, |
| 836 | struct perf_evsel *evsel, | 839 | struct perf_evsel *evsel, |
| 837 | struct hist_browser_timer *hbt) | 840 | struct hist_browser_timer *hbt, |
| 841 | struct annotation_options *opts) | ||
| 838 | { | 842 | { |
| 839 | struct annotation *notes = symbol__annotation(sym); | 843 | struct annotation *notes = symbol__annotation(sym); |
| 840 | struct map_symbol ms = { | 844 | struct map_symbol ms = { |
| @@ -851,6 +855,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, | |||
| 851 | .priv = &ms, | 855 | .priv = &ms, |
| 852 | .use_navkeypressed = true, | 856 | .use_navkeypressed = true, |
| 853 | }, | 857 | }, |
| 858 | .opts = opts, | ||
| 854 | }; | 859 | }; |
| 855 | int ret = -1, err; | 860 | int ret = -1, err; |
| 856 | 861 | ||
| @@ -860,7 +865,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, | |||
| 860 | if (map->dso->annotate_warned) | 865 | if (map->dso->annotate_warned) |
| 861 | return -1; | 866 | return -1; |
| 862 | 867 | ||
| 863 | err = symbol__annotate2(sym, map, evsel, &annotation__default_options, &browser.arch); | 868 | err = symbol__annotate2(sym, map, evsel, opts, &browser.arch); |
| 864 | if (err) { | 869 | if (err) { |
| 865 | char msg[BUFSIZ]; | 870 | char msg[BUFSIZ]; |
| 866 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); | 871 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e5f247247daa..a96f62ca984a 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
| @@ -1231,6 +1231,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
| 1231 | int width = browser->b.width; | 1231 | int width = browser->b.width; |
| 1232 | char folded_sign = ' '; | 1232 | char folded_sign = ' '; |
| 1233 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); | 1233 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); |
| 1234 | bool use_callchain = hist_entry__has_callchains(entry) && symbol_conf.use_callchain; | ||
| 1234 | off_t row_offset = entry->row_offset; | 1235 | off_t row_offset = entry->row_offset; |
| 1235 | bool first = true; | 1236 | bool first = true; |
| 1236 | struct perf_hpp_fmt *fmt; | 1237 | struct perf_hpp_fmt *fmt; |
| @@ -1240,7 +1241,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
| 1240 | browser->selection = &entry->ms; | 1241 | browser->selection = &entry->ms; |
| 1241 | } | 1242 | } |
| 1242 | 1243 | ||
| 1243 | if (symbol_conf.use_callchain) { | 1244 | if (use_callchain) { |
| 1244 | hist_entry__init_have_children(entry); | 1245 | hist_entry__init_have_children(entry); |
| 1245 | folded_sign = hist_entry__folded(entry); | 1246 | folded_sign = hist_entry__folded(entry); |
| 1246 | } | 1247 | } |
| @@ -1276,7 +1277,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
| 1276 | } | 1277 | } |
| 1277 | 1278 | ||
| 1278 | if (first) { | 1279 | if (first) { |
| 1279 | if (symbol_conf.use_callchain) { | 1280 | if (use_callchain) { |
| 1280 | ui_browser__printf(&browser->b, "%c ", folded_sign); | 1281 | ui_browser__printf(&browser->b, "%c ", folded_sign); |
| 1281 | width -= 2; | 1282 | width -= 2; |
| 1282 | } | 1283 | } |
| @@ -1583,7 +1584,7 @@ hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, | |||
| 1583 | int column = 0; | 1584 | int column = 0; |
| 1584 | int span = 0; | 1585 | int span = 0; |
| 1585 | 1586 | ||
| 1586 | if (symbol_conf.use_callchain) { | 1587 | if (hists__has_callchains(hists) && symbol_conf.use_callchain) { |
| 1587 | ret = scnprintf(buf, size, " "); | 1588 | ret = scnprintf(buf, size, " "); |
| 1588 | if (advance_hpp_check(&dummy_hpp, ret)) | 1589 | if (advance_hpp_check(&dummy_hpp, ret)) |
| 1589 | return ret; | 1590 | return ret; |
| @@ -1987,7 +1988,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, | |||
| 1987 | bool first = true; | 1988 | bool first = true; |
| 1988 | int ret; | 1989 | int ret; |
| 1989 | 1990 | ||
| 1990 | if (symbol_conf.use_callchain) { | 1991 | if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) { |
| 1991 | folded_sign = hist_entry__folded(he); | 1992 | folded_sign = hist_entry__folded(he); |
| 1992 | printed += fprintf(fp, "%c ", folded_sign); | 1993 | printed += fprintf(fp, "%c ", folded_sign); |
| 1993 | } | 1994 | } |
| @@ -2175,7 +2176,8 @@ struct hist_browser *hist_browser__new(struct hists *hists) | |||
| 2175 | static struct hist_browser * | 2176 | static struct hist_browser * |
| 2176 | perf_evsel_browser__new(struct perf_evsel *evsel, | 2177 | perf_evsel_browser__new(struct perf_evsel *evsel, |
| 2177 | struct hist_browser_timer *hbt, | 2178 | struct hist_browser_timer *hbt, |
| 2178 | struct perf_env *env) | 2179 | struct perf_env *env, |
| 2180 | struct annotation_options *annotation_opts) | ||
| 2179 | { | 2181 | { |
| 2180 | struct hist_browser *browser = hist_browser__new(evsel__hists(evsel)); | 2182 | struct hist_browser *browser = hist_browser__new(evsel__hists(evsel)); |
| 2181 | 2183 | ||
| @@ -2183,6 +2185,7 @@ perf_evsel_browser__new(struct perf_evsel *evsel, | |||
| 2183 | browser->hbt = hbt; | 2185 | browser->hbt = hbt; |
| 2184 | browser->env = env; | 2186 | browser->env = env; |
| 2185 | browser->title = hists_browser__scnprintf_title; | 2187 | browser->title = hists_browser__scnprintf_title; |
| 2188 | browser->annotation_opts = annotation_opts; | ||
| 2186 | } | 2189 | } |
| 2187 | return browser; | 2190 | return browser; |
| 2188 | } | 2191 | } |
| @@ -2336,7 +2339,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) | |||
| 2336 | struct hist_entry *he; | 2339 | struct hist_entry *he; |
| 2337 | int err; | 2340 | int err; |
| 2338 | 2341 | ||
| 2339 | if (!objdump_path && perf_env__lookup_objdump(browser->env)) | 2342 | if (!browser->annotation_opts->objdump_path && |
| 2343 | perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path)) | ||
| 2340 | return 0; | 2344 | return 0; |
| 2341 | 2345 | ||
| 2342 | notes = symbol__annotation(act->ms.sym); | 2346 | notes = symbol__annotation(act->ms.sym); |
| @@ -2344,7 +2348,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) | |||
| 2344 | return 0; | 2348 | return 0; |
| 2345 | 2349 | ||
| 2346 | evsel = hists_to_evsel(browser->hists); | 2350 | evsel = hists_to_evsel(browser->hists); |
| 2347 | err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); | 2351 | err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt, |
| 2352 | browser->annotation_opts); | ||
| 2348 | he = hist_browser__selected_entry(browser); | 2353 | he = hist_browser__selected_entry(browser); |
| 2349 | /* | 2354 | /* |
| 2350 | * offer option to annotate the other branch source or target | 2355 | * offer option to annotate the other branch source or target |
| @@ -2667,7 +2672,7 @@ static void hist_browser__update_percent_limit(struct hist_browser *hb, | |||
| 2667 | he->nr_rows = 0; | 2672 | he->nr_rows = 0; |
| 2668 | } | 2673 | } |
| 2669 | 2674 | ||
| 2670 | if (!he->leaf || !symbol_conf.use_callchain) | 2675 | if (!he->leaf || !hist_entry__has_callchains(he) || !symbol_conf.use_callchain) |
| 2671 | goto next; | 2676 | goto next; |
| 2672 | 2677 | ||
| 2673 | if (callchain_param.mode == CHAIN_GRAPH_REL) { | 2678 | if (callchain_param.mode == CHAIN_GRAPH_REL) { |
| @@ -2697,10 +2702,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
| 2697 | struct hist_browser_timer *hbt, | 2702 | struct hist_browser_timer *hbt, |
| 2698 | float min_pcnt, | 2703 | float min_pcnt, |
| 2699 | struct perf_env *env, | 2704 | struct perf_env *env, |
| 2700 | bool warn_lost_event) | 2705 | bool warn_lost_event, |
| 2706 | struct annotation_options *annotation_opts) | ||
| 2701 | { | 2707 | { |
| 2702 | struct hists *hists = evsel__hists(evsel); | 2708 | struct hists *hists = evsel__hists(evsel); |
| 2703 | struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); | 2709 | struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts); |
| 2704 | struct branch_info *bi; | 2710 | struct branch_info *bi; |
| 2705 | #define MAX_OPTIONS 16 | 2711 | #define MAX_OPTIONS 16 |
| 2706 | char *options[MAX_OPTIONS]; | 2712 | char *options[MAX_OPTIONS]; |
| @@ -3062,6 +3068,7 @@ out: | |||
| 3062 | struct perf_evsel_menu { | 3068 | struct perf_evsel_menu { |
| 3063 | struct ui_browser b; | 3069 | struct ui_browser b; |
| 3064 | struct perf_evsel *selection; | 3070 | struct perf_evsel *selection; |
| 3071 | struct annotation_options *annotation_opts; | ||
| 3065 | bool lost_events, lost_events_warned; | 3072 | bool lost_events, lost_events_warned; |
| 3066 | float min_pcnt; | 3073 | float min_pcnt; |
| 3067 | struct perf_env *env; | 3074 | struct perf_env *env; |
| @@ -3163,7 +3170,8 @@ browse_hists: | |||
| 3163 | true, hbt, | 3170 | true, hbt, |
| 3164 | menu->min_pcnt, | 3171 | menu->min_pcnt, |
| 3165 | menu->env, | 3172 | menu->env, |
| 3166 | warn_lost_event); | 3173 | warn_lost_event, |
| 3174 | menu->annotation_opts); | ||
| 3167 | ui_browser__show_title(&menu->b, title); | 3175 | ui_browser__show_title(&menu->b, title); |
| 3168 | switch (key) { | 3176 | switch (key) { |
| 3169 | case K_TAB: | 3177 | case K_TAB: |
| @@ -3222,7 +3230,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
| 3222 | struct hist_browser_timer *hbt, | 3230 | struct hist_browser_timer *hbt, |
| 3223 | float min_pcnt, | 3231 | float min_pcnt, |
| 3224 | struct perf_env *env, | 3232 | struct perf_env *env, |
| 3225 | bool warn_lost_event) | 3233 | bool warn_lost_event, |
| 3234 | struct annotation_options *annotation_opts) | ||
| 3226 | { | 3235 | { |
| 3227 | struct perf_evsel *pos; | 3236 | struct perf_evsel *pos; |
| 3228 | struct perf_evsel_menu menu = { | 3237 | struct perf_evsel_menu menu = { |
| @@ -3237,6 +3246,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
| 3237 | }, | 3246 | }, |
| 3238 | .min_pcnt = min_pcnt, | 3247 | .min_pcnt = min_pcnt, |
| 3239 | .env = env, | 3248 | .env = env, |
| 3249 | .annotation_opts = annotation_opts, | ||
| 3240 | }; | 3250 | }; |
| 3241 | 3251 | ||
| 3242 | ui_helpline__push("Press ESC to exit"); | 3252 | ui_helpline__push("Press ESC to exit"); |
| @@ -3257,7 +3267,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | |||
| 3257 | struct hist_browser_timer *hbt, | 3267 | struct hist_browser_timer *hbt, |
| 3258 | float min_pcnt, | 3268 | float min_pcnt, |
| 3259 | struct perf_env *env, | 3269 | struct perf_env *env, |
| 3260 | bool warn_lost_event) | 3270 | bool warn_lost_event, |
| 3271 | struct annotation_options *annotation_opts) | ||
| 3261 | { | 3272 | { |
| 3262 | int nr_entries = evlist->nr_entries; | 3273 | int nr_entries = evlist->nr_entries; |
| 3263 | 3274 | ||
| @@ -3267,7 +3278,8 @@ single_entry: | |||
| 3267 | 3278 | ||
| 3268 | return perf_evsel__hists_browse(first, nr_entries, help, | 3279 | return perf_evsel__hists_browse(first, nr_entries, help, |
| 3269 | false, hbt, min_pcnt, | 3280 | false, hbt, min_pcnt, |
| 3270 | env, warn_lost_event); | 3281 | env, warn_lost_event, |
| 3282 | annotation_opts); | ||
| 3271 | } | 3283 | } |
| 3272 | 3284 | ||
| 3273 | if (symbol_conf.event_group) { | 3285 | if (symbol_conf.event_group) { |
| @@ -3285,5 +3297,6 @@ single_entry: | |||
| 3285 | 3297 | ||
| 3286 | return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, | 3298 | return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, |
| 3287 | hbt, min_pcnt, env, | 3299 | hbt, min_pcnt, env, |
| 3288 | warn_lost_event); | 3300 | warn_lost_event, |
| 3301 | annotation_opts); | ||
| 3289 | } | 3302 | } |
diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h index 9428bee076f2..91d3e18b50aa 100644 --- a/tools/perf/ui/browsers/hists.h +++ b/tools/perf/ui/browsers/hists.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #include "ui/browser.h" | 5 | #include "ui/browser.h" |
| 6 | 6 | ||
| 7 | struct annotation_options; | ||
| 8 | |||
| 7 | struct hist_browser { | 9 | struct hist_browser { |
| 8 | struct ui_browser b; | 10 | struct ui_browser b; |
| 9 | struct hists *hists; | 11 | struct hists *hists; |
| @@ -12,6 +14,7 @@ struct hist_browser { | |||
| 12 | struct hist_browser_timer *hbt; | 14 | struct hist_browser_timer *hbt; |
| 13 | struct pstack *pstack; | 15 | struct pstack *pstack; |
| 14 | struct perf_env *env; | 16 | struct perf_env *env; |
| 17 | struct annotation_options *annotation_opts; | ||
| 15 | int print_seq; | 18 | int print_seq; |
| 16 | bool show_dso; | 19 | bool show_dso; |
| 17 | bool show_headers; | 20 | bool show_headers; |
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index aeeaf15029f0..48428c9acd89 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c | |||
| @@ -169,7 +169,7 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, | |||
| 169 | if (map->dso->annotate_warned) | 169 | if (map->dso->annotate_warned) |
| 170 | return -1; | 170 | return -1; |
| 171 | 171 | ||
| 172 | err = symbol__annotate(sym, map, evsel, 0, NULL); | 172 | err = symbol__annotate(sym, map, evsel, 0, &annotation__default_options, NULL); |
| 173 | if (err) { | 173 | if (err) { |
| 174 | char msg[BUFSIZ]; | 174 | char msg[BUFSIZ]; |
| 175 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); | 175 | symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); |
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 24e1ec201ffd..4ab663ec3e5e 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
| @@ -382,7 +382,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
| 382 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); | 382 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); |
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | if (symbol_conf.use_callchain && hists__has(hists, sym)) { | 385 | if (hist_entry__has_callchains(h) && |
| 386 | symbol_conf.use_callchain && hists__has(hists, sym)) { | ||
| 386 | if (callchain_param.mode == CHAIN_GRAPH_REL) | 387 | if (callchain_param.mode == CHAIN_GRAPH_REL) |
| 387 | total = symbol_conf.cumulate_callchain ? | 388 | total = symbol_conf.cumulate_callchain ? |
| 388 | h->stat_acc->period : h->stat.period; | 389 | h->stat_acc->period : h->stat.period; |
| @@ -479,7 +480,7 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists, | |||
| 479 | } | 480 | } |
| 480 | } | 481 | } |
| 481 | 482 | ||
| 482 | if (symbol_conf.use_callchain && he->leaf) { | 483 | if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) { |
| 483 | if (callchain_param.mode == CHAIN_GRAPH_REL) | 484 | if (callchain_param.mode == CHAIN_GRAPH_REL) |
| 484 | total = symbol_conf.cumulate_callchain ? | 485 | total = symbol_conf.cumulate_callchain ? |
| 485 | he->stat_acc->period : he->stat.period; | 486 | he->stat_acc->period : he->stat.period; |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 706f6f1e9c7d..fe3dfaa64a91 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
| @@ -207,7 +207,7 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, | |||
| 207 | if (ret) | 207 | if (ret) |
| 208 | return ret; | 208 | return ret; |
| 209 | 209 | ||
| 210 | if (a->thread != b->thread || !symbol_conf.use_callchain) | 210 | if (a->thread != b->thread || !hist_entry__has_callchains(a) || !symbol_conf.use_callchain) |
| 211 | return 0; | 211 | return 0; |
| 212 | 212 | ||
| 213 | ret = b->callchain->max_depth - a->callchain->max_depth; | 213 | ret = b->callchain->max_depth - a->callchain->max_depth; |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index c1eb476da91b..69b7a28f7a1c 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
| @@ -516,7 +516,7 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he, | |||
| 516 | } | 516 | } |
| 517 | printed += putc('\n', fp); | 517 | printed += putc('\n', fp); |
| 518 | 518 | ||
| 519 | if (symbol_conf.use_callchain && he->leaf) { | 519 | if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) { |
| 520 | u64 total = hists__total_period(hists); | 520 | u64 total = hists__total_period(hists); |
| 521 | 521 | ||
| 522 | printed += hist_entry_callchain__fprintf(he, total, 0, fp); | 522 | printed += hist_entry_callchain__fprintf(he, total, 0, fp); |
| @@ -550,7 +550,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, | |||
| 550 | 550 | ||
| 551 | ret = fprintf(fp, "%s\n", bf); | 551 | ret = fprintf(fp, "%s\n", bf); |
| 552 | 552 | ||
| 553 | if (use_callchain) | 553 | if (hist_entry__has_callchains(he) && use_callchain) |
| 554 | callchain_ret = hist_entry_callchain__fprintf(he, total_period, | 554 | callchain_ret = hist_entry_callchain__fprintf(he, total_period, |
| 555 | 0, fp); | 555 | 0, fp); |
| 556 | 556 | ||
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 5d4c45b76895..b604ef334dc9 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
| @@ -24,7 +24,6 @@ libperf-y += libstring.o | |||
| 24 | libperf-y += bitmap.o | 24 | libperf-y += bitmap.o |
| 25 | libperf-y += hweight.o | 25 | libperf-y += hweight.o |
| 26 | libperf-y += smt.o | 26 | libperf-y += smt.o |
| 27 | libperf-y += quote.o | ||
| 28 | libperf-y += strbuf.o | 27 | libperf-y += strbuf.o |
| 29 | libperf-y += string.o | 28 | libperf-y += string.o |
| 30 | libperf-y += strlist.o | 29 | libperf-y += strlist.o |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 71897689dacf..f91775b4bc3c 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "debug.h" | 21 | #include "debug.h" |
| 22 | #include "annotate.h" | 22 | #include "annotate.h" |
| 23 | #include "evsel.h" | 23 | #include "evsel.h" |
| 24 | #include "evlist.h" | ||
| 24 | #include "block-range.h" | 25 | #include "block-range.h" |
| 25 | #include "string2.h" | 26 | #include "string2.h" |
| 26 | #include "arch/common.h" | 27 | #include "arch/common.h" |
| @@ -46,11 +47,10 @@ | |||
| 46 | struct annotation_options annotation__default_options = { | 47 | struct annotation_options annotation__default_options = { |
| 47 | .use_offset = true, | 48 | .use_offset = true, |
| 48 | .jump_arrows = true, | 49 | .jump_arrows = true, |
| 50 | .annotate_src = true, | ||
| 49 | .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, | 51 | .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, |
| 50 | }; | 52 | }; |
| 51 | 53 | ||
| 52 | const char *disassembler_style; | ||
| 53 | const char *objdump_path; | ||
| 54 | static regex_t file_lineno; | 54 | static regex_t file_lineno; |
| 55 | 55 | ||
| 56 | static struct ins_ops *ins__find(struct arch *arch, const char *name); | 56 | static struct ins_ops *ins__find(struct arch *arch, const char *name); |
| @@ -678,10 +678,28 @@ static struct arch *arch__find(const char *name) | |||
| 678 | return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); | 678 | return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); |
| 679 | } | 679 | } |
| 680 | 680 | ||
| 681 | int symbol__alloc_hist(struct symbol *sym) | 681 | static struct annotated_source *annotated_source__new(void) |
| 682 | { | ||
| 683 | struct annotated_source *src = zalloc(sizeof(*src)); | ||
| 684 | |||
| 685 | if (src != NULL) | ||
| 686 | INIT_LIST_HEAD(&src->source); | ||
| 687 | |||
| 688 | return src; | ||
| 689 | } | ||
| 690 | |||
| 691 | static __maybe_unused void annotated_source__delete(struct annotated_source *src) | ||
| 692 | { | ||
| 693 | if (src == NULL) | ||
| 694 | return; | ||
| 695 | zfree(&src->histograms); | ||
| 696 | zfree(&src->cycles_hist); | ||
| 697 | free(src); | ||
| 698 | } | ||
| 699 | |||
| 700 | static int annotated_source__alloc_histograms(struct annotated_source *src, | ||
| 701 | size_t size, int nr_hists) | ||
| 682 | { | 702 | { |
| 683 | struct annotation *notes = symbol__annotation(sym); | ||
| 684 | size_t size = symbol__size(sym); | ||
| 685 | size_t sizeof_sym_hist; | 703 | size_t sizeof_sym_hist; |
| 686 | 704 | ||
| 687 | /* | 705 | /* |
| @@ -701,17 +719,13 @@ int symbol__alloc_hist(struct symbol *sym) | |||
| 701 | sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry)); | 719 | sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry)); |
| 702 | 720 | ||
| 703 | /* Check for overflow in zalloc argument */ | 721 | /* Check for overflow in zalloc argument */ |
| 704 | if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) | 722 | if (sizeof_sym_hist > SIZE_MAX / nr_hists) |
| 705 | / symbol_conf.nr_events) | ||
| 706 | return -1; | 723 | return -1; |
| 707 | 724 | ||
| 708 | notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); | 725 | src->sizeof_sym_hist = sizeof_sym_hist; |
| 709 | if (notes->src == NULL) | 726 | src->nr_histograms = nr_hists; |
| 710 | return -1; | 727 | src->histograms = calloc(nr_hists, sizeof_sym_hist) ; |
| 711 | notes->src->sizeof_sym_hist = sizeof_sym_hist; | 728 | return src->histograms ? 0 : -1; |
| 712 | notes->src->nr_histograms = symbol_conf.nr_events; | ||
| 713 | INIT_LIST_HEAD(¬es->src->source); | ||
| 714 | return 0; | ||
| 715 | } | 729 | } |
| 716 | 730 | ||
| 717 | /* The cycles histogram is lazily allocated. */ | 731 | /* The cycles histogram is lazily allocated. */ |
| @@ -741,14 +755,11 @@ void symbol__annotate_zero_histograms(struct symbol *sym) | |||
| 741 | pthread_mutex_unlock(¬es->lock); | 755 | pthread_mutex_unlock(¬es->lock); |
| 742 | } | 756 | } |
| 743 | 757 | ||
| 744 | static int __symbol__account_cycles(struct annotation *notes, | 758 | static int __symbol__account_cycles(struct cyc_hist *ch, |
| 745 | u64 start, | 759 | u64 start, |
| 746 | unsigned offset, unsigned cycles, | 760 | unsigned offset, unsigned cycles, |
| 747 | unsigned have_start) | 761 | unsigned have_start) |
| 748 | { | 762 | { |
| 749 | struct cyc_hist *ch; | ||
| 750 | |||
| 751 | ch = notes->src->cycles_hist; | ||
| 752 | /* | 763 | /* |
| 753 | * For now we can only account one basic block per | 764 | * For now we can only account one basic block per |
| 754 | * final jump. But multiple could be overlapping. | 765 | * final jump. But multiple could be overlapping. |
| @@ -791,7 +802,7 @@ static int __symbol__account_cycles(struct annotation *notes, | |||
| 791 | } | 802 | } |
| 792 | 803 | ||
| 793 | static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 804 | static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, |
| 794 | struct annotation *notes, int evidx, u64 addr, | 805 | struct annotated_source *src, int evidx, u64 addr, |
| 795 | struct perf_sample *sample) | 806 | struct perf_sample *sample) |
| 796 | { | 807 | { |
| 797 | unsigned offset; | 808 | unsigned offset; |
| @@ -807,7 +818,12 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
| 807 | } | 818 | } |
| 808 | 819 | ||
| 809 | offset = addr - sym->start; | 820 | offset = addr - sym->start; |
| 810 | h = annotation__histogram(notes, evidx); | 821 | h = annotated_source__histogram(src, evidx); |
| 822 | if (h == NULL) { | ||
| 823 | pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n", | ||
| 824 | __func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC); | ||
| 825 | return -ENOMEM; | ||
| 826 | } | ||
| 811 | h->nr_samples++; | 827 | h->nr_samples++; |
| 812 | h->addr[offset].nr_samples++; | 828 | h->addr[offset].nr_samples++; |
| 813 | h->period += sample->period; | 829 | h->period += sample->period; |
| @@ -820,45 +836,69 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
| 820 | return 0; | 836 | return 0; |
| 821 | } | 837 | } |
| 822 | 838 | ||
| 823 | static struct annotation *symbol__get_annotation(struct symbol *sym, bool cycles) | 839 | static struct cyc_hist *symbol__cycles_hist(struct symbol *sym) |
| 824 | { | 840 | { |
| 825 | struct annotation *notes = symbol__annotation(sym); | 841 | struct annotation *notes = symbol__annotation(sym); |
| 826 | 842 | ||
| 827 | if (notes->src == NULL) { | 843 | if (notes->src == NULL) { |
| 828 | if (symbol__alloc_hist(sym) < 0) | 844 | notes->src = annotated_source__new(); |
| 845 | if (notes->src == NULL) | ||
| 829 | return NULL; | 846 | return NULL; |
| 847 | goto alloc_cycles_hist; | ||
| 848 | } | ||
| 849 | |||
| 850 | if (!notes->src->cycles_hist) { | ||
| 851 | alloc_cycles_hist: | ||
| 852 | symbol__alloc_hist_cycles(sym); | ||
| 830 | } | 853 | } |
| 831 | if (!notes->src->cycles_hist && cycles) { | 854 | |
| 832 | if (symbol__alloc_hist_cycles(sym) < 0) | 855 | return notes->src->cycles_hist; |
| 856 | } | ||
| 857 | |||
| 858 | struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists) | ||
| 859 | { | ||
| 860 | struct annotation *notes = symbol__annotation(sym); | ||
| 861 | |||
| 862 | if (notes->src == NULL) { | ||
| 863 | notes->src = annotated_source__new(); | ||
| 864 | if (notes->src == NULL) | ||
| 833 | return NULL; | 865 | return NULL; |
| 866 | goto alloc_histograms; | ||
| 834 | } | 867 | } |
| 835 | return notes; | 868 | |
| 869 | if (notes->src->histograms == NULL) { | ||
| 870 | alloc_histograms: | ||
| 871 | annotated_source__alloc_histograms(notes->src, symbol__size(sym), | ||
| 872 | nr_hists); | ||
| 873 | } | ||
| 874 | |||
| 875 | return notes->src; | ||
| 836 | } | 876 | } |
| 837 | 877 | ||
| 838 | static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 878 | static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, |
| 839 | int evidx, u64 addr, | 879 | struct perf_evsel *evsel, u64 addr, |
| 840 | struct perf_sample *sample) | 880 | struct perf_sample *sample) |
| 841 | { | 881 | { |
| 842 | struct annotation *notes; | 882 | struct annotated_source *src; |
| 843 | 883 | ||
| 844 | if (sym == NULL) | 884 | if (sym == NULL) |
| 845 | return 0; | 885 | return 0; |
| 846 | notes = symbol__get_annotation(sym, false); | 886 | src = symbol__hists(sym, evsel->evlist->nr_entries); |
| 847 | if (notes == NULL) | 887 | if (src == NULL) |
| 848 | return -ENOMEM; | 888 | return -ENOMEM; |
| 849 | return __symbol__inc_addr_samples(sym, map, notes, evidx, addr, sample); | 889 | return __symbol__inc_addr_samples(sym, map, src, evsel->idx, addr, sample); |
| 850 | } | 890 | } |
| 851 | 891 | ||
| 852 | static int symbol__account_cycles(u64 addr, u64 start, | 892 | static int symbol__account_cycles(u64 addr, u64 start, |
| 853 | struct symbol *sym, unsigned cycles) | 893 | struct symbol *sym, unsigned cycles) |
| 854 | { | 894 | { |
| 855 | struct annotation *notes; | 895 | struct cyc_hist *cycles_hist; |
| 856 | unsigned offset; | 896 | unsigned offset; |
| 857 | 897 | ||
| 858 | if (sym == NULL) | 898 | if (sym == NULL) |
| 859 | return 0; | 899 | return 0; |
| 860 | notes = symbol__get_annotation(sym, true); | 900 | cycles_hist = symbol__cycles_hist(sym); |
| 861 | if (notes == NULL) | 901 | if (cycles_hist == NULL) |
| 862 | return -ENOMEM; | 902 | return -ENOMEM; |
| 863 | if (addr < sym->start || addr >= sym->end) | 903 | if (addr < sym->start || addr >= sym->end) |
| 864 | return -ERANGE; | 904 | return -ERANGE; |
| @@ -870,7 +910,7 @@ static int symbol__account_cycles(u64 addr, u64 start, | |||
| 870 | start = 0; | 910 | start = 0; |
| 871 | } | 911 | } |
| 872 | offset = addr - sym->start; | 912 | offset = addr - sym->start; |
| 873 | return __symbol__account_cycles(notes, | 913 | return __symbol__account_cycles(cycles_hist, |
| 874 | start ? start - sym->start : 0, | 914 | start ? start - sym->start : 0, |
| 875 | offset, cycles, | 915 | offset, cycles, |
| 876 | !!start); | 916 | !!start); |
| @@ -974,15 +1014,15 @@ void annotation__compute_ipc(struct annotation *notes, size_t size) | |||
| 974 | } | 1014 | } |
| 975 | 1015 | ||
| 976 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, | 1016 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, |
| 977 | int evidx) | 1017 | struct perf_evsel *evsel) |
| 978 | { | 1018 | { |
| 979 | return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr, sample); | 1019 | return symbol__inc_addr_samples(ams->sym, ams->map, evsel, ams->al_addr, sample); |
| 980 | } | 1020 | } |
| 981 | 1021 | ||
| 982 | int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, | 1022 | int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, |
| 983 | int evidx, u64 ip) | 1023 | struct perf_evsel *evsel, u64 ip) |
| 984 | { | 1024 | { |
| 985 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip, sample); | 1025 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evsel, ip, sample); |
| 986 | } | 1026 | } |
| 987 | 1027 | ||
| 988 | static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms) | 1028 | static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms) |
| @@ -1031,6 +1071,7 @@ struct annotate_args { | |||
| 1031 | struct arch *arch; | 1071 | struct arch *arch; |
| 1032 | struct map_symbol ms; | 1072 | struct map_symbol ms; |
| 1033 | struct perf_evsel *evsel; | 1073 | struct perf_evsel *evsel; |
| 1074 | struct annotation_options *options; | ||
| 1034 | s64 offset; | 1075 | s64 offset; |
| 1035 | char *line; | 1076 | char *line; |
| 1036 | int line_nr; | 1077 | int line_nr; |
| @@ -1572,6 +1613,7 @@ fallback: | |||
| 1572 | 1613 | ||
| 1573 | static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) | 1614 | static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) |
| 1574 | { | 1615 | { |
| 1616 | struct annotation_options *opts = args->options; | ||
| 1575 | struct map *map = args->ms.map; | 1617 | struct map *map = args->ms.map; |
| 1576 | struct dso *dso = map->dso; | 1618 | struct dso *dso = map->dso; |
| 1577 | char *command; | 1619 | char *command; |
| @@ -1619,13 +1661,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) | |||
| 1619 | "%s %s%s --start-address=0x%016" PRIx64 | 1661 | "%s %s%s --start-address=0x%016" PRIx64 |
| 1620 | " --stop-address=0x%016" PRIx64 | 1662 | " --stop-address=0x%016" PRIx64 |
| 1621 | " -l -d %s %s -C \"%s\" 2>/dev/null|grep -v \"%s:\"|expand", | 1663 | " -l -d %s %s -C \"%s\" 2>/dev/null|grep -v \"%s:\"|expand", |
| 1622 | objdump_path ? objdump_path : "objdump", | 1664 | opts->objdump_path ?: "objdump", |
| 1623 | disassembler_style ? "-M " : "", | 1665 | opts->disassembler_style ? "-M " : "", |
| 1624 | disassembler_style ? disassembler_style : "", | 1666 | opts->disassembler_style ?: "", |
| 1625 | map__rip_2objdump(map, sym->start), | 1667 | map__rip_2objdump(map, sym->start), |
| 1626 | map__rip_2objdump(map, sym->end), | 1668 | map__rip_2objdump(map, sym->end), |
| 1627 | symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", | 1669 | opts->show_asm_raw ? "" : "--no-show-raw", |
| 1628 | symbol_conf.annotate_src ? "-S" : "", | 1670 | opts->annotate_src ? "-S" : "", |
| 1629 | symfs_filename, symfs_filename); | 1671 | symfs_filename, symfs_filename); |
| 1630 | 1672 | ||
| 1631 | if (err < 0) { | 1673 | if (err < 0) { |
| @@ -1767,11 +1809,13 @@ void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) | |||
| 1767 | 1809 | ||
| 1768 | int symbol__annotate(struct symbol *sym, struct map *map, | 1810 | int symbol__annotate(struct symbol *sym, struct map *map, |
| 1769 | struct perf_evsel *evsel, size_t privsize, | 1811 | struct perf_evsel *evsel, size_t privsize, |
| 1812 | struct annotation_options *options, | ||
| 1770 | struct arch **parch) | 1813 | struct arch **parch) |
| 1771 | { | 1814 | { |
| 1772 | struct annotate_args args = { | 1815 | struct annotate_args args = { |
| 1773 | .privsize = privsize, | 1816 | .privsize = privsize, |
| 1774 | .evsel = evsel, | 1817 | .evsel = evsel, |
| 1818 | .options = options, | ||
| 1775 | }; | 1819 | }; |
| 1776 | struct perf_env *env = perf_evsel__env(evsel); | 1820 | struct perf_env *env = perf_evsel__env(evsel); |
| 1777 | const char *arch_name = perf_env__arch(env); | 1821 | const char *arch_name = perf_env__arch(env); |
| @@ -1949,8 +1993,8 @@ static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) | |||
| 1949 | } | 1993 | } |
| 1950 | 1994 | ||
| 1951 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 1995 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
| 1952 | struct perf_evsel *evsel, bool full_paths, | 1996 | struct perf_evsel *evsel, |
| 1953 | int min_pcnt, int max_lines, int context) | 1997 | struct annotation_options *opts) |
| 1954 | { | 1998 | { |
| 1955 | struct dso *dso = map->dso; | 1999 | struct dso *dso = map->dso; |
| 1956 | char *filename; | 2000 | char *filename; |
| @@ -1962,6 +2006,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
| 1962 | u64 start = map__rip_2objdump(map, sym->start); | 2006 | u64 start = map__rip_2objdump(map, sym->start); |
| 1963 | int printed = 2, queue_len = 0, addr_fmt_width; | 2007 | int printed = 2, queue_len = 0, addr_fmt_width; |
| 1964 | int more = 0; | 2008 | int more = 0; |
| 2009 | bool context = opts->context; | ||
| 1965 | u64 len; | 2010 | u64 len; |
| 1966 | int width = symbol_conf.show_total_period ? 12 : 8; | 2011 | int width = symbol_conf.show_total_period ? 12 : 8; |
| 1967 | int graph_dotted_len; | 2012 | int graph_dotted_len; |
| @@ -1971,7 +2016,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
| 1971 | if (!filename) | 2016 | if (!filename) |
| 1972 | return -ENOMEM; | 2017 | return -ENOMEM; |
| 1973 | 2018 | ||
| 1974 | if (full_paths) | 2019 | if (opts->full_path) |
| 1975 | d_filename = filename; | 2020 | d_filename = filename; |
| 1976 | else | 2021 | else |
| 1977 | d_filename = basename(filename); | 2022 | d_filename = basename(filename); |
| @@ -2006,7 +2051,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
| 2006 | } | 2051 | } |
| 2007 | 2052 | ||
| 2008 | err = annotation_line__print(pos, sym, start, evsel, len, | 2053 | err = annotation_line__print(pos, sym, start, evsel, len, |
| 2009 | min_pcnt, printed, max_lines, | 2054 | opts->min_pcnt, printed, opts->max_lines, |
| 2010 | queue, addr_fmt_width); | 2055 | queue, addr_fmt_width); |
| 2011 | 2056 | ||
| 2012 | switch (err) { | 2057 | switch (err) { |
| @@ -2339,20 +2384,19 @@ static void symbol__calc_lines(struct symbol *sym, struct map *map, | |||
| 2339 | } | 2384 | } |
| 2340 | 2385 | ||
| 2341 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, | 2386 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, |
| 2342 | struct perf_evsel *evsel, bool print_lines, | 2387 | struct perf_evsel *evsel, |
| 2343 | bool full_paths) | 2388 | struct annotation_options *opts) |
| 2344 | { | 2389 | { |
| 2345 | struct dso *dso = map->dso; | 2390 | struct dso *dso = map->dso; |
| 2346 | struct rb_root source_line = RB_ROOT; | 2391 | struct rb_root source_line = RB_ROOT; |
| 2347 | struct annotation_options opts = annotation__default_options; | ||
| 2348 | struct annotation *notes = symbol__annotation(sym); | 2392 | struct annotation *notes = symbol__annotation(sym); |
| 2349 | char buf[1024]; | 2393 | char buf[1024]; |
| 2350 | 2394 | ||
| 2351 | if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) | 2395 | if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) |
| 2352 | return -1; | 2396 | return -1; |
| 2353 | 2397 | ||
| 2354 | if (print_lines) { | 2398 | if (opts->print_lines) { |
| 2355 | srcline_full_filename = full_paths; | 2399 | srcline_full_filename = opts->full_path; |
| 2356 | symbol__calc_lines(sym, map, &source_line); | 2400 | symbol__calc_lines(sym, map, &source_line); |
| 2357 | print_summary(&source_line, dso->long_name); | 2401 | print_summary(&source_line, dso->long_name); |
| 2358 | } | 2402 | } |
| @@ -2367,25 +2411,24 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, | |||
| 2367 | } | 2411 | } |
| 2368 | 2412 | ||
| 2369 | int symbol__tty_annotate(struct symbol *sym, struct map *map, | 2413 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
| 2370 | struct perf_evsel *evsel, bool print_lines, | 2414 | struct perf_evsel *evsel, |
| 2371 | bool full_paths, int min_pcnt, int max_lines) | 2415 | struct annotation_options *opts) |
| 2372 | { | 2416 | { |
| 2373 | struct dso *dso = map->dso; | 2417 | struct dso *dso = map->dso; |
| 2374 | struct rb_root source_line = RB_ROOT; | 2418 | struct rb_root source_line = RB_ROOT; |
| 2375 | 2419 | ||
| 2376 | if (symbol__annotate(sym, map, evsel, 0, NULL) < 0) | 2420 | if (symbol__annotate(sym, map, evsel, 0, opts, NULL) < 0) |
| 2377 | return -1; | 2421 | return -1; |
| 2378 | 2422 | ||
| 2379 | symbol__calc_percent(sym, evsel); | 2423 | symbol__calc_percent(sym, evsel); |
| 2380 | 2424 | ||
| 2381 | if (print_lines) { | 2425 | if (opts->print_lines) { |
| 2382 | srcline_full_filename = full_paths; | 2426 | srcline_full_filename = opts->full_path; |
| 2383 | symbol__calc_lines(sym, map, &source_line); | 2427 | symbol__calc_lines(sym, map, &source_line); |
| 2384 | print_summary(&source_line, dso->long_name); | 2428 | print_summary(&source_line, dso->long_name); |
| 2385 | } | 2429 | } |
| 2386 | 2430 | ||
| 2387 | symbol__annotate_printf(sym, map, evsel, full_paths, | 2431 | symbol__annotate_printf(sym, map, evsel, opts); |
| 2388 | min_pcnt, max_lines, 0); | ||
| 2389 | 2432 | ||
| 2390 | annotated_source__purge(symbol__annotation(sym)->src); | 2433 | annotated_source__purge(symbol__annotation(sym)->src); |
| 2391 | 2434 | ||
| @@ -2620,7 +2663,7 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *ev | |||
| 2620 | if (perf_evsel__is_group_event(evsel)) | 2663 | if (perf_evsel__is_group_event(evsel)) |
| 2621 | nr_pcnt = evsel->nr_members; | 2664 | nr_pcnt = evsel->nr_members; |
| 2622 | 2665 | ||
| 2623 | err = symbol__annotate(sym, map, evsel, 0, parch); | 2666 | err = symbol__annotate(sym, map, evsel, 0, options, parch); |
| 2624 | if (err) | 2667 | if (err) |
| 2625 | goto out_free_offsets; | 2668 | goto out_free_offsets; |
| 2626 | 2669 | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 5080b6dd98b8..a4c0d91907e6 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
| @@ -67,12 +67,21 @@ struct annotation_options { | |||
| 67 | bool hide_src_code, | 67 | bool hide_src_code, |
| 68 | use_offset, | 68 | use_offset, |
| 69 | jump_arrows, | 69 | jump_arrows, |
| 70 | print_lines, | ||
| 71 | full_path, | ||
| 70 | show_linenr, | 72 | show_linenr, |
| 71 | show_nr_jumps, | 73 | show_nr_jumps, |
| 72 | show_nr_samples, | 74 | show_nr_samples, |
| 73 | show_total_period, | 75 | show_total_period, |
| 74 | show_minmax_cycle; | 76 | show_minmax_cycle, |
| 77 | show_asm_raw, | ||
| 78 | annotate_src; | ||
| 75 | u8 offset_level; | 79 | u8 offset_level; |
| 80 | int min_pcnt; | ||
| 81 | int max_lines; | ||
| 82 | int context; | ||
| 83 | const char *objdump_path; | ||
| 84 | const char *disassembler_style; | ||
| 76 | }; | 85 | }; |
| 77 | 86 | ||
| 78 | enum { | 87 | enum { |
| @@ -201,7 +210,11 @@ struct cyc_hist { | |||
| 201 | 210 | ||
| 202 | /** struct annotated_source - symbols with hits have this attached as in sannotation | 211 | /** struct annotated_source - symbols with hits have this attached as in sannotation |
| 203 | * | 212 | * |
| 204 | * @histogram: Array of addr hit histograms per event being monitored | 213 | * @histograms: Array of addr hit histograms per event being monitored |
| 214 | * nr_histograms: This may not be the same as evsel->evlist->nr_entries if | ||
| 215 | * we have more than a group in a evlist, where we will want | ||
| 216 | * to see each group separately, that is why symbol__annotate2() | ||
| 217 | * sets src->nr_histograms to evsel->nr_members. | ||
| 205 | * @lines: If 'print_lines' is specified, per source code line percentages | 218 | * @lines: If 'print_lines' is specified, per source code line percentages |
| 206 | * @source: source parsed from a disassembler like objdump -dS | 219 | * @source: source parsed from a disassembler like objdump -dS |
| 207 | * @cyc_hist: Average cycles per basic block | 220 | * @cyc_hist: Average cycles per basic block |
| @@ -217,7 +230,7 @@ struct annotated_source { | |||
| 217 | int nr_histograms; | 230 | int nr_histograms; |
| 218 | size_t sizeof_sym_hist; | 231 | size_t sizeof_sym_hist; |
| 219 | struct cyc_hist *cycles_hist; | 232 | struct cyc_hist *cycles_hist; |
| 220 | struct sym_hist histograms[0]; | 233 | struct sym_hist *histograms; |
| 221 | }; | 234 | }; |
| 222 | 235 | ||
| 223 | struct annotation { | 236 | struct annotation { |
| @@ -267,10 +280,14 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) | |||
| 267 | void annotation__update_column_widths(struct annotation *notes); | 280 | void annotation__update_column_widths(struct annotation *notes); |
| 268 | void annotation__init_column_widths(struct annotation *notes, struct symbol *sym); | 281 | void annotation__init_column_widths(struct annotation *notes, struct symbol *sym); |
| 269 | 282 | ||
| 283 | static inline struct sym_hist *annotated_source__histogram(struct annotated_source *src, int idx) | ||
| 284 | { | ||
| 285 | return ((void *)src->histograms) + (src->sizeof_sym_hist * idx); | ||
| 286 | } | ||
| 287 | |||
| 270 | static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) | 288 | static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) |
| 271 | { | 289 | { |
| 272 | return (((void *)¬es->src->histograms) + | 290 | return annotated_source__histogram(notes->src, idx); |
| 273 | (notes->src->sizeof_sym_hist * idx)); | ||
| 274 | } | 291 | } |
| 275 | 292 | ||
| 276 | static inline struct annotation *symbol__annotation(struct symbol *sym) | 293 | static inline struct annotation *symbol__annotation(struct symbol *sym) |
| @@ -279,20 +296,21 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) | |||
| 279 | } | 296 | } |
| 280 | 297 | ||
| 281 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, | 298 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, |
| 282 | int evidx); | 299 | struct perf_evsel *evsel); |
| 283 | 300 | ||
| 284 | int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, | 301 | int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, |
| 285 | struct addr_map_symbol *start, | 302 | struct addr_map_symbol *start, |
| 286 | unsigned cycles); | 303 | unsigned cycles); |
| 287 | 304 | ||
| 288 | int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, | 305 | int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, |
| 289 | int evidx, u64 addr); | 306 | struct perf_evsel *evsel, u64 addr); |
| 290 | 307 | ||
| 291 | int symbol__alloc_hist(struct symbol *sym); | 308 | struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists); |
| 292 | void symbol__annotate_zero_histograms(struct symbol *sym); | 309 | void symbol__annotate_zero_histograms(struct symbol *sym); |
| 293 | 310 | ||
| 294 | int symbol__annotate(struct symbol *sym, struct map *map, | 311 | int symbol__annotate(struct symbol *sym, struct map *map, |
| 295 | struct perf_evsel *evsel, size_t privsize, | 312 | struct perf_evsel *evsel, size_t privsize, |
| 313 | struct annotation_options *options, | ||
| 296 | struct arch **parch); | 314 | struct arch **parch); |
| 297 | int symbol__annotate2(struct symbol *sym, struct map *map, | 315 | int symbol__annotate2(struct symbol *sym, struct map *map, |
| 298 | struct perf_evsel *evsel, | 316 | struct perf_evsel *evsel, |
| @@ -320,8 +338,8 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map, | |||
| 320 | int errnum, char *buf, size_t buflen); | 338 | int errnum, char *buf, size_t buflen); |
| 321 | 339 | ||
| 322 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 340 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
| 323 | struct perf_evsel *evsel, bool full_paths, | 341 | struct perf_evsel *evsel, |
| 324 | int min_pcnt, int max_lines, int context); | 342 | struct annotation_options *options); |
| 325 | int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); | 343 | int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); |
| 326 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); | 344 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); |
| 327 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); | 345 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); |
| @@ -332,30 +350,27 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) | |||
| 332 | bool ui__has_annotation(void); | 350 | bool ui__has_annotation(void); |
| 333 | 351 | ||
| 334 | int symbol__tty_annotate(struct symbol *sym, struct map *map, | 352 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
| 335 | struct perf_evsel *evsel, bool print_lines, | 353 | struct perf_evsel *evsel, struct annotation_options *opts); |
| 336 | bool full_paths, int min_pcnt, int max_lines); | ||
| 337 | 354 | ||
| 338 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, | 355 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, |
| 339 | struct perf_evsel *evsel, bool print_lines, | 356 | struct perf_evsel *evsel, struct annotation_options *opts); |
| 340 | bool full_paths); | ||
| 341 | 357 | ||
| 342 | #ifdef HAVE_SLANG_SUPPORT | 358 | #ifdef HAVE_SLANG_SUPPORT |
| 343 | int symbol__tui_annotate(struct symbol *sym, struct map *map, | 359 | int symbol__tui_annotate(struct symbol *sym, struct map *map, |
| 344 | struct perf_evsel *evsel, | 360 | struct perf_evsel *evsel, |
| 345 | struct hist_browser_timer *hbt); | 361 | struct hist_browser_timer *hbt, |
| 362 | struct annotation_options *opts); | ||
| 346 | #else | 363 | #else |
| 347 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | 364 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, |
| 348 | struct map *map __maybe_unused, | 365 | struct map *map __maybe_unused, |
| 349 | struct perf_evsel *evsel __maybe_unused, | 366 | struct perf_evsel *evsel __maybe_unused, |
| 350 | struct hist_browser_timer *hbt | 367 | struct hist_browser_timer *hbt __maybe_unused, |
| 351 | __maybe_unused) | 368 | struct annotation_options *opts __maybe_unused) |
| 352 | { | 369 | { |
| 353 | return 0; | 370 | return 0; |
| 354 | } | 371 | } |
| 355 | #endif | 372 | #endif |
| 356 | 373 | ||
| 357 | extern const char *disassembler_style; | ||
| 358 | |||
| 359 | void annotation_config__init(void); | 374 | void annotation_config__init(void); |
| 360 | 375 | ||
| 361 | #endif /* __PERF_ANNOTATE_H */ | 376 | #endif /* __PERF_ANNOTATE_H */ |
diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c index 29347756b0af..77e4891e17b0 100644 --- a/tools/perf/util/bpf-prologue.c +++ b/tools/perf/util/bpf-prologue.c | |||
| @@ -61,7 +61,7 @@ check_pos(struct bpf_insn_pos *pos) | |||
| 61 | 61 | ||
| 62 | /* | 62 | /* |
| 63 | * Convert type string (u8/u16/u32/u64/s8/s16/s32/s64 ..., see | 63 | * Convert type string (u8/u16/u32/u64/s8/s16/s32/s64 ..., see |
| 64 | * Documentation/trace/kprobetrace.txt) to size field of BPF_LDX_MEM | 64 | * Documentation/trace/kprobetrace.rst) to size field of BPF_LDX_MEM |
| 65 | * instruction (BPF_{B,H,W,DW}). | 65 | * instruction (BPF_{B,H,W,DW}). |
| 66 | */ | 66 | */ |
| 67 | static int | 67 | static int |
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index bf31ceab33bd..89512504551b 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp | |||
| @@ -146,8 +146,15 @@ getBPFObjectFromModule(llvm::Module *Module) | |||
| 146 | raw_svector_ostream ostream(*Buffer); | 146 | raw_svector_ostream ostream(*Buffer); |
| 147 | 147 | ||
| 148 | legacy::PassManager PM; | 148 | legacy::PassManager PM; |
| 149 | if (TargetMachine->addPassesToEmitFile(PM, ostream, | 149 | bool NotAdded; |
| 150 | TargetMachine::CGFT_ObjectFile)) { | 150 | #if CLANG_VERSION_MAJOR < 7 |
| 151 | NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream, | ||
| 152 | TargetMachine::CGFT_ObjectFile); | ||
| 153 | #else | ||
| 154 | NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream, nullptr, | ||
| 155 | TargetMachine::CGFT_ObjectFile); | ||
| 156 | #endif | ||
| 157 | if (NotAdded) { | ||
| 151 | llvm::errs() << "TargetMachine can't emit a file of this type\n"; | 158 | llvm::errs() << "TargetMachine can't emit a file of this type\n"; |
| 152 | return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);; | 159 | return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);; |
| 153 | } | 160 | } |
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index decb91f9da82..ccd02634a616 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c | |||
| @@ -93,20 +93,17 @@ static int open_cgroup(const char *name) | |||
| 93 | static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str) | 93 | static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str) |
| 94 | { | 94 | { |
| 95 | struct perf_evsel *counter; | 95 | struct perf_evsel *counter; |
| 96 | struct cgroup *cgrp = NULL; | ||
| 97 | /* | 96 | /* |
| 98 | * check if cgrp is already defined, if so we reuse it | 97 | * check if cgrp is already defined, if so we reuse it |
| 99 | */ | 98 | */ |
| 100 | evlist__for_each_entry(evlist, counter) { | 99 | evlist__for_each_entry(evlist, counter) { |
| 101 | if (!counter->cgrp) | 100 | if (!counter->cgrp) |
| 102 | continue; | 101 | continue; |
| 103 | if (!strcmp(counter->cgrp->name, str)) { | 102 | if (!strcmp(counter->cgrp->name, str)) |
| 104 | cgrp = cgroup__get(counter->cgrp); | 103 | return cgroup__get(counter->cgrp); |
| 105 | break; | ||
| 106 | } | ||
| 107 | } | 104 | } |
| 108 | 105 | ||
| 109 | return cgrp; | 106 | return NULL; |
| 110 | } | 107 | } |
| 111 | 108 | ||
| 112 | static struct cgroup *cgroup__new(const char *name) | 109 | static struct cgroup *cgroup__new(const char *name) |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index cdfc2e5f55f5..51cf82cf1882 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
| @@ -354,6 +354,8 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, | |||
| 354 | if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) || | 354 | if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) || |
| 355 | (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) || | 355 | (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) || |
| 356 | (strncmp(name, "[vdso]", 6) == 0) || | 356 | (strncmp(name, "[vdso]", 6) == 0) || |
| 357 | (strncmp(name, "[vdso32]", 8) == 0) || | ||
| 358 | (strncmp(name, "[vdsox32]", 9) == 0) || | ||
| 357 | (strncmp(name, "[vsyscall]", 10) == 0)) { | 359 | (strncmp(name, "[vsyscall]", 10) == 0)) { |
| 358 | m->kmod = false; | 360 | m->kmod = false; |
| 359 | 361 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 150db5ed7400..94fce4f537e9 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -2197,7 +2197,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
| 2197 | } | 2197 | } |
| 2198 | } | 2198 | } |
| 2199 | 2199 | ||
| 2200 | if (type & PERF_SAMPLE_CALLCHAIN) { | 2200 | if (evsel__has_callchain(evsel)) { |
| 2201 | const u64 max_callchain_nr = UINT64_MAX / sizeof(u64); | 2201 | const u64 max_callchain_nr = UINT64_MAX / sizeof(u64); |
| 2202 | 2202 | ||
| 2203 | OVERFLOW_CHECK_u64(array); | 2203 | OVERFLOW_CHECK_u64(array); |
| @@ -2857,7 +2857,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
| 2857 | "Hint: Try again after reducing the number of events.\n" | 2857 | "Hint: Try again after reducing the number of events.\n" |
| 2858 | "Hint: Try increasing the limit with 'ulimit -n <limit>'"); | 2858 | "Hint: Try increasing the limit with 'ulimit -n <limit>'"); |
| 2859 | case ENOMEM: | 2859 | case ENOMEM: |
| 2860 | if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0 && | 2860 | if (evsel__has_callchain(evsel) && |
| 2861 | access("/proc/sys/kernel/perf_event_max_stack", F_OK) == 0) | 2861 | access("/proc/sys/kernel/perf_event_max_stack", F_OK) == 0) |
| 2862 | return scnprintf(msg, size, | 2862 | return scnprintf(msg, size, |
| 2863 | "Not enough memory to setup event with callchain.\n" | 2863 | "Not enough memory to setup event with callchain.\n" |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index b13f5f234c8f..d277930b19a1 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -459,6 +459,11 @@ static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evs | |||
| 459 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; | 459 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; |
| 460 | } | 460 | } |
| 461 | 461 | ||
| 462 | static inline bool evsel__has_callchain(const struct perf_evsel *evsel) | ||
| 463 | { | ||
| 464 | return (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0; | ||
| 465 | } | ||
| 466 | |||
| 462 | typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); | 467 | typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); |
| 463 | 468 | ||
| 464 | int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, | 469 | int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a8bff2178fbc..653ff65aa2c3 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -1459,8 +1459,24 @@ static void print_cmdline(struct feat_fd *ff, FILE *fp) | |||
| 1459 | 1459 | ||
| 1460 | fprintf(fp, "# cmdline : "); | 1460 | fprintf(fp, "# cmdline : "); |
| 1461 | 1461 | ||
| 1462 | for (i = 0; i < nr; i++) | 1462 | for (i = 0; i < nr; i++) { |
| 1463 | fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]); | 1463 | char *argv_i = strdup(ff->ph->env.cmdline_argv[i]); |
| 1464 | if (!argv_i) { | ||
| 1465 | fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]); | ||
| 1466 | } else { | ||
| 1467 | char *mem = argv_i; | ||
| 1468 | do { | ||
| 1469 | char *quote = strchr(argv_i, '\''); | ||
| 1470 | if (!quote) | ||
| 1471 | break; | ||
| 1472 | *quote++ = '\0'; | ||
| 1473 | fprintf(fp, "%s\\\'", argv_i); | ||
| 1474 | argv_i = quote; | ||
| 1475 | } while (1); | ||
| 1476 | fprintf(fp, "%s ", argv_i); | ||
| 1477 | free(mem); | ||
| 1478 | } | ||
| 1479 | } | ||
| 1464 | fputc('\n', fp); | 1480 | fputc('\n', fp); |
| 1465 | } | 1481 | } |
| 1466 | 1482 | ||
| @@ -2113,6 +2129,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) | |||
| 2113 | int cpu_nr = ff->ph->env.nr_cpus_avail; | 2129 | int cpu_nr = ff->ph->env.nr_cpus_avail; |
| 2114 | u64 size = 0; | 2130 | u64 size = 0; |
| 2115 | struct perf_header *ph = ff->ph; | 2131 | struct perf_header *ph = ff->ph; |
| 2132 | bool do_core_id_test = true; | ||
| 2116 | 2133 | ||
| 2117 | ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); | 2134 | ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); |
| 2118 | if (!ph->env.cpu) | 2135 | if (!ph->env.cpu) |
| @@ -2167,6 +2184,13 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) | |||
| 2167 | return 0; | 2184 | return 0; |
| 2168 | } | 2185 | } |
| 2169 | 2186 | ||
| 2187 | /* On s390 the socket_id number is not related to the numbers of cpus. | ||
| 2188 | * The socket_id number might be higher than the numbers of cpus. | ||
| 2189 | * This depends on the configuration. | ||
| 2190 | */ | ||
| 2191 | if (ph->env.arch && !strncmp(ph->env.arch, "s390", 4)) | ||
| 2192 | do_core_id_test = false; | ||
| 2193 | |||
| 2170 | for (i = 0; i < (u32)cpu_nr; i++) { | 2194 | for (i = 0; i < (u32)cpu_nr; i++) { |
| 2171 | if (do_read_u32(ff, &nr)) | 2195 | if (do_read_u32(ff, &nr)) |
| 2172 | goto free_cpu; | 2196 | goto free_cpu; |
| @@ -2176,7 +2200,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) | |||
| 2176 | if (do_read_u32(ff, &nr)) | 2200 | if (do_read_u32(ff, &nr)) |
| 2177 | goto free_cpu; | 2201 | goto free_cpu; |
| 2178 | 2202 | ||
| 2179 | if (nr != (u32)-1 && nr > (u32)cpu_nr) { | 2203 | if (do_core_id_test && nr != (u32)-1 && nr > (u32)cpu_nr) { |
| 2180 | pr_debug("socket_id number is too big." | 2204 | pr_debug("socket_id number is too big." |
| 2181 | "You may need to upgrade the perf tool.\n"); | 2205 | "You may need to upgrade the perf tool.\n"); |
| 2182 | goto free_cpu; | 2206 | goto free_cpu; |
| @@ -3312,8 +3336,6 @@ int perf_session__read_header(struct perf_session *session) | |||
| 3312 | lseek(fd, tmp, SEEK_SET); | 3336 | lseek(fd, tmp, SEEK_SET); |
| 3313 | } | 3337 | } |
| 3314 | 3338 | ||
| 3315 | symbol_conf.nr_events = nr_attrs; | ||
| 3316 | |||
| 3317 | perf_header__process_sections(header, fd, &session->tevent, | 3339 | perf_header__process_sections(header, fd, &session->tevent, |
| 3318 | perf_file_section__process); | 3340 | perf_file_section__process); |
| 3319 | 3341 | ||
| @@ -3442,7 +3464,7 @@ int perf_event__process_feature(struct perf_tool *tool, | |||
| 3442 | pr_warning("invalid record type %d in pipe-mode\n", type); | 3464 | pr_warning("invalid record type %d in pipe-mode\n", type); |
| 3443 | return 0; | 3465 | return 0; |
| 3444 | } | 3466 | } |
| 3445 | if (feat == HEADER_RESERVED || feat > HEADER_LAST_FEATURE) { | 3467 | if (feat == HEADER_RESERVED || feat >= HEADER_LAST_FEATURE) { |
| 3446 | pr_warning("invalid record type %d in pipe-mode\n", type); | 3468 | pr_warning("invalid record type %d in pipe-mode\n", type); |
| 3447 | return -1; | 3469 | return -1; |
| 3448 | } | 3470 | } |
| @@ -3739,8 +3761,6 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused, | |||
| 3739 | perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); | 3761 | perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); |
| 3740 | } | 3762 | } |
| 3741 | 3763 | ||
| 3742 | symbol_conf.nr_events = evlist->nr_entries; | ||
| 3743 | |||
| 3744 | return 0; | 3764 | return 0; |
| 3745 | } | 3765 | } |
| 3746 | 3766 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 4d602fba40b2..828cb9794c76 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -370,9 +370,11 @@ void hists__delete_entries(struct hists *hists) | |||
| 370 | 370 | ||
| 371 | static int hist_entry__init(struct hist_entry *he, | 371 | static int hist_entry__init(struct hist_entry *he, |
| 372 | struct hist_entry *template, | 372 | struct hist_entry *template, |
| 373 | bool sample_self) | 373 | bool sample_self, |
| 374 | size_t callchain_size) | ||
| 374 | { | 375 | { |
| 375 | *he = *template; | 376 | *he = *template; |
| 377 | he->callchain_size = callchain_size; | ||
| 376 | 378 | ||
| 377 | if (symbol_conf.cumulate_callchain) { | 379 | if (symbol_conf.cumulate_callchain) { |
| 378 | he->stat_acc = malloc(sizeof(he->stat)); | 380 | he->stat_acc = malloc(sizeof(he->stat)); |
| @@ -410,7 +412,7 @@ static int hist_entry__init(struct hist_entry *he, | |||
| 410 | map__get(he->mem_info->daddr.map); | 412 | map__get(he->mem_info->daddr.map); |
| 411 | } | 413 | } |
| 412 | 414 | ||
| 413 | if (symbol_conf.use_callchain) | 415 | if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) |
| 414 | callchain_init(he->callchain); | 416 | callchain_init(he->callchain); |
| 415 | 417 | ||
| 416 | if (he->raw_data) { | 418 | if (he->raw_data) { |
| @@ -473,7 +475,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, | |||
| 473 | 475 | ||
| 474 | he = ops->new(callchain_size); | 476 | he = ops->new(callchain_size); |
| 475 | if (he) { | 477 | if (he) { |
| 476 | err = hist_entry__init(he, template, sample_self); | 478 | err = hist_entry__init(he, template, sample_self, callchain_size); |
| 477 | if (err) { | 479 | if (err) { |
| 478 | ops->free(he); | 480 | ops->free(he); |
| 479 | he = NULL; | 481 | he = NULL; |
| @@ -492,7 +494,7 @@ static u8 symbol__parent_filter(const struct symbol *parent) | |||
| 492 | 494 | ||
| 493 | static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period) | 495 | static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period) |
| 494 | { | 496 | { |
| 495 | if (!symbol_conf.use_callchain) | 497 | if (!hist_entry__has_callchains(he) || !symbol_conf.use_callchain) |
| 496 | return; | 498 | return; |
| 497 | 499 | ||
| 498 | he->hists->callchain_period += period; | 500 | he->hists->callchain_period += period; |
| @@ -619,9 +621,11 @@ __hists__add_entry(struct hists *hists, | |||
| 619 | .raw_data = sample->raw_data, | 621 | .raw_data = sample->raw_data, |
| 620 | .raw_size = sample->raw_size, | 622 | .raw_size = sample->raw_size, |
| 621 | .ops = ops, | 623 | .ops = ops, |
| 622 | }; | 624 | }, *he = hists__findnew_entry(hists, &entry, al, sample_self); |
| 623 | 625 | ||
| 624 | return hists__findnew_entry(hists, &entry, al, sample_self); | 626 | if (!hists->has_callchains && he && he->callchain_size != 0) |
| 627 | hists->has_callchains = true; | ||
| 628 | return he; | ||
| 625 | } | 629 | } |
| 626 | 630 | ||
| 627 | struct hist_entry *hists__add_entry(struct hists *hists, | 631 | struct hist_entry *hists__add_entry(struct hists *hists, |
| @@ -986,7 +990,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, | |||
| 986 | iter->he = he; | 990 | iter->he = he; |
| 987 | he_cache[iter->curr++] = he; | 991 | he_cache[iter->curr++] = he; |
| 988 | 992 | ||
| 989 | if (symbol_conf.use_callchain) | 993 | if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) |
| 990 | callchain_append(he->callchain, &cursor, sample->period); | 994 | callchain_append(he->callchain, &cursor, sample->period); |
| 991 | return 0; | 995 | return 0; |
| 992 | } | 996 | } |
| @@ -1039,7 +1043,7 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | |||
| 1039 | int err, err2; | 1043 | int err, err2; |
| 1040 | struct map *alm = NULL; | 1044 | struct map *alm = NULL; |
| 1041 | 1045 | ||
| 1042 | if (al && al->map) | 1046 | if (al) |
| 1043 | alm = map__get(al->map); | 1047 | alm = map__get(al->map); |
| 1044 | 1048 | ||
| 1045 | err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, | 1049 | err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, |
| @@ -1373,7 +1377,8 @@ static int hists__hierarchy_insert_entry(struct hists *hists, | |||
| 1373 | if (new_he) { | 1377 | if (new_he) { |
| 1374 | new_he->leaf = true; | 1378 | new_he->leaf = true; |
| 1375 | 1379 | ||
| 1376 | if (symbol_conf.use_callchain) { | 1380 | if (hist_entry__has_callchains(new_he) && |
| 1381 | symbol_conf.use_callchain) { | ||
| 1377 | callchain_cursor_reset(&callchain_cursor); | 1382 | callchain_cursor_reset(&callchain_cursor); |
| 1378 | if (callchain_merge(&callchain_cursor, | 1383 | if (callchain_merge(&callchain_cursor, |
| 1379 | new_he->callchain, | 1384 | new_he->callchain, |
| @@ -1414,7 +1419,7 @@ static int hists__collapse_insert_entry(struct hists *hists, | |||
| 1414 | if (symbol_conf.cumulate_callchain) | 1419 | if (symbol_conf.cumulate_callchain) |
| 1415 | he_stat__add_stat(iter->stat_acc, he->stat_acc); | 1420 | he_stat__add_stat(iter->stat_acc, he->stat_acc); |
| 1416 | 1421 | ||
| 1417 | if (symbol_conf.use_callchain) { | 1422 | if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) { |
| 1418 | callchain_cursor_reset(&callchain_cursor); | 1423 | callchain_cursor_reset(&callchain_cursor); |
| 1419 | if (callchain_merge(&callchain_cursor, | 1424 | if (callchain_merge(&callchain_cursor, |
| 1420 | iter->callchain, | 1425 | iter->callchain, |
| @@ -1757,7 +1762,7 @@ void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *pro | |||
| 1757 | bool use_callchain; | 1762 | bool use_callchain; |
| 1758 | 1763 | ||
| 1759 | if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph) | 1764 | if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph) |
| 1760 | use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN; | 1765 | use_callchain = evsel__has_callchain(evsel); |
| 1761 | else | 1766 | else |
| 1762 | use_callchain = symbol_conf.use_callchain; | 1767 | use_callchain = symbol_conf.use_callchain; |
| 1763 | 1768 | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index fbabfd8a215d..73049f7f0f60 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -85,6 +85,7 @@ struct hists { | |||
| 85 | struct events_stats stats; | 85 | struct events_stats stats; |
| 86 | u64 event_stream; | 86 | u64 event_stream; |
| 87 | u16 col_len[HISTC_NR_COLS]; | 87 | u16 col_len[HISTC_NR_COLS]; |
| 88 | bool has_callchains; | ||
| 88 | int socket_filter; | 89 | int socket_filter; |
| 89 | struct perf_hpp_list *hpp_list; | 90 | struct perf_hpp_list *hpp_list; |
| 90 | struct list_head hpp_formats; | 91 | struct list_head hpp_formats; |
| @@ -220,6 +221,11 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel) | |||
| 220 | return &hevsel->hists; | 221 | return &hevsel->hists; |
| 221 | } | 222 | } |
| 222 | 223 | ||
| 224 | static __pure inline bool hists__has_callchains(struct hists *hists) | ||
| 225 | { | ||
| 226 | return hists->has_callchains; | ||
| 227 | } | ||
| 228 | |||
| 223 | int hists__init(void); | 229 | int hists__init(void); |
| 224 | int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list); | 230 | int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list); |
| 225 | 231 | ||
| @@ -419,19 +425,24 @@ struct hist_browser_timer { | |||
| 419 | int refresh; | 425 | int refresh; |
| 420 | }; | 426 | }; |
| 421 | 427 | ||
| 428 | struct annotation_options; | ||
| 429 | |||
| 422 | #ifdef HAVE_SLANG_SUPPORT | 430 | #ifdef HAVE_SLANG_SUPPORT |
| 423 | #include "../ui/keysyms.h" | 431 | #include "../ui/keysyms.h" |
| 424 | int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, | 432 | int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, |
| 425 | struct hist_browser_timer *hbt); | 433 | struct hist_browser_timer *hbt, |
| 434 | struct annotation_options *annotation_opts); | ||
| 426 | 435 | ||
| 427 | int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, | 436 | int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, |
| 428 | struct hist_browser_timer *hbt); | 437 | struct hist_browser_timer *hbt, |
| 438 | struct annotation_options *annotation_opts); | ||
| 429 | 439 | ||
| 430 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | 440 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
| 431 | struct hist_browser_timer *hbt, | 441 | struct hist_browser_timer *hbt, |
| 432 | float min_pcnt, | 442 | float min_pcnt, |
| 433 | struct perf_env *env, | 443 | struct perf_env *env, |
| 434 | bool warn_lost_event); | 444 | bool warn_lost_event, |
| 445 | struct annotation_options *annotation_options); | ||
| 435 | int script_browse(const char *script_opt); | 446 | int script_browse(const char *script_opt); |
| 436 | #else | 447 | #else |
| 437 | static inline | 448 | static inline |
| @@ -440,20 +451,23 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
| 440 | struct hist_browser_timer *hbt __maybe_unused, | 451 | struct hist_browser_timer *hbt __maybe_unused, |
| 441 | float min_pcnt __maybe_unused, | 452 | float min_pcnt __maybe_unused, |
| 442 | struct perf_env *env __maybe_unused, | 453 | struct perf_env *env __maybe_unused, |
| 443 | bool warn_lost_event __maybe_unused) | 454 | bool warn_lost_event __maybe_unused, |
| 455 | struct annotation_options *annotation_options __maybe_unused) | ||
| 444 | { | 456 | { |
| 445 | return 0; | 457 | return 0; |
| 446 | } | 458 | } |
| 447 | static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, | 459 | static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, |
| 448 | struct perf_evsel *evsel __maybe_unused, | 460 | struct perf_evsel *evsel __maybe_unused, |
| 449 | struct hist_browser_timer *hbt __maybe_unused) | 461 | struct hist_browser_timer *hbt __maybe_unused, |
| 462 | struct annotation_options *annotation_options __maybe_unused) | ||
| 450 | { | 463 | { |
| 451 | return 0; | 464 | return 0; |
| 452 | } | 465 | } |
| 453 | 466 | ||
| 454 | static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, | 467 | static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, |
| 455 | struct perf_evsel *evsel __maybe_unused, | 468 | struct perf_evsel *evsel __maybe_unused, |
| 456 | struct hist_browser_timer *hbt __maybe_unused) | 469 | struct hist_browser_timer *hbt __maybe_unused, |
| 470 | struct annotation_options *annotation_opts __maybe_unused) | ||
| 457 | { | 471 | { |
| 458 | return 0; | 472 | return 0; |
| 459 | } | 473 | } |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index f9157aed1289..d404bed7003a 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | |||
| @@ -113,6 +113,7 @@ struct intel_pt_decoder { | |||
| 113 | bool have_cyc; | 113 | bool have_cyc; |
| 114 | bool fixup_last_mtc; | 114 | bool fixup_last_mtc; |
| 115 | bool have_last_ip; | 115 | bool have_last_ip; |
| 116 | enum intel_pt_param_flags flags; | ||
| 116 | uint64_t pos; | 117 | uint64_t pos; |
| 117 | uint64_t last_ip; | 118 | uint64_t last_ip; |
| 118 | uint64_t ip; | 119 | uint64_t ip; |
| @@ -226,6 +227,8 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) | |||
| 226 | decoder->return_compression = params->return_compression; | 227 | decoder->return_compression = params->return_compression; |
| 227 | decoder->branch_enable = params->branch_enable; | 228 | decoder->branch_enable = params->branch_enable; |
| 228 | 229 | ||
| 230 | decoder->flags = params->flags; | ||
| 231 | |||
| 229 | decoder->period = params->period; | 232 | decoder->period = params->period; |
| 230 | decoder->period_type = params->period_type; | 233 | decoder->period_type = params->period_type; |
| 231 | 234 | ||
| @@ -1097,6 +1100,15 @@ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder) | |||
| 1097 | return ret; | 1100 | return ret; |
| 1098 | } | 1101 | } |
| 1099 | 1102 | ||
| 1103 | static inline bool intel_pt_fup_with_nlip(struct intel_pt_decoder *decoder, | ||
| 1104 | struct intel_pt_insn *intel_pt_insn, | ||
| 1105 | uint64_t ip, int err) | ||
| 1106 | { | ||
| 1107 | return decoder->flags & INTEL_PT_FUP_WITH_NLIP && !err && | ||
| 1108 | intel_pt_insn->branch == INTEL_PT_BR_INDIRECT && | ||
| 1109 | ip == decoder->ip + intel_pt_insn->length; | ||
| 1110 | } | ||
| 1111 | |||
| 1100 | static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) | 1112 | static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) |
| 1101 | { | 1113 | { |
| 1102 | struct intel_pt_insn intel_pt_insn; | 1114 | struct intel_pt_insn intel_pt_insn; |
| @@ -1109,10 +1121,11 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) | |||
| 1109 | err = intel_pt_walk_insn(decoder, &intel_pt_insn, ip); | 1121 | err = intel_pt_walk_insn(decoder, &intel_pt_insn, ip); |
| 1110 | if (err == INTEL_PT_RETURN) | 1122 | if (err == INTEL_PT_RETURN) |
| 1111 | return 0; | 1123 | return 0; |
| 1112 | if (err == -EAGAIN) { | 1124 | if (err == -EAGAIN || |
| 1125 | intel_pt_fup_with_nlip(decoder, &intel_pt_insn, ip, err)) { | ||
| 1113 | if (intel_pt_fup_event(decoder)) | 1126 | if (intel_pt_fup_event(decoder)) |
| 1114 | return 0; | 1127 | return 0; |
| 1115 | return err; | 1128 | return -EAGAIN; |
| 1116 | } | 1129 | } |
| 1117 | decoder->set_fup_tx_flags = false; | 1130 | decoder->set_fup_tx_flags = false; |
| 1118 | if (err) | 1131 | if (err) |
| @@ -1376,7 +1389,6 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder) | |||
| 1376 | { | 1389 | { |
| 1377 | intel_pt_log("ERROR: Buffer overflow\n"); | 1390 | intel_pt_log("ERROR: Buffer overflow\n"); |
| 1378 | intel_pt_clear_tx_flags(decoder); | 1391 | intel_pt_clear_tx_flags(decoder); |
| 1379 | decoder->have_tma = false; | ||
| 1380 | decoder->cbr = 0; | 1392 | decoder->cbr = 0; |
| 1381 | decoder->timestamp_insn_cnt = 0; | 1393 | decoder->timestamp_insn_cnt = 0; |
| 1382 | decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; | 1394 | decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; |
| @@ -1604,7 +1616,6 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) | |||
| 1604 | case INTEL_PT_PSB: | 1616 | case INTEL_PT_PSB: |
| 1605 | case INTEL_PT_TSC: | 1617 | case INTEL_PT_TSC: |
| 1606 | case INTEL_PT_TMA: | 1618 | case INTEL_PT_TMA: |
| 1607 | case INTEL_PT_CBR: | ||
| 1608 | case INTEL_PT_MODE_TSX: | 1619 | case INTEL_PT_MODE_TSX: |
| 1609 | case INTEL_PT_BAD: | 1620 | case INTEL_PT_BAD: |
| 1610 | case INTEL_PT_PSBEND: | 1621 | case INTEL_PT_PSBEND: |
| @@ -1620,6 +1631,10 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) | |||
| 1620 | decoder->pkt_step = 0; | 1631 | decoder->pkt_step = 0; |
| 1621 | return -ENOENT; | 1632 | return -ENOENT; |
| 1622 | 1633 | ||
| 1634 | case INTEL_PT_CBR: | ||
| 1635 | intel_pt_calc_cbr(decoder); | ||
| 1636 | break; | ||
| 1637 | |||
| 1623 | case INTEL_PT_OVF: | 1638 | case INTEL_PT_OVF: |
| 1624 | return intel_pt_overflow(decoder); | 1639 | return intel_pt_overflow(decoder); |
| 1625 | 1640 | ||
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index fc1752d50019..51c18d67f4ca 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h | |||
| @@ -60,6 +60,14 @@ enum { | |||
| 60 | INTEL_PT_ERR_MAX, | 60 | INTEL_PT_ERR_MAX, |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | enum intel_pt_param_flags { | ||
| 64 | /* | ||
| 65 | * FUP packet can contain next linear instruction pointer instead of | ||
| 66 | * current linear instruction pointer. | ||
| 67 | */ | ||
| 68 | INTEL_PT_FUP_WITH_NLIP = 1 << 0, | ||
| 69 | }; | ||
| 70 | |||
| 63 | struct intel_pt_state { | 71 | struct intel_pt_state { |
| 64 | enum intel_pt_sample_type type; | 72 | enum intel_pt_sample_type type; |
| 65 | int err; | 73 | int err; |
| @@ -106,6 +114,7 @@ struct intel_pt_params { | |||
| 106 | unsigned int mtc_period; | 114 | unsigned int mtc_period; |
| 107 | uint32_t tsc_ctc_ratio_n; | 115 | uint32_t tsc_ctc_ratio_n; |
| 108 | uint32_t tsc_ctc_ratio_d; | 116 | uint32_t tsc_ctc_ratio_d; |
| 117 | enum intel_pt_param_flags flags; | ||
| 109 | }; | 118 | }; |
| 110 | 119 | ||
| 111 | struct intel_pt_decoder; | 120 | struct intel_pt_decoder; |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index ba4c9dd18643..d426761a549d 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | |||
| @@ -366,7 +366,7 @@ static int intel_pt_get_cyc(unsigned int byte, const unsigned char *buf, | |||
| 366 | if (len < offs) | 366 | if (len < offs) |
| 367 | return INTEL_PT_NEED_MORE_BYTES; | 367 | return INTEL_PT_NEED_MORE_BYTES; |
| 368 | byte = buf[offs++]; | 368 | byte = buf[offs++]; |
| 369 | payload |= (byte >> 1) << shift; | 369 | payload |= ((uint64_t)byte >> 1) << shift; |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | packet->type = INTEL_PT_CYC; | 372 | packet->type = INTEL_PT_CYC; |
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 492986a25ef6..aec68908d604 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c | |||
| @@ -749,6 +749,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, | |||
| 749 | unsigned int queue_nr) | 749 | unsigned int queue_nr) |
| 750 | { | 750 | { |
| 751 | struct intel_pt_params params = { .get_trace = 0, }; | 751 | struct intel_pt_params params = { .get_trace = 0, }; |
| 752 | struct perf_env *env = pt->machine->env; | ||
| 752 | struct intel_pt_queue *ptq; | 753 | struct intel_pt_queue *ptq; |
| 753 | 754 | ||
| 754 | ptq = zalloc(sizeof(struct intel_pt_queue)); | 755 | ptq = zalloc(sizeof(struct intel_pt_queue)); |
| @@ -830,6 +831,9 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, | |||
| 830 | } | 831 | } |
| 831 | } | 832 | } |
| 832 | 833 | ||
| 834 | if (env->cpuid && !strncmp(env->cpuid, "GenuineIntel,6,92,", 18)) | ||
| 835 | params.flags |= INTEL_PT_FUP_WITH_NLIP; | ||
| 836 | |||
| 833 | ptq->decoder = intel_pt_decoder_new(¶ms); | 837 | ptq->decoder = intel_pt_decoder_new(¶ms); |
| 834 | if (!ptq->decoder) | 838 | if (!ptq->decoder) |
| 835 | goto out_free; | 839 | goto out_free; |
| @@ -1521,6 +1525,7 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) | |||
| 1521 | 1525 | ||
| 1522 | if (intel_pt_is_switch_ip(ptq, state->to_ip)) { | 1526 | if (intel_pt_is_switch_ip(ptq, state->to_ip)) { |
| 1523 | switch (ptq->switch_state) { | 1527 | switch (ptq->switch_state) { |
| 1528 | case INTEL_PT_SS_NOT_TRACING: | ||
| 1524 | case INTEL_PT_SS_UNKNOWN: | 1529 | case INTEL_PT_SS_UNKNOWN: |
| 1525 | case INTEL_PT_SS_EXPECTING_SWITCH_IP: | 1530 | case INTEL_PT_SS_EXPECTING_SWITCH_IP: |
| 1526 | err = intel_pt_next_tid(pt, ptq); | 1531 | err = intel_pt_next_tid(pt, ptq); |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 6ae97eda370b..89ac5b5dc218 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
| @@ -415,16 +415,20 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) | |||
| 415 | return fprintf(fp, "%s", dsoname); | 415 | return fprintf(fp, "%s", dsoname); |
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | char *map__srcline(struct map *map, u64 addr, struct symbol *sym) | ||
| 419 | { | ||
| 420 | if (map == NULL) | ||
| 421 | return SRCLINE_UNKNOWN; | ||
| 422 | return get_srcline(map->dso, map__rip_2objdump(map, addr), sym, true, true, addr); | ||
| 423 | } | ||
| 424 | |||
| 418 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | 425 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, |
| 419 | FILE *fp) | 426 | FILE *fp) |
| 420 | { | 427 | { |
| 421 | char *srcline; | ||
| 422 | int ret = 0; | 428 | int ret = 0; |
| 423 | 429 | ||
| 424 | if (map && map->dso) { | 430 | if (map && map->dso) { |
| 425 | srcline = get_srcline(map->dso, | 431 | char *srcline = map__srcline(map, addr, NULL); |
| 426 | map__rip_2objdump(map, addr), NULL, | ||
| 427 | true, true, addr); | ||
| 428 | if (srcline != SRCLINE_UNKNOWN) | 432 | if (srcline != SRCLINE_UNKNOWN) |
| 429 | ret = fprintf(fp, "%s%s", prefix, srcline); | 433 | ret = fprintf(fp, "%s%s", prefix, srcline); |
| 430 | free_srcline(srcline); | 434 | free_srcline(srcline); |
| @@ -445,6 +449,20 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | |||
| 445 | */ | 449 | */ |
| 446 | u64 map__rip_2objdump(struct map *map, u64 rip) | 450 | u64 map__rip_2objdump(struct map *map, u64 rip) |
| 447 | { | 451 | { |
| 452 | struct kmap *kmap = __map__kmap(map); | ||
| 453 | |||
| 454 | /* | ||
| 455 | * vmlinux does not have program headers for PTI entry trampolines and | ||
| 456 | * kcore may not either. However the trampoline object code is on the | ||
| 457 | * main kernel map, so just use that instead. | ||
| 458 | */ | ||
| 459 | if (kmap && is_entry_trampoline(kmap->name) && kmap->kmaps && kmap->kmaps->machine) { | ||
| 460 | struct map *kernel_map = machine__kernel_map(kmap->kmaps->machine); | ||
| 461 | |||
| 462 | if (kernel_map) | ||
| 463 | map = kernel_map; | ||
| 464 | } | ||
| 465 | |||
| 448 | if (!map->dso->adjust_symbols) | 466 | if (!map->dso->adjust_symbols) |
| 449 | return rip; | 467 | return rip; |
| 450 | 468 | ||
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 97e2a063bd65..4cb90f242bed 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
| @@ -169,6 +169,7 @@ static inline void __map__zput(struct map **map) | |||
| 169 | int map__overlap(struct map *l, struct map *r); | 169 | int map__overlap(struct map *l, struct map *r); |
| 170 | size_t map__fprintf(struct map *map, FILE *fp); | 170 | size_t map__fprintf(struct map *map, FILE *fp); |
| 171 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); | 171 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); |
| 172 | char *map__srcline(struct map *map, u64 addr, struct symbol *sym); | ||
| 172 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | 173 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, |
| 173 | FILE *fp); | 174 | FILE *fp); |
| 174 | 175 | ||
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index a1a01b1ac8b8..5f761f3ed0f3 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
| @@ -53,7 +53,21 @@ static int str(yyscan_t scanner, int token) | |||
| 53 | YYSTYPE *yylval = parse_events_get_lval(scanner); | 53 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
| 54 | char *text = parse_events_get_text(scanner); | 54 | char *text = parse_events_get_text(scanner); |
| 55 | 55 | ||
| 56 | yylval->str = strdup(text); | 56 | if (text[0] != '\'') { |
| 57 | yylval->str = strdup(text); | ||
| 58 | } else { | ||
| 59 | /* | ||
| 60 | * If a text tag specified on the command line | ||
| 61 | * contains opening single quite ' then it is | ||
| 62 | * expected that the tag ends with single quote | ||
| 63 | * as well, like this: | ||
| 64 | * name=\'CPU_CLK_UNHALTED.THREAD:cmask=1\' | ||
| 65 | * quotes need to be escaped to bypass shell | ||
| 66 | * processing. | ||
| 67 | */ | ||
| 68 | yylval->str = strndup(&text[1], strlen(text) - 2); | ||
| 69 | } | ||
| 70 | |||
| 57 | return token; | 71 | return token; |
| 58 | } | 72 | } |
| 59 | 73 | ||
| @@ -176,6 +190,7 @@ num_dec [0-9]+ | |||
| 176 | num_hex 0x[a-fA-F0-9]+ | 190 | num_hex 0x[a-fA-F0-9]+ |
| 177 | num_raw_hex [a-fA-F0-9]+ | 191 | num_raw_hex [a-fA-F0-9]+ |
| 178 | name [a-zA-Z_*?\[\]][a-zA-Z0-9_*?.\[\]]* | 192 | name [a-zA-Z_*?\[\]][a-zA-Z0-9_*?.\[\]]* |
| 193 | name_tag [\'][a-zA-Z_*?\[\]][a-zA-Z0-9_*?\-,\.\[\]:=]*[\'] | ||
| 179 | name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]* | 194 | name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]* |
| 180 | drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)? | 195 | drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)? |
| 181 | /* If you add a modifier you need to update check_modifier() */ | 196 | /* If you add a modifier you need to update check_modifier() */ |
| @@ -344,6 +359,7 @@ r{num_raw_hex} { return raw(yyscanner); } | |||
| 344 | {bpf_object} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); } | 359 | {bpf_object} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); } |
| 345 | {bpf_source} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_SOURCE); } | 360 | {bpf_source} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_SOURCE); } |
| 346 | {name} { return pmu_str_check(yyscanner); } | 361 | {name} { return pmu_str_check(yyscanner); } |
| 362 | {name_tag} { return str(yyscanner, PE_NAME); } | ||
| 347 | "/" { BEGIN(config); return '/'; } | 363 | "/" { BEGIN(config); return '/'; } |
| 348 | - { return '-'; } | 364 | - { return '-'; } |
| 349 | , { BEGIN(event); return ','; } | 365 | , { BEGIN(event); return ','; } |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index e37608a87dba..da8fe57691b8 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
| @@ -73,6 +73,7 @@ static void inc_group_count(struct list_head *list, | |||
| 73 | %type <num> value_sym | 73 | %type <num> value_sym |
| 74 | %type <head> event_config | 74 | %type <head> event_config |
| 75 | %type <head> opt_event_config | 75 | %type <head> opt_event_config |
| 76 | %type <head> opt_pmu_config | ||
| 76 | %type <term> event_term | 77 | %type <term> event_term |
| 77 | %type <head> event_pmu | 78 | %type <head> event_pmu |
| 78 | %type <head> event_legacy_symbol | 79 | %type <head> event_legacy_symbol |
| @@ -224,13 +225,18 @@ event_def: event_pmu | | |||
| 224 | event_bpf_file | 225 | event_bpf_file |
| 225 | 226 | ||
| 226 | event_pmu: | 227 | event_pmu: |
| 227 | PE_NAME opt_event_config | 228 | PE_NAME opt_pmu_config |
| 228 | { | 229 | { |
| 230 | struct parse_events_state *parse_state = _parse_state; | ||
| 231 | struct parse_events_error *error = parse_state->error; | ||
| 229 | struct list_head *list, *orig_terms, *terms; | 232 | struct list_head *list, *orig_terms, *terms; |
| 230 | 233 | ||
| 231 | if (parse_events_copy_term_list($2, &orig_terms)) | 234 | if (parse_events_copy_term_list($2, &orig_terms)) |
| 232 | YYABORT; | 235 | YYABORT; |
| 233 | 236 | ||
| 237 | if (error) | ||
| 238 | error->idx = @1.first_column; | ||
| 239 | |||
| 234 | ALLOC_LIST(list); | 240 | ALLOC_LIST(list); |
| 235 | if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) { | 241 | if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) { |
| 236 | struct perf_pmu *pmu = NULL; | 242 | struct perf_pmu *pmu = NULL; |
| @@ -496,6 +502,17 @@ opt_event_config: | |||
| 496 | $$ = NULL; | 502 | $$ = NULL; |
| 497 | } | 503 | } |
| 498 | 504 | ||
| 505 | opt_pmu_config: | ||
| 506 | '/' event_config '/' | ||
| 507 | { | ||
| 508 | $$ = $2; | ||
| 509 | } | ||
| 510 | | | ||
| 511 | '/' '/' | ||
| 512 | { | ||
| 513 | $$ = NULL; | ||
| 514 | } | ||
| 515 | |||
| 499 | start_terms: event_config | 516 | start_terms: event_config |
| 500 | { | 517 | { |
| 501 | struct parse_events_state *parse_state = _parse_state; | 518 | struct parse_events_state *parse_state = _parse_state; |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index d2fb597c9a8c..3ba6a1742f91 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
| @@ -234,6 +234,74 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, | |||
| 234 | return 0; | 234 | return 0; |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | static void perf_pmu_assign_str(char *name, const char *field, char **old_str, | ||
| 238 | char **new_str) | ||
| 239 | { | ||
| 240 | if (!*old_str) | ||
| 241 | goto set_new; | ||
| 242 | |||
| 243 | if (*new_str) { /* Have new string, check with old */ | ||
| 244 | if (strcasecmp(*old_str, *new_str)) | ||
| 245 | pr_debug("alias %s differs in field '%s'\n", | ||
| 246 | name, field); | ||
| 247 | zfree(old_str); | ||
| 248 | } else /* Nothing new --> keep old string */ | ||
| 249 | return; | ||
| 250 | set_new: | ||
| 251 | *old_str = *new_str; | ||
| 252 | *new_str = NULL; | ||
| 253 | } | ||
| 254 | |||
| 255 | static void perf_pmu_update_alias(struct perf_pmu_alias *old, | ||
| 256 | struct perf_pmu_alias *newalias) | ||
| 257 | { | ||
| 258 | perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); | ||
| 259 | perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, | ||
| 260 | &newalias->long_desc); | ||
| 261 | perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); | ||
| 262 | perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr, | ||
| 263 | &newalias->metric_expr); | ||
| 264 | perf_pmu_assign_str(old->name, "metric_name", &old->metric_name, | ||
| 265 | &newalias->metric_name); | ||
| 266 | perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); | ||
| 267 | old->scale = newalias->scale; | ||
| 268 | old->per_pkg = newalias->per_pkg; | ||
| 269 | old->snapshot = newalias->snapshot; | ||
| 270 | memcpy(old->unit, newalias->unit, sizeof(old->unit)); | ||
| 271 | } | ||
| 272 | |||
| 273 | /* Delete an alias entry. */ | ||
| 274 | static void perf_pmu_free_alias(struct perf_pmu_alias *newalias) | ||
| 275 | { | ||
| 276 | zfree(&newalias->name); | ||
| 277 | zfree(&newalias->desc); | ||
| 278 | zfree(&newalias->long_desc); | ||
| 279 | zfree(&newalias->topic); | ||
| 280 | zfree(&newalias->str); | ||
| 281 | zfree(&newalias->metric_expr); | ||
| 282 | zfree(&newalias->metric_name); | ||
| 283 | parse_events_terms__purge(&newalias->terms); | ||
| 284 | free(newalias); | ||
| 285 | } | ||
| 286 | |||
| 287 | /* Merge an alias, search in alias list. If this name is already | ||
| 288 | * present merge both of them to combine all information. | ||
| 289 | */ | ||
| 290 | static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, | ||
| 291 | struct list_head *alist) | ||
| 292 | { | ||
| 293 | struct perf_pmu_alias *a; | ||
| 294 | |||
| 295 | list_for_each_entry(a, alist, list) { | ||
| 296 | if (!strcasecmp(newalias->name, a->name)) { | ||
| 297 | perf_pmu_update_alias(a, newalias); | ||
| 298 | perf_pmu_free_alias(newalias); | ||
| 299 | return true; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | return false; | ||
| 303 | } | ||
| 304 | |||
| 237 | static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, | 305 | static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, |
| 238 | char *desc, char *val, | 306 | char *desc, char *val, |
| 239 | char *long_desc, char *topic, | 307 | char *long_desc, char *topic, |
| @@ -241,9 +309,11 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, | |||
| 241 | char *metric_expr, | 309 | char *metric_expr, |
| 242 | char *metric_name) | 310 | char *metric_name) |
| 243 | { | 311 | { |
| 312 | struct parse_events_term *term; | ||
| 244 | struct perf_pmu_alias *alias; | 313 | struct perf_pmu_alias *alias; |
| 245 | int ret; | 314 | int ret; |
| 246 | int num; | 315 | int num; |
| 316 | char newval[256]; | ||
| 247 | 317 | ||
| 248 | alias = malloc(sizeof(*alias)); | 318 | alias = malloc(sizeof(*alias)); |
| 249 | if (!alias) | 319 | if (!alias) |
| @@ -262,6 +332,27 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, | |||
| 262 | return ret; | 332 | return ret; |
| 263 | } | 333 | } |
| 264 | 334 | ||
| 335 | /* Scan event and remove leading zeroes, spaces, newlines, some | ||
| 336 | * platforms have terms specified as | ||
| 337 | * event=0x0091 (read from files ../<PMU>/events/<FILE> | ||
| 338 | * and terms specified as event=0x91 (read from JSON files). | ||
| 339 | * | ||
| 340 | * Rebuild string to make alias->str member comparable. | ||
| 341 | */ | ||
| 342 | memset(newval, 0, sizeof(newval)); | ||
| 343 | ret = 0; | ||
| 344 | list_for_each_entry(term, &alias->terms, list) { | ||
| 345 | if (ret) | ||
| 346 | ret += scnprintf(newval + ret, sizeof(newval) - ret, | ||
| 347 | ","); | ||
| 348 | if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) | ||
| 349 | ret += scnprintf(newval + ret, sizeof(newval) - ret, | ||
| 350 | "%s=%#x", term->config, term->val.num); | ||
| 351 | else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) | ||
| 352 | ret += scnprintf(newval + ret, sizeof(newval) - ret, | ||
| 353 | "%s=%s", term->config, term->val.str); | ||
| 354 | } | ||
| 355 | |||
| 265 | alias->name = strdup(name); | 356 | alias->name = strdup(name); |
| 266 | if (dir) { | 357 | if (dir) { |
| 267 | /* | 358 | /* |
| @@ -285,9 +376,10 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, | |||
| 285 | snprintf(alias->unit, sizeof(alias->unit), "%s", unit); | 376 | snprintf(alias->unit, sizeof(alias->unit), "%s", unit); |
| 286 | } | 377 | } |
| 287 | alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; | 378 | alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; |
| 288 | alias->str = strdup(val); | 379 | alias->str = strdup(newval); |
| 289 | 380 | ||
| 290 | list_add_tail(&alias->list, list); | 381 | if (!perf_pmu_merge_alias(alias, list)) |
| 382 | list_add_tail(&alias->list, list); | ||
| 291 | 383 | ||
| 292 | return 0; | 384 | return 0; |
| 293 | } | 385 | } |
| @@ -303,6 +395,9 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI | |||
| 303 | 395 | ||
| 304 | buf[ret] = 0; | 396 | buf[ret] = 0; |
| 305 | 397 | ||
| 398 | /* Remove trailing newline from sysfs file */ | ||
| 399 | rtrim(buf); | ||
| 400 | |||
| 306 | return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, | 401 | return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, |
| 307 | NULL, NULL, NULL); | 402 | NULL, NULL, NULL); |
| 308 | } | 403 | } |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 3094f11e7d81..f119eb628dbb 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -165,8 +165,7 @@ static struct map *kernel_get_module_map(const char *module) | |||
| 165 | if (strncmp(pos->dso->short_name + 1, module, | 165 | if (strncmp(pos->dso->short_name + 1, module, |
| 166 | pos->dso->short_name_len - 2) == 0 && | 166 | pos->dso->short_name_len - 2) == 0 && |
| 167 | module[pos->dso->short_name_len - 2] == '\0') { | 167 | module[pos->dso->short_name_len - 2] == '\0') { |
| 168 | map__get(pos); | 168 | return map__get(pos); |
| 169 | return pos; | ||
| 170 | } | 169 | } |
| 171 | } | 170 | } |
| 172 | return NULL; | 171 | return NULL; |
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c deleted file mode 100644 index 22eaa201aa27..000000000000 --- a/tools/perf/util/quote.c +++ /dev/null | |||
| @@ -1,62 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include <errno.h> | ||
| 3 | #include <stdlib.h> | ||
| 4 | #include "strbuf.h" | ||
| 5 | #include "quote.h" | ||
| 6 | #include "util.h" | ||
| 7 | |||
| 8 | /* Help to copy the thing properly quoted for the shell safety. | ||
| 9 | * any single quote is replaced with '\'', any exclamation point | ||
| 10 | * is replaced with '\!', and the whole thing is enclosed in a | ||
| 11 | * | ||
| 12 | * E.g. | ||
| 13 | * original sq_quote result | ||
| 14 | * name ==> name ==> 'name' | ||
| 15 | * a b ==> a b ==> 'a b' | ||
| 16 | * a'b ==> a'\''b ==> 'a'\''b' | ||
| 17 | * a!b ==> a'\!'b ==> 'a'\!'b' | ||
| 18 | */ | ||
| 19 | static inline int need_bs_quote(char c) | ||
| 20 | { | ||
| 21 | return (c == '\'' || c == '!'); | ||
| 22 | } | ||
| 23 | |||
| 24 | static int sq_quote_buf(struct strbuf *dst, const char *src) | ||
| 25 | { | ||
| 26 | char *to_free = NULL; | ||
| 27 | int ret; | ||
| 28 | |||
| 29 | if (dst->buf == src) | ||
| 30 | to_free = strbuf_detach(dst, NULL); | ||
| 31 | |||
| 32 | ret = strbuf_addch(dst, '\''); | ||
| 33 | while (!ret && *src) { | ||
| 34 | size_t len = strcspn(src, "'!"); | ||
| 35 | ret = strbuf_add(dst, src, len); | ||
| 36 | src += len; | ||
| 37 | while (!ret && need_bs_quote(*src)) | ||
| 38 | ret = strbuf_addf(dst, "'\\%c\'", *src++); | ||
| 39 | } | ||
| 40 | if (!ret) | ||
| 41 | ret = strbuf_addch(dst, '\''); | ||
| 42 | free(to_free); | ||
| 43 | |||
| 44 | return ret; | ||
| 45 | } | ||
| 46 | |||
| 47 | int sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) | ||
| 48 | { | ||
| 49 | int i, ret; | ||
| 50 | |||
| 51 | /* Copy into destination buffer. */ | ||
| 52 | ret = strbuf_grow(dst, 255); | ||
| 53 | for (i = 0; !ret && argv[i]; ++i) { | ||
| 54 | ret = strbuf_addch(dst, ' '); | ||
| 55 | if (ret) | ||
| 56 | break; | ||
| 57 | ret = sq_quote_buf(dst, argv[i]); | ||
| 58 | if (maxlen && dst->len > maxlen) | ||
| 59 | return -ENOSPC; | ||
| 60 | } | ||
| 61 | return ret; | ||
| 62 | } | ||
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h deleted file mode 100644 index 274bf26d3511..000000000000 --- a/tools/perf/util/quote.h +++ /dev/null | |||
| @@ -1,31 +0,0 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #ifndef __PERF_QUOTE_H | ||
| 3 | #define __PERF_QUOTE_H | ||
| 4 | |||
| 5 | #include <stddef.h> | ||
| 6 | |||
| 7 | /* Help to copy the thing properly quoted for the shell safety. | ||
| 8 | * any single quote is replaced with '\'', any exclamation point | ||
| 9 | * is replaced with '\!', and the whole thing is enclosed in a | ||
| 10 | * single quote pair. | ||
| 11 | * | ||
| 12 | * For example, if you are passing the result to system() as an | ||
| 13 | * argument: | ||
| 14 | * | ||
| 15 | * sprintf(cmd, "foobar %s %s", sq_quote(arg0), sq_quote(arg1)) | ||
| 16 | * | ||
| 17 | * would be appropriate. If the system() is going to call ssh to | ||
| 18 | * run the command on the other side: | ||
| 19 | * | ||
| 20 | * sprintf(cmd, "git-diff-tree %s %s", sq_quote(arg0), sq_quote(arg1)); | ||
| 21 | * sprintf(rcmd, "ssh %s %s", sq_util/quote.host), sq_quote(cmd)); | ||
| 22 | * | ||
| 23 | * Note that the above examples leak memory! Remember to free result from | ||
| 24 | * sq_quote() in a real application. | ||
| 25 | */ | ||
| 26 | |||
| 27 | struct strbuf; | ||
| 28 | |||
| 29 | int sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); | ||
| 30 | |||
| 31 | #endif /* __PERF_QUOTE_H */ | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 7f8afacd08ee..46e9e19ab1ac 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #include "cpumap.h" | 48 | #include "cpumap.h" |
| 49 | #include "print_binary.h" | 49 | #include "print_binary.h" |
| 50 | #include "stat.h" | 50 | #include "stat.h" |
| 51 | #include "mem-events.h" | ||
| 51 | 52 | ||
| 52 | #if PY_MAJOR_VERSION < 3 | 53 | #if PY_MAJOR_VERSION < 3 |
| 53 | #define _PyUnicode_FromString(arg) \ | 54 | #define _PyUnicode_FromString(arg) \ |
| @@ -372,6 +373,19 @@ static PyObject *get_field_numeric_entry(struct event_format *event, | |||
| 372 | return obj; | 373 | return obj; |
| 373 | } | 374 | } |
| 374 | 375 | ||
| 376 | static const char *get_dsoname(struct map *map) | ||
| 377 | { | ||
| 378 | const char *dsoname = "[unknown]"; | ||
| 379 | |||
| 380 | if (map && map->dso) { | ||
| 381 | if (symbol_conf.show_kernel_path && map->dso->long_name) | ||
| 382 | dsoname = map->dso->long_name; | ||
| 383 | else | ||
| 384 | dsoname = map->dso->name; | ||
| 385 | } | ||
| 386 | |||
| 387 | return dsoname; | ||
| 388 | } | ||
| 375 | 389 | ||
| 376 | static PyObject *python_process_callchain(struct perf_sample *sample, | 390 | static PyObject *python_process_callchain(struct perf_sample *sample, |
| 377 | struct perf_evsel *evsel, | 391 | struct perf_evsel *evsel, |
| @@ -427,14 +441,8 @@ static PyObject *python_process_callchain(struct perf_sample *sample, | |||
| 427 | } | 441 | } |
| 428 | 442 | ||
| 429 | if (node->map) { | 443 | if (node->map) { |
| 430 | struct map *map = node->map; | 444 | const char *dsoname = get_dsoname(node->map); |
| 431 | const char *dsoname = "[unknown]"; | 445 | |
| 432 | if (map && map->dso) { | ||
| 433 | if (symbol_conf.show_kernel_path && map->dso->long_name) | ||
| 434 | dsoname = map->dso->long_name; | ||
| 435 | else | ||
| 436 | dsoname = map->dso->name; | ||
| 437 | } | ||
| 438 | pydict_set_item_string_decref(pyelem, "dso", | 446 | pydict_set_item_string_decref(pyelem, "dso", |
| 439 | _PyUnicode_FromString(dsoname)); | 447 | _PyUnicode_FromString(dsoname)); |
| 440 | } | 448 | } |
| @@ -448,6 +456,166 @@ exit: | |||
| 448 | return pylist; | 456 | return pylist; |
| 449 | } | 457 | } |
| 450 | 458 | ||
| 459 | static PyObject *python_process_brstack(struct perf_sample *sample, | ||
| 460 | struct thread *thread) | ||
| 461 | { | ||
| 462 | struct branch_stack *br = sample->branch_stack; | ||
| 463 | PyObject *pylist; | ||
| 464 | u64 i; | ||
| 465 | |||
| 466 | pylist = PyList_New(0); | ||
| 467 | if (!pylist) | ||
| 468 | Py_FatalError("couldn't create Python list"); | ||
| 469 | |||
| 470 | if (!(br && br->nr)) | ||
| 471 | goto exit; | ||
| 472 | |||
| 473 | for (i = 0; i < br->nr; i++) { | ||
| 474 | PyObject *pyelem; | ||
| 475 | struct addr_location al; | ||
| 476 | const char *dsoname; | ||
| 477 | |||
| 478 | pyelem = PyDict_New(); | ||
| 479 | if (!pyelem) | ||
| 480 | Py_FatalError("couldn't create Python dictionary"); | ||
| 481 | |||
| 482 | pydict_set_item_string_decref(pyelem, "from", | ||
| 483 | PyLong_FromUnsignedLongLong(br->entries[i].from)); | ||
| 484 | pydict_set_item_string_decref(pyelem, "to", | ||
| 485 | PyLong_FromUnsignedLongLong(br->entries[i].to)); | ||
| 486 | pydict_set_item_string_decref(pyelem, "mispred", | ||
| 487 | PyBool_FromLong(br->entries[i].flags.mispred)); | ||
| 488 | pydict_set_item_string_decref(pyelem, "predicted", | ||
| 489 | PyBool_FromLong(br->entries[i].flags.predicted)); | ||
| 490 | pydict_set_item_string_decref(pyelem, "in_tx", | ||
| 491 | PyBool_FromLong(br->entries[i].flags.in_tx)); | ||
| 492 | pydict_set_item_string_decref(pyelem, "abort", | ||
| 493 | PyBool_FromLong(br->entries[i].flags.abort)); | ||
| 494 | pydict_set_item_string_decref(pyelem, "cycles", | ||
| 495 | PyLong_FromUnsignedLongLong(br->entries[i].flags.cycles)); | ||
| 496 | |||
| 497 | thread__find_map(thread, sample->cpumode, | ||
| 498 | br->entries[i].from, &al); | ||
| 499 | dsoname = get_dsoname(al.map); | ||
| 500 | pydict_set_item_string_decref(pyelem, "from_dsoname", | ||
| 501 | _PyUnicode_FromString(dsoname)); | ||
| 502 | |||
| 503 | thread__find_map(thread, sample->cpumode, | ||
| 504 | br->entries[i].to, &al); | ||
| 505 | dsoname = get_dsoname(al.map); | ||
| 506 | pydict_set_item_string_decref(pyelem, "to_dsoname", | ||
| 507 | _PyUnicode_FromString(dsoname)); | ||
| 508 | |||
| 509 | PyList_Append(pylist, pyelem); | ||
| 510 | Py_DECREF(pyelem); | ||
| 511 | } | ||
| 512 | |||
| 513 | exit: | ||
| 514 | return pylist; | ||
| 515 | } | ||
| 516 | |||
| 517 | static unsigned long get_offset(struct symbol *sym, struct addr_location *al) | ||
| 518 | { | ||
| 519 | unsigned long offset; | ||
| 520 | |||
| 521 | if (al->addr < sym->end) | ||
| 522 | offset = al->addr - sym->start; | ||
| 523 | else | ||
| 524 | offset = al->addr - al->map->start - sym->start; | ||
| 525 | |||
| 526 | return offset; | ||
| 527 | } | ||
| 528 | |||
| 529 | static int get_symoff(struct symbol *sym, struct addr_location *al, | ||
| 530 | bool print_off, char *bf, int size) | ||
| 531 | { | ||
| 532 | unsigned long offset; | ||
| 533 | |||
| 534 | if (!sym || !sym->name[0]) | ||
| 535 | return scnprintf(bf, size, "%s", "[unknown]"); | ||
| 536 | |||
| 537 | if (!print_off) | ||
| 538 | return scnprintf(bf, size, "%s", sym->name); | ||
| 539 | |||
| 540 | offset = get_offset(sym, al); | ||
| 541 | |||
| 542 | return scnprintf(bf, size, "%s+0x%x", sym->name, offset); | ||
| 543 | } | ||
| 544 | |||
| 545 | static int get_br_mspred(struct branch_flags *flags, char *bf, int size) | ||
| 546 | { | ||
| 547 | if (!flags->mispred && !flags->predicted) | ||
| 548 | return scnprintf(bf, size, "%s", "-"); | ||
| 549 | |||
| 550 | if (flags->mispred) | ||
| 551 | return scnprintf(bf, size, "%s", "M"); | ||
| 552 | |||
| 553 | return scnprintf(bf, size, "%s", "P"); | ||
| 554 | } | ||
| 555 | |||
| 556 | static PyObject *python_process_brstacksym(struct perf_sample *sample, | ||
| 557 | struct thread *thread) | ||
| 558 | { | ||
| 559 | struct branch_stack *br = sample->branch_stack; | ||
| 560 | PyObject *pylist; | ||
| 561 | u64 i; | ||
| 562 | char bf[512]; | ||
| 563 | struct addr_location al; | ||
| 564 | |||
| 565 | pylist = PyList_New(0); | ||
| 566 | if (!pylist) | ||
| 567 | Py_FatalError("couldn't create Python list"); | ||
| 568 | |||
| 569 | if (!(br && br->nr)) | ||
| 570 | goto exit; | ||
| 571 | |||
| 572 | for (i = 0; i < br->nr; i++) { | ||
| 573 | PyObject *pyelem; | ||
| 574 | |||
| 575 | pyelem = PyDict_New(); | ||
| 576 | if (!pyelem) | ||
| 577 | Py_FatalError("couldn't create Python dictionary"); | ||
| 578 | |||
| 579 | thread__find_symbol(thread, sample->cpumode, | ||
| 580 | br->entries[i].from, &al); | ||
| 581 | get_symoff(al.sym, &al, true, bf, sizeof(bf)); | ||
| 582 | pydict_set_item_string_decref(pyelem, "from", | ||
| 583 | _PyUnicode_FromString(bf)); | ||
| 584 | |||
| 585 | thread__find_symbol(thread, sample->cpumode, | ||
| 586 | br->entries[i].to, &al); | ||
| 587 | get_symoff(al.sym, &al, true, bf, sizeof(bf)); | ||
| 588 | pydict_set_item_string_decref(pyelem, "to", | ||
| 589 | _PyUnicode_FromString(bf)); | ||
| 590 | |||
| 591 | get_br_mspred(&br->entries[i].flags, bf, sizeof(bf)); | ||
| 592 | pydict_set_item_string_decref(pyelem, "pred", | ||
| 593 | _PyUnicode_FromString(bf)); | ||
| 594 | |||
| 595 | if (br->entries[i].flags.in_tx) { | ||
| 596 | pydict_set_item_string_decref(pyelem, "in_tx", | ||
| 597 | _PyUnicode_FromString("X")); | ||
| 598 | } else { | ||
| 599 | pydict_set_item_string_decref(pyelem, "in_tx", | ||
| 600 | _PyUnicode_FromString("-")); | ||
| 601 | } | ||
| 602 | |||
| 603 | if (br->entries[i].flags.abort) { | ||
| 604 | pydict_set_item_string_decref(pyelem, "abort", | ||
| 605 | _PyUnicode_FromString("A")); | ||
| 606 | } else { | ||
| 607 | pydict_set_item_string_decref(pyelem, "abort", | ||
| 608 | _PyUnicode_FromString("-")); | ||
| 609 | } | ||
| 610 | |||
| 611 | PyList_Append(pylist, pyelem); | ||
| 612 | Py_DECREF(pyelem); | ||
| 613 | } | ||
| 614 | |||
| 615 | exit: | ||
| 616 | return pylist; | ||
| 617 | } | ||
| 618 | |||
| 451 | static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) | 619 | static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) |
| 452 | { | 620 | { |
| 453 | PyObject *t; | 621 | PyObject *t; |
| @@ -498,12 +666,63 @@ static void set_sample_read_in_dict(PyObject *dict_sample, | |||
| 498 | pydict_set_item_string_decref(dict_sample, "values", values); | 666 | pydict_set_item_string_decref(dict_sample, "values", values); |
| 499 | } | 667 | } |
| 500 | 668 | ||
| 669 | static void set_sample_datasrc_in_dict(PyObject *dict, | ||
| 670 | struct perf_sample *sample) | ||
| 671 | { | ||
| 672 | struct mem_info mi = { .data_src.val = sample->data_src }; | ||
| 673 | char decode[100]; | ||
| 674 | |||
| 675 | pydict_set_item_string_decref(dict, "datasrc", | ||
| 676 | PyLong_FromUnsignedLongLong(sample->data_src)); | ||
| 677 | |||
| 678 | perf_script__meminfo_scnprintf(decode, 100, &mi); | ||
| 679 | |||
| 680 | pydict_set_item_string_decref(dict, "datasrc_decode", | ||
| 681 | _PyUnicode_FromString(decode)); | ||
| 682 | } | ||
| 683 | |||
| 684 | static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size) | ||
| 685 | { | ||
| 686 | unsigned int i = 0, r; | ||
| 687 | int printed = 0; | ||
| 688 | |||
| 689 | bf[0] = 0; | ||
| 690 | |||
| 691 | for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { | ||
| 692 | u64 val = regs->regs[i++]; | ||
| 693 | |||
| 694 | printed += scnprintf(bf + printed, size - printed, | ||
| 695 | "%5s:0x%" PRIx64 " ", | ||
| 696 | perf_reg_name(r), val); | ||
| 697 | } | ||
| 698 | |||
| 699 | return printed; | ||
| 700 | } | ||
| 701 | |||
| 702 | static void set_regs_in_dict(PyObject *dict, | ||
| 703 | struct perf_sample *sample, | ||
| 704 | struct perf_evsel *evsel) | ||
| 705 | { | ||
| 706 | struct perf_event_attr *attr = &evsel->attr; | ||
| 707 | char bf[512]; | ||
| 708 | |||
| 709 | regs_map(&sample->intr_regs, attr->sample_regs_intr, bf, sizeof(bf)); | ||
| 710 | |||
| 711 | pydict_set_item_string_decref(dict, "iregs", | ||
| 712 | _PyUnicode_FromString(bf)); | ||
| 713 | |||
| 714 | regs_map(&sample->user_regs, attr->sample_regs_user, bf, sizeof(bf)); | ||
| 715 | |||
| 716 | pydict_set_item_string_decref(dict, "uregs", | ||
| 717 | _PyUnicode_FromString(bf)); | ||
| 718 | } | ||
| 719 | |||
| 501 | static PyObject *get_perf_sample_dict(struct perf_sample *sample, | 720 | static PyObject *get_perf_sample_dict(struct perf_sample *sample, |
| 502 | struct perf_evsel *evsel, | 721 | struct perf_evsel *evsel, |
| 503 | struct addr_location *al, | 722 | struct addr_location *al, |
| 504 | PyObject *callchain) | 723 | PyObject *callchain) |
| 505 | { | 724 | { |
| 506 | PyObject *dict, *dict_sample; | 725 | PyObject *dict, *dict_sample, *brstack, *brstacksym; |
| 507 | 726 | ||
| 508 | dict = PyDict_New(); | 727 | dict = PyDict_New(); |
| 509 | if (!dict) | 728 | if (!dict) |
| @@ -534,6 +753,11 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, | |||
| 534 | pydict_set_item_string_decref(dict_sample, "addr", | 753 | pydict_set_item_string_decref(dict_sample, "addr", |
| 535 | PyLong_FromUnsignedLongLong(sample->addr)); | 754 | PyLong_FromUnsignedLongLong(sample->addr)); |
| 536 | set_sample_read_in_dict(dict_sample, sample, evsel); | 755 | set_sample_read_in_dict(dict_sample, sample, evsel); |
| 756 | pydict_set_item_string_decref(dict_sample, "weight", | ||
| 757 | PyLong_FromUnsignedLongLong(sample->weight)); | ||
| 758 | pydict_set_item_string_decref(dict_sample, "transaction", | ||
| 759 | PyLong_FromUnsignedLongLong(sample->transaction)); | ||
| 760 | set_sample_datasrc_in_dict(dict_sample, sample); | ||
| 537 | pydict_set_item_string_decref(dict, "sample", dict_sample); | 761 | pydict_set_item_string_decref(dict, "sample", dict_sample); |
| 538 | 762 | ||
| 539 | pydict_set_item_string_decref(dict, "raw_buf", _PyBytes_FromStringAndSize( | 763 | pydict_set_item_string_decref(dict, "raw_buf", _PyBytes_FromStringAndSize( |
| @@ -551,6 +775,14 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, | |||
| 551 | 775 | ||
| 552 | pydict_set_item_string_decref(dict, "callchain", callchain); | 776 | pydict_set_item_string_decref(dict, "callchain", callchain); |
| 553 | 777 | ||
| 778 | brstack = python_process_brstack(sample, al->thread); | ||
| 779 | pydict_set_item_string_decref(dict, "brstack", brstack); | ||
| 780 | |||
| 781 | brstacksym = python_process_brstacksym(sample, al->thread); | ||
| 782 | pydict_set_item_string_decref(dict, "brstacksym", brstacksym); | ||
| 783 | |||
| 784 | set_regs_in_dict(dict, sample, evsel); | ||
| 785 | |||
| 554 | return dict; | 786 | return dict; |
| 555 | } | 787 | } |
| 556 | 788 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index b998bb475589..8b9369303561 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -1094,7 +1094,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | |||
| 1094 | 1094 | ||
| 1095 | sample_type = evsel->attr.sample_type; | 1095 | sample_type = evsel->attr.sample_type; |
| 1096 | 1096 | ||
| 1097 | if (sample_type & PERF_SAMPLE_CALLCHAIN) | 1097 | if (evsel__has_callchain(evsel)) |
| 1098 | callchain__printf(evsel, sample); | 1098 | callchain__printf(evsel, sample); |
| 1099 | 1099 | ||
| 1100 | if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !perf_evsel__has_branch_callstack(evsel)) | 1100 | if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !perf_evsel__has_branch_callstack(evsel)) |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 4058ade352a5..fed2952ab45a 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
| @@ -331,24 +331,18 @@ struct sort_entry sort_sym = { | |||
| 331 | 331 | ||
| 332 | /* --sort srcline */ | 332 | /* --sort srcline */ |
| 333 | 333 | ||
| 334 | char *hist_entry__get_srcline(struct hist_entry *he) | 334 | char *hist_entry__srcline(struct hist_entry *he) |
| 335 | { | 335 | { |
| 336 | struct map *map = he->ms.map; | 336 | return map__srcline(he->ms.map, he->ip, he->ms.sym); |
| 337 | |||
| 338 | if (!map) | ||
| 339 | return SRCLINE_UNKNOWN; | ||
| 340 | |||
| 341 | return get_srcline(map->dso, map__rip_2objdump(map, he->ip), | ||
| 342 | he->ms.sym, true, true, he->ip); | ||
| 343 | } | 337 | } |
| 344 | 338 | ||
| 345 | static int64_t | 339 | static int64_t |
| 346 | sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) | 340 | sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) |
| 347 | { | 341 | { |
| 348 | if (!left->srcline) | 342 | if (!left->srcline) |
| 349 | left->srcline = hist_entry__get_srcline(left); | 343 | left->srcline = hist_entry__srcline(left); |
| 350 | if (!right->srcline) | 344 | if (!right->srcline) |
| 351 | right->srcline = hist_entry__get_srcline(right); | 345 | right->srcline = hist_entry__srcline(right); |
| 352 | 346 | ||
| 353 | return strcmp(right->srcline, left->srcline); | 347 | return strcmp(right->srcline, left->srcline); |
| 354 | } | 348 | } |
| @@ -357,7 +351,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, | |||
| 357 | size_t size, unsigned int width) | 351 | size_t size, unsigned int width) |
| 358 | { | 352 | { |
| 359 | if (!he->srcline) | 353 | if (!he->srcline) |
| 360 | he->srcline = hist_entry__get_srcline(he); | 354 | he->srcline = hist_entry__srcline(he); |
| 361 | 355 | ||
| 362 | return repsep_snprintf(bf, size, "%-.*s", width, he->srcline); | 356 | return repsep_snprintf(bf, size, "%-.*s", width, he->srcline); |
| 363 | } | 357 | } |
| @@ -371,33 +365,20 @@ struct sort_entry sort_srcline = { | |||
| 371 | 365 | ||
| 372 | /* --sort srcline_from */ | 366 | /* --sort srcline_from */ |
| 373 | 367 | ||
| 368 | static char *addr_map_symbol__srcline(struct addr_map_symbol *ams) | ||
| 369 | { | ||
| 370 | return map__srcline(ams->map, ams->al_addr, ams->sym); | ||
| 371 | } | ||
| 372 | |||
| 374 | static int64_t | 373 | static int64_t |
| 375 | sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) | 374 | sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) |
| 376 | { | 375 | { |
| 377 | if (!left->branch_info->srcline_from) { | 376 | if (!left->branch_info->srcline_from) |
| 378 | struct map *map = left->branch_info->from.map; | 377 | left->branch_info->srcline_from = addr_map_symbol__srcline(&left->branch_info->from); |
| 379 | if (!map) | 378 | |
| 380 | left->branch_info->srcline_from = SRCLINE_UNKNOWN; | 379 | if (!right->branch_info->srcline_from) |
| 381 | else | 380 | right->branch_info->srcline_from = addr_map_symbol__srcline(&right->branch_info->from); |
| 382 | left->branch_info->srcline_from = get_srcline(map->dso, | 381 | |
| 383 | map__rip_2objdump(map, | ||
| 384 | left->branch_info->from.al_addr), | ||
| 385 | left->branch_info->from.sym, | ||
| 386 | true, true, | ||
| 387 | left->branch_info->from.al_addr); | ||
| 388 | } | ||
| 389 | if (!right->branch_info->srcline_from) { | ||
| 390 | struct map *map = right->branch_info->from.map; | ||
| 391 | if (!map) | ||
| 392 | right->branch_info->srcline_from = SRCLINE_UNKNOWN; | ||
| 393 | else | ||
| 394 | right->branch_info->srcline_from = get_srcline(map->dso, | ||
| 395 | map__rip_2objdump(map, | ||
| 396 | right->branch_info->from.al_addr), | ||
| 397 | right->branch_info->from.sym, | ||
| 398 | true, true, | ||
| 399 | right->branch_info->from.al_addr); | ||
| 400 | } | ||
| 401 | return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); | 382 | return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); |
| 402 | } | 383 | } |
| 403 | 384 | ||
| @@ -419,30 +400,12 @@ struct sort_entry sort_srcline_from = { | |||
| 419 | static int64_t | 400 | static int64_t |
| 420 | sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) | 401 | sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) |
| 421 | { | 402 | { |
| 422 | if (!left->branch_info->srcline_to) { | 403 | if (!left->branch_info->srcline_to) |
| 423 | struct map *map = left->branch_info->to.map; | 404 | left->branch_info->srcline_to = addr_map_symbol__srcline(&left->branch_info->to); |
| 424 | if (!map) | 405 | |
| 425 | left->branch_info->srcline_to = SRCLINE_UNKNOWN; | 406 | if (!right->branch_info->srcline_to) |
| 426 | else | 407 | right->branch_info->srcline_to = addr_map_symbol__srcline(&right->branch_info->to); |
| 427 | left->branch_info->srcline_to = get_srcline(map->dso, | 408 | |
| 428 | map__rip_2objdump(map, | ||
| 429 | left->branch_info->to.al_addr), | ||
| 430 | left->branch_info->from.sym, | ||
| 431 | true, true, | ||
| 432 | left->branch_info->to.al_addr); | ||
| 433 | } | ||
| 434 | if (!right->branch_info->srcline_to) { | ||
| 435 | struct map *map = right->branch_info->to.map; | ||
| 436 | if (!map) | ||
| 437 | right->branch_info->srcline_to = SRCLINE_UNKNOWN; | ||
| 438 | else | ||
| 439 | right->branch_info->srcline_to = get_srcline(map->dso, | ||
| 440 | map__rip_2objdump(map, | ||
| 441 | right->branch_info->to.al_addr), | ||
| 442 | right->branch_info->to.sym, | ||
| 443 | true, true, | ||
| 444 | right->branch_info->to.al_addr); | ||
| 445 | } | ||
| 446 | return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); | 409 | return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); |
| 447 | } | 410 | } |
| 448 | 411 | ||
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 9e6896293bbd..8bf302cafcec 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
| @@ -112,6 +112,8 @@ struct hist_entry { | |||
| 112 | 112 | ||
| 113 | char level; | 113 | char level; |
| 114 | u8 filtered; | 114 | u8 filtered; |
| 115 | |||
| 116 | u16 callchain_size; | ||
| 115 | union { | 117 | union { |
| 116 | /* | 118 | /* |
| 117 | * Since perf diff only supports the stdio output, TUI | 119 | * Since perf diff only supports the stdio output, TUI |
| @@ -151,6 +153,11 @@ struct hist_entry { | |||
| 151 | struct callchain_root callchain[0]; /* must be last member */ | 153 | struct callchain_root callchain[0]; /* must be last member */ |
| 152 | }; | 154 | }; |
| 153 | 155 | ||
| 156 | static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) | ||
| 157 | { | ||
| 158 | return he->callchain_size != 0; | ||
| 159 | } | ||
| 160 | |||
| 154 | static inline bool hist_entry__has_pairs(struct hist_entry *he) | 161 | static inline bool hist_entry__has_pairs(struct hist_entry *he) |
| 155 | { | 162 | { |
| 156 | return !list_empty(&he->pairs.node); | 163 | return !list_empty(&he->pairs.node); |
| @@ -292,5 +299,5 @@ int64_t | |||
| 292 | sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right); | 299 | sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right); |
| 293 | int64_t | 300 | int64_t |
| 294 | sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right); | 301 | sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right); |
| 295 | char *hist_entry__get_srcline(struct hist_entry *he); | 302 | char *hist_entry__srcline(struct hist_entry *he); |
| 296 | #endif /* __PERF_SORT_H */ | 303 | #endif /* __PERF_SORT_H */ |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8c84437f2a10..d188b7588152 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -40,7 +40,6 @@ char **vmlinux_path; | |||
| 40 | struct symbol_conf symbol_conf = { | 40 | struct symbol_conf symbol_conf = { |
| 41 | .use_modules = true, | 41 | .use_modules = true, |
| 42 | .try_vmlinux_path = true, | 42 | .try_vmlinux_path = true, |
| 43 | .annotate_src = true, | ||
| 44 | .demangle = true, | 43 | .demangle = true, |
| 45 | .demangle_kernel = false, | 44 | .demangle_kernel = false, |
| 46 | .cumulate_callchain = true, | 45 | .cumulate_callchain = true, |
| @@ -74,7 +73,7 @@ static enum dso_binary_type binary_type_symtab[] = { | |||
| 74 | static bool symbol_type__filter(char symbol_type) | 73 | static bool symbol_type__filter(char symbol_type) |
| 75 | { | 74 | { |
| 76 | symbol_type = toupper(symbol_type); | 75 | symbol_type = toupper(symbol_type); |
| 77 | return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D'; | 76 | return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B'; |
| 78 | } | 77 | } |
| 79 | 78 | ||
| 80 | static int prefix_underscores_count(const char *str) | 79 | static int prefix_underscores_count(const char *str) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 1a16438eb3ce..f25fae4b5743 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -90,7 +90,6 @@ struct intlist; | |||
| 90 | 90 | ||
| 91 | struct symbol_conf { | 91 | struct symbol_conf { |
| 92 | unsigned short priv_size; | 92 | unsigned short priv_size; |
| 93 | unsigned short nr_events; | ||
| 94 | bool try_vmlinux_path, | 93 | bool try_vmlinux_path, |
| 95 | init_annotation, | 94 | init_annotation, |
| 96 | force, | 95 | force, |
| @@ -109,8 +108,6 @@ struct symbol_conf { | |||
| 109 | show_cpu_utilization, | 108 | show_cpu_utilization, |
| 110 | initialized, | 109 | initialized, |
| 111 | kptr_restrict, | 110 | kptr_restrict, |
| 112 | annotate_asm_raw, | ||
| 113 | annotate_src, | ||
| 114 | event_group, | 111 | event_group, |
| 115 | demangle, | 112 | demangle, |
| 116 | demangle_kernel, | 113 | demangle_kernel, |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 9892323cdd7c..9add1f72ce95 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #define __PERF_TOP_H 1 | 3 | #define __PERF_TOP_H 1 |
| 4 | 4 | ||
| 5 | #include "tool.h" | 5 | #include "tool.h" |
| 6 | #include "annotate.h" | ||
| 6 | #include <linux/types.h> | 7 | #include <linux/types.h> |
| 7 | #include <stddef.h> | 8 | #include <stddef.h> |
| 8 | #include <stdbool.h> | 9 | #include <stdbool.h> |
| @@ -16,6 +17,7 @@ struct perf_top { | |||
| 16 | struct perf_tool tool; | 17 | struct perf_tool tool; |
| 17 | struct perf_evlist *evlist; | 18 | struct perf_evlist *evlist; |
| 18 | struct record_opts record_opts; | 19 | struct record_opts record_opts; |
| 20 | struct annotation_options annotation_opts; | ||
| 19 | /* | 21 | /* |
| 20 | * Symbols will be added here in perf_event__process_sample and will | 22 | * Symbols will be added here in perf_event__process_sample and will |
| 21 | * get out after decayed. | 23 | * get out after decayed. |
| @@ -35,7 +37,6 @@ struct perf_top { | |||
| 35 | struct perf_session *session; | 37 | struct perf_session *session; |
| 36 | struct winsize winsize; | 38 | struct winsize winsize; |
| 37 | int realtime_prio; | 39 | int realtime_prio; |
| 38 | int sym_pcnt_filter; | ||
| 39 | const char *sym_filter; | 40 | const char *sym_filter; |
| 40 | float min_percent; | 41 | float min_percent; |
| 41 | unsigned int nr_threads_synthesize; | 42 | unsigned int nr_threads_synthesize; |
