Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'perf-core-for-mingo-20160330' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes:

User visible changes:

- Add support for skipping itrace instructions, useful to fast forward
processor trace (Intel PT, BTS) to right after initialization code at the start
of a workload (Andi Kleen)

- Add support for backtraces in perl 'perf script's (Dima Kogan)

- Add -U/-K (--all-user/--all-kernel) options to 'perf mem' (Jiri Olsa)

- Make -f/--force option documentation consistent across tools (Jiri Olsa)

Infrastructure changes:

- Add 'perf test' to check for event times (Jiri Olsa)

- 'perf config' cleanups (Taeung Song)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>

+448 -55
+7
tools/perf/Documentation/intel-pt.txt
··· 672 672 d create a debug log 673 673 g synthesize a call chain (use with i or x) 674 674 l synthesize last branch entries (use with i or x) 675 + s skip initial number of events 675 676 676 677 "Instructions" events look like they were recorded by "perf record -e 677 678 instructions". ··· 731 730 732 731 To disable trace decoding entirely, use the option --no-itrace. 733 732 733 + It is also possible to skip events generated (instructions, branches, transactions) 734 + at the beginning. This is useful to ignore initialization code. 735 + 736 + --itrace=i0nss1000000 737 + 738 + skips the first million instructions. 734 739 735 740 dump option 736 741 -----------
+8
tools/perf/Documentation/itrace.txt
··· 7 7 d create a debug log 8 8 g synthesize a call chain (use with i or x) 9 9 l synthesize last branch entries (use with i or x) 10 + s skip initial number of events 10 11 11 12 The default is all events i.e. the same as --itrace=ibxe 12 13 ··· 25 24 26 25 Also the number of last branch entries (default 64, max. 1024) for 27 26 instructions or transactions events can be specified. 27 + 28 + It is also possible to skip events generated (instructions, branches, transactions) 29 + at the beginning. This is useful to ignore initialization code. 30 + 31 + --itrace=i0nss1000000 32 + 33 + skips the first million instructions.
+1 -1
tools/perf/Documentation/perf-annotate.txt
··· 33 33 34 34 -f:: 35 35 --force:: 36 - Don't complain, do it. 36 + Don't do ownership validation. 37 37 38 38 -v:: 39 39 --verbose::
+1 -1
tools/perf/Documentation/perf-diff.txt
··· 75 75 76 76 -f:: 77 77 --force:: 78 - Don't complain, do it. 78 + Don't do ownership validation. 79 79 80 80 --symfs=<directory>:: 81 81 Look for files with symbols relative to this directory.
+8
tools/perf/Documentation/perf-mem.txt
··· 48 48 option can be passed in record mode. It will be interpreted the same way as perf 49 49 record. 50 50 51 + -K:: 52 + --all-kernel:: 53 + Configure all used events to run in kernel space. 54 + 55 + -U:: 56 + --all-user:: 57 + Configure all used events to run in user space. 58 + 51 59 SEE ALSO 52 60 -------- 53 61 linkperf:perf-record[1], linkperf:perf-report[1]
+1 -1
tools/perf/Documentation/perf-report.txt
··· 285 285 286 286 -f:: 287 287 --force:: 288 - Don't complain, do it. 288 + Don't do ownership validation. 289 289 290 290 --symfs=<directory>:: 291 291 Look for files with symbols relative to this directory.
+4
tools/perf/Documentation/perf-script.txt
··· 262 262 --ns:: 263 263 Use 9 decimal places when displaying time (i.e. show the nanoseconds) 264 264 265 + -f:: 266 + --force:: 267 + Don't do ownership validation. 268 + 265 269 SEE ALSO 266 270 -------- 267 271 linkperf:perf-record[1], linkperf:perf-script-perl[1],
+10 -1
tools/perf/builtin-mem.c
··· 62 62 int rec_argc, i = 0, j; 63 63 const char **rec_argv; 64 64 int ret; 65 + bool all_user = false, all_kernel = false; 65 66 struct option options[] = { 66 67 OPT_CALLBACK('e', "event", &mem, "event", 67 68 "event selector. use 'perf mem record -e list' to list available events", 68 69 parse_record_events), 69 70 OPT_INCR('v', "verbose", &verbose, 70 71 "be more verbose (show counter open errors, etc)"), 72 + OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"), 73 + OPT_BOOLEAN('K', "--all-kernel", &all_kernel, "collect only kernel level data"), 71 74 OPT_END() 72 75 }; 73 76 74 77 argc = parse_options(argc, argv, options, record_mem_usage, 75 78 PARSE_OPT_STOP_AT_NON_OPTION); 76 79 77 - rec_argc = argc + 7; /* max number of arguments */ 80 + rec_argc = argc + 9; /* max number of arguments */ 78 81 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 79 82 if (!rec_argv) 80 83 return -1; ··· 105 102 rec_argv[i++] = "-e"; 106 103 rec_argv[i++] = perf_mem_events__name(j); 107 104 }; 105 + 106 + if (all_user) 107 + rec_argv[i++] = "--all-user"; 108 + 109 + if (all_kernel) 110 + rec_argv[i++] = "--all-kernel"; 108 111 109 112 for (j = 0; j < argc; j++, i++) 110 113 rec_argv[i] = argv[j];
+1 -2
tools/perf/perf.c
··· 549 549 srandom(time(NULL)); 550 550 551 551 perf_config(perf_default_config, NULL); 552 + set_buildid_dir(NULL); 552 553 553 554 /* get debugfs/tracefs mount point from /proc/mounts */ 554 555 tracing_path_mount(); ··· 573 572 } 574 573 if (!prefixcmp(cmd, "trace")) { 575 574 #ifdef HAVE_LIBAUDIT_SUPPORT 576 - set_buildid_dir(NULL); 577 575 setup_path(); 578 576 argv[0] = "trace"; 579 577 return cmd_trace(argc, argv, NULL); ··· 587 587 argc--; 588 588 handle_options(&argv, &argc, NULL); 589 589 commit_pager_choice(); 590 - set_buildid_dir(NULL); 591 590 592 591 if (argc > 0) { 593 592 if (!prefixcmp(argv[0], "--"))
+1
tools/perf/tests/Build
··· 37 37 perf-y += cpumap.o 38 38 perf-y += stat.o 39 39 perf-y += event_update.o 40 + perf-y += event-times.o 40 41 41 42 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build 42 43 $(call rule_mkdir)
+4
tools/perf/tests/builtin-test.c
··· 204 204 .func = test__event_update, 205 205 }, 206 206 { 207 + .desc = "Test events times", 208 + .func = test__event_times, 209 + }, 210 + { 207 211 .func = NULL, 208 212 }, 209 213 };
+236
tools/perf/tests/event-times.c
··· 1 + #include <linux/compiler.h> 2 + #include <string.h> 3 + #include "tests.h" 4 + #include "evlist.h" 5 + #include "evsel.h" 6 + #include "util.h" 7 + #include "debug.h" 8 + #include "thread_map.h" 9 + #include "target.h" 10 + 11 + static int attach__enable_on_exec(struct perf_evlist *evlist) 12 + { 13 + struct perf_evsel *evsel = perf_evlist__last(evlist); 14 + struct target target = { 15 + .uid = UINT_MAX, 16 + }; 17 + const char *argv[] = { "true", NULL, }; 18 + char sbuf[STRERR_BUFSIZE]; 19 + int err; 20 + 21 + pr_debug("attaching to spawned child, enable on exec\n"); 22 + 23 + err = perf_evlist__create_maps(evlist, &target); 24 + if (err < 0) { 25 + pr_debug("Not enough memory to create thread/cpu maps\n"); 26 + return err; 27 + } 28 + 29 + err = perf_evlist__prepare_workload(evlist, &target, argv, false, NULL); 30 + if (err < 0) { 31 + pr_debug("Couldn't run the workload!\n"); 32 + return err; 33 + } 34 + 35 + evsel->attr.enable_on_exec = 1; 36 + 37 + err = perf_evlist__open(evlist); 38 + if (err < 0) { 39 + pr_debug("perf_evlist__open: %s\n", 40 + strerror_r(errno, sbuf, sizeof(sbuf))); 41 + return err; 42 + } 43 + 44 + return perf_evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL; 45 + } 46 + 47 + static int detach__enable_on_exec(struct perf_evlist *evlist) 48 + { 49 + waitpid(evlist->workload.pid, NULL, 0); 50 + return 0; 51 + } 52 + 53 + static int attach__current_disabled(struct perf_evlist *evlist) 54 + { 55 + struct perf_evsel *evsel = perf_evlist__last(evlist); 56 + struct thread_map *threads; 57 + int err; 58 + 59 + pr_debug("attaching to current thread as disabled\n"); 60 + 61 + threads = thread_map__new(-1, getpid(), UINT_MAX); 62 + if (threads == NULL) { 63 + pr_debug("thread_map__new\n"); 64 + return -1; 65 + } 66 + 67 + evsel->attr.disabled = 1; 68 + 69 + err = perf_evsel__open_per_thread(evsel, threads); 70 + if (err) { 71 + pr_debug("Failed to open event cpu-clock:u\n"); 72 + return err; 73 + } 74 + 75 + thread_map__put(threads); 76 + return perf_evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL; 77 + } 78 + 79 + static int attach__current_enabled(struct perf_evlist *evlist) 80 + { 81 + struct perf_evsel *evsel = perf_evlist__last(evlist); 82 + struct thread_map *threads; 83 + int err; 84 + 85 + pr_debug("attaching to current thread as enabled\n"); 86 + 87 + threads = thread_map__new(-1, getpid(), UINT_MAX); 88 + if (threads == NULL) { 89 + pr_debug("failed to call thread_map__new\n"); 90 + return -1; 91 + } 92 + 93 + err = perf_evsel__open_per_thread(evsel, threads); 94 + 95 + thread_map__put(threads); 96 + return err == 0 ? TEST_OK : TEST_FAIL; 97 + } 98 + 99 + static int detach__disable(struct perf_evlist *evlist) 100 + { 101 + struct perf_evsel *evsel = perf_evlist__last(evlist); 102 + 103 + return perf_evsel__enable(evsel); 104 + } 105 + 106 + static int attach__cpu_disabled(struct perf_evlist *evlist) 107 + { 108 + struct perf_evsel *evsel = perf_evlist__last(evlist); 109 + struct cpu_map *cpus; 110 + int err; 111 + 112 + pr_debug("attaching to CPU 0 as enabled\n"); 113 + 114 + cpus = cpu_map__new("0"); 115 + if (cpus == NULL) { 116 + pr_debug("failed to call cpu_map__new\n"); 117 + return -1; 118 + } 119 + 120 + evsel->attr.disabled = 1; 121 + 122 + err = perf_evsel__open_per_cpu(evsel, cpus); 123 + if (err) { 124 + if (err == -EACCES) 125 + return TEST_SKIP; 126 + 127 + pr_debug("Failed to open event cpu-clock:u\n"); 128 + return err; 129 + } 130 + 131 + cpu_map__put(cpus); 132 + return perf_evsel__enable(evsel); 133 + } 134 + 135 + static int attach__cpu_enabled(struct perf_evlist *evlist) 136 + { 137 + struct perf_evsel *evsel = perf_evlist__last(evlist); 138 + struct cpu_map *cpus; 139 + int err; 140 + 141 + pr_debug("attaching to CPU 0 as enabled\n"); 142 + 143 + cpus = cpu_map__new("0"); 144 + if (cpus == NULL) { 145 + pr_debug("failed to call cpu_map__new\n"); 146 + return -1; 147 + } 148 + 149 + err = perf_evsel__open_per_cpu(evsel, cpus); 150 + if (err == -EACCES) 151 + return TEST_SKIP; 152 + 153 + cpu_map__put(cpus); 154 + return err ? TEST_FAIL : TEST_OK; 155 + } 156 + 157 + static int test_times(int (attach)(struct perf_evlist *), 158 + int (detach)(struct perf_evlist *)) 159 + { 160 + struct perf_counts_values count; 161 + struct perf_evlist *evlist = NULL; 162 + struct perf_evsel *evsel; 163 + int err = -1, i; 164 + 165 + evlist = perf_evlist__new(); 166 + if (!evlist) { 167 + pr_debug("failed to create event list\n"); 168 + goto out_err; 169 + } 170 + 171 + err = parse_events(evlist, "cpu-clock:u", NULL); 172 + if (err) { 173 + pr_debug("failed to parse event cpu-clock:u\n"); 174 + goto out_err; 175 + } 176 + 177 + evsel = perf_evlist__last(evlist); 178 + evsel->attr.read_format |= 179 + PERF_FORMAT_TOTAL_TIME_ENABLED | 180 + PERF_FORMAT_TOTAL_TIME_RUNNING; 181 + 182 + err = attach(evlist); 183 + if (err == TEST_SKIP) { 184 + pr_debug(" SKIP : not enough rights\n"); 185 + return err; 186 + } 187 + 188 + TEST_ASSERT_VAL("failed to attach", !err); 189 + 190 + for (i = 0; i < 100000000; i++) { } 191 + 192 + TEST_ASSERT_VAL("failed to detach", !detach(evlist)); 193 + 194 + perf_evsel__read(evsel, 0, 0, &count); 195 + 196 + err = !(count.ena == count.run); 197 + 198 + pr_debug(" %s: ena %" PRIu64", run %" PRIu64"\n", 199 + !err ? "OK " : "FAILED", 200 + count.ena, count.run); 201 + 202 + out_err: 203 + if (evlist) 204 + perf_evlist__delete(evlist); 205 + return !err ? TEST_OK : TEST_FAIL; 206 + } 207 + 208 + /* 209 + * This test creates software event 'cpu-clock' 210 + * attaches it in several ways (explained below) 211 + * and checks that enabled and running times 212 + * match. 213 + */ 214 + int test__event_times(int subtest __maybe_unused) 215 + { 216 + int err, ret = 0; 217 + 218 + #define _T(attach, detach) \ 219 + err = test_times(attach, detach); \ 220 + if (err && (ret == TEST_OK || ret == TEST_SKIP)) \ 221 + ret = err; 222 + 223 + /* attach on newly spawned process after exec */ 224 + _T(attach__enable_on_exec, detach__enable_on_exec) 225 + /* attach on current process as enabled */ 226 + _T(attach__current_enabled, detach__disable) 227 + /* attach on current process as disabled */ 228 + _T(attach__current_disabled, detach__disable) 229 + /* attach on cpu as disabled */ 230 + _T(attach__cpu_disabled, detach__disable) 231 + /* attach on cpu as enabled */ 232 + _T(attach__cpu_enabled, detach__disable) 233 + 234 + #undef _T 235 + return ret; 236 + }
+1
tools/perf/tests/tests.h
··· 85 85 int test__synthesize_stat(int subtest); 86 86 int test__synthesize_stat_round(int subtest); 87 87 int test__event_update(int subtest); 88 + int test__event_times(int subtest); 88 89 89 90 #if defined(__arm__) || defined(__aarch64__) 90 91 #ifdef HAVE_DWARF_UNWIND_SUPPORT
+7
tools/perf/util/auxtrace.c
··· 940 940 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; 941 941 synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; 942 942 synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; 943 + synth_opts->initial_skip = 0; 943 944 } 944 945 945 946 /* ··· 1064 1063 goto out_err; 1065 1064 synth_opts->last_branch_sz = val; 1066 1065 } 1066 + break; 1067 + case 's': 1068 + synth_opts->initial_skip = strtoul(p, &endptr, 10); 1069 + if (p == endptr) 1070 + goto out_err; 1071 + p = endptr; 1067 1072 break; 1068 1073 case ' ': 1069 1074 case ',':
+2
tools/perf/util/auxtrace.h
··· 68 68 * @last_branch_sz: branch context size 69 69 * @period: 'instructions' events period 70 70 * @period_type: 'instructions' events period type 71 + * @initial_skip: skip N events at the beginning. 71 72 */ 72 73 struct itrace_synth_opts { 73 74 bool set; ··· 87 86 unsigned int last_branch_sz; 88 87 unsigned long long period; 89 88 enum itrace_period_type period_type; 89 + unsigned long initial_skip; 90 90 }; 91 91 92 92 /**
+22 -35
tools/perf/util/config.c
··· 377 377 return value; 378 378 } 379 379 380 + static int perf_buildid_config(const char *var, const char *value) 381 + { 382 + /* same dir for all commands */ 383 + if (!strcmp(var, "buildid.dir")) { 384 + const char *dirname = perf_config_dirname(var, value); 385 + 386 + if (!dirname) 387 + return -1; 388 + strncpy(buildid_dir, dirname, MAXPATHLEN-1); 389 + buildid_dir[MAXPATHLEN-1] = '\0'; 390 + } 391 + 392 + return 0; 393 + } 394 + 380 395 static int perf_default_core_config(const char *var __maybe_unused, 381 396 const char *value __maybe_unused) 382 397 { ··· 426 411 427 412 if (!prefixcmp(var, "llvm.")) 428 413 return perf_llvm_config(var, value); 414 + 415 + if (!prefixcmp(var, "buildid.")) 416 + return perf_buildid_config(var, value); 429 417 430 418 /* Add other config variables here. */ 431 419 return 0; ··· 533 515 return error("Missing value for '%s'", var); 534 516 } 535 517 536 - struct buildid_dir_config { 537 - char *dir; 538 - }; 539 - 540 - static int buildid_dir_command_config(const char *var, const char *value, 541 - void *data) 542 - { 543 - struct buildid_dir_config *c = data; 544 - const char *v; 545 - 546 - /* same dir for all commands */ 547 - if (!strcmp(var, "buildid.dir")) { 548 - v = perf_config_dirname(var, value); 549 - if (!v) 550 - return -1; 551 - strncpy(c->dir, v, MAXPATHLEN-1); 552 - c->dir[MAXPATHLEN-1] = '\0'; 553 - } 554 - return 0; 555 - } 556 - 557 - static void check_buildid_dir_config(void) 558 - { 559 - struct buildid_dir_config c; 560 - c.dir = buildid_dir; 561 - perf_config(buildid_dir_command_config, &c); 562 - } 563 - 564 518 void set_buildid_dir(const char *dir) 565 519 { 566 520 if (dir) 567 521 scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir); 568 522 569 - /* try config file */ 570 - if (buildid_dir[0] == '\0') 571 - check_buildid_dir_config(); 572 - 573 523 /* default to $HOME/.debug */ 574 524 if (buildid_dir[0] == '\0') { 575 - char *v = getenv("HOME"); 576 - if (v) { 525 + char *home = getenv("HOME"); 526 + 527 + if (home) { 577 528 snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s", 578 - v, DEBUG_CACHE_DIR); 529 + home, DEBUG_CACHE_DIR); 579 530 } else { 580 531 strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); 581 532 }
+3 -2
tools/perf/util/hist.c
··· 1295 1295 return ret; 1296 1296 } 1297 1297 1298 - int hists__collapse_insert_entry(struct hists *hists, struct rb_root *root, 1299 - struct hist_entry *he) 1298 + static int hists__collapse_insert_entry(struct hists *hists, 1299 + struct rb_root *root, 1300 + struct hist_entry *he) 1300 1301 { 1301 1302 struct rb_node **p = &root->rb_node; 1302 1303 struct rb_node *parent = NULL;
-2
tools/perf/util/hist.h
··· 199 199 int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list); 200 200 201 201 struct rb_root *hists__get_rotate_entries_in(struct hists *hists); 202 - int hists__collapse_insert_entry(struct hists *hists, 203 - struct rb_root *root, struct hist_entry *he); 204 202 205 203 struct perf_hpp { 206 204 char *buf;
+5
tools/perf/util/intel-bts.c
··· 66 66 u64 branches_id; 67 67 size_t branches_event_size; 68 68 bool synth_needs_swap; 69 + unsigned long num_events; 69 70 }; 70 71 71 72 struct intel_bts_queue { ··· 275 274 struct intel_bts *bts = btsq->bts; 276 275 union perf_event event; 277 276 struct perf_sample sample = { .ip = 0, }; 277 + 278 + if (bts->synth_opts.initial_skip && 279 + bts->num_events++ <= bts->synth_opts.initial_skip) 280 + return 0; 278 281 279 282 event.sample.header.type = PERF_RECORD_SAMPLE; 280 283 event.sample.header.misc = PERF_RECORD_MISC_USER;
+20 -2
tools/perf/util/intel-pt.c
··· 100 100 u64 cyc_bit; 101 101 u64 noretcomp_bit; 102 102 unsigned max_non_turbo_ratio; 103 + 104 + unsigned long num_events; 103 105 }; 104 106 105 107 enum switch_state { ··· 974 972 if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) 975 973 return 0; 976 974 975 + if (pt->synth_opts.initial_skip && 976 + pt->num_events++ < pt->synth_opts.initial_skip) 977 + return 0; 978 + 977 979 event->sample.header.type = PERF_RECORD_SAMPLE; 978 980 event->sample.header.misc = PERF_RECORD_MISC_USER; 979 981 event->sample.header.size = sizeof(struct perf_event_header); ··· 1034 1028 struct intel_pt *pt = ptq->pt; 1035 1029 union perf_event *event = ptq->event_buf; 1036 1030 struct perf_sample sample = { .ip = 0, }; 1031 + 1032 + if (pt->synth_opts.initial_skip && 1033 + pt->num_events++ < pt->synth_opts.initial_skip) 1034 + return 0; 1037 1035 1038 1036 event->sample.header.type = PERF_RECORD_SAMPLE; 1039 1037 event->sample.header.misc = PERF_RECORD_MISC_USER; ··· 1096 1086 struct intel_pt *pt = ptq->pt; 1097 1087 union perf_event *event = ptq->event_buf; 1098 1088 struct perf_sample sample = { .ip = 0, }; 1089 + 1090 + if (pt->synth_opts.initial_skip && 1091 + pt->num_events++ < pt->synth_opts.initial_skip) 1092 + return 0; 1099 1093 1100 1094 event->sample.header.type = PERF_RECORD_SAMPLE; 1101 1095 event->sample.header.misc = PERF_RECORD_MISC_USER; ··· 1213 1199 ptq->have_sample = false; 1214 1200 1215 1201 if (pt->sample_instructions && 1216 - (state->type & INTEL_PT_INSTRUCTION)) { 1202 + (state->type & INTEL_PT_INSTRUCTION) && 1203 + (!pt->synth_opts.initial_skip || 1204 + pt->num_events++ >= pt->synth_opts.initial_skip)) { 1217 1205 err = intel_pt_synth_instruction_sample(ptq); 1218 1206 if (err) 1219 1207 return err; 1220 1208 } 1221 1209 1222 1210 if (pt->sample_transactions && 1223 - (state->type & INTEL_PT_TRANSACTION)) { 1211 + (state->type & INTEL_PT_TRANSACTION) && 1212 + (!pt->synth_opts.initial_skip || 1213 + pt->num_events++ >= pt->synth_opts.initial_skip)) { 1224 1214 err = intel_pt_synth_transaction_sample(ptq); 1225 1215 if (err) 1226 1216 return err;
+106 -8
tools/perf/util/scripting-engines/trace-event-perl.c
··· 31 31 #include <perl.h> 32 32 33 33 #include "../../perf.h" 34 + #include "../callchain.h" 35 + #include "../machine.h" 34 36 #include "../thread.h" 35 37 #include "../event.h" 36 38 #include "../trace-event.h" ··· 250 248 define_event_symbols(event, ev_name, args->next); 251 249 } 252 250 251 + static SV *perl_process_callchain(struct perf_sample *sample, 252 + struct perf_evsel *evsel, 253 + struct addr_location *al) 254 + { 255 + AV *list; 256 + 257 + list = newAV(); 258 + if (!list) 259 + goto exit; 260 + 261 + if (!symbol_conf.use_callchain || !sample->callchain) 262 + goto exit; 263 + 264 + if (thread__resolve_callchain(al->thread, evsel, 265 + sample, NULL, NULL, 266 + PERF_MAX_STACK_DEPTH) != 0) { 267 + pr_err("Failed to resolve callchain. Skipping\n"); 268 + goto exit; 269 + } 270 + callchain_cursor_commit(&callchain_cursor); 271 + 272 + 273 + while (1) { 274 + HV *elem; 275 + struct callchain_cursor_node *node; 276 + node = callchain_cursor_current(&callchain_cursor); 277 + if (!node) 278 + break; 279 + 280 + elem = newHV(); 281 + if (!elem) 282 + goto exit; 283 + 284 + hv_stores(elem, "ip", newSVuv(node->ip)); 285 + 286 + if (node->sym) { 287 + HV *sym = newHV(); 288 + if (!sym) 289 + goto exit; 290 + hv_stores(sym, "start", newSVuv(node->sym->start)); 291 + hv_stores(sym, "end", newSVuv(node->sym->end)); 292 + hv_stores(sym, "binding", newSVuv(node->sym->binding)); 293 + hv_stores(sym, "name", newSVpvn(node->sym->name, 294 + node->sym->namelen)); 295 + hv_stores(elem, "sym", newRV_noinc((SV*)sym)); 296 + } 297 + 298 + if (node->map) { 299 + struct map *map = node->map; 300 + const char *dsoname = "[unknown]"; 301 + if (map && map->dso && (map->dso->name || map->dso->long_name)) { 302 + if (symbol_conf.show_kernel_path && map->dso->long_name) 303 + dsoname = map->dso->long_name; 304 + else if (map->dso->name) 305 + dsoname = map->dso->name; 306 + } 307 + hv_stores(elem, "dso", newSVpv(dsoname,0)); 308 + } 309 + 310 + callchain_cursor_advance(&callchain_cursor); 311 + av_push(list, newRV_noinc((SV*)elem)); 312 + } 313 + 314 + exit: 315 + return newRV_noinc((SV*)list); 316 + } 317 + 253 318 static void perl_process_tracepoint(struct perf_sample *sample, 254 319 struct perf_evsel *evsel, 255 - struct thread *thread) 320 + struct addr_location *al) 256 321 { 322 + struct thread *thread = al->thread; 257 323 struct event_format *event = evsel->tp_format; 258 324 struct format_field *field; 259 325 static char handler[256]; ··· 365 295 XPUSHs(sv_2mortal(newSVuv(ns))); 366 296 XPUSHs(sv_2mortal(newSViv(pid))); 367 297 XPUSHs(sv_2mortal(newSVpv(comm, 0))); 298 + XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al))); 368 299 369 300 /* common fields other than pid can be accessed via xsub fns */ 370 301 ··· 400 329 XPUSHs(sv_2mortal(newSVuv(nsecs))); 401 330 XPUSHs(sv_2mortal(newSViv(pid))); 402 331 XPUSHs(sv_2mortal(newSVpv(comm, 0))); 332 + XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al))); 403 333 call_pv("main::trace_unhandled", G_SCALAR); 404 334 } 405 335 SPAGAIN; ··· 438 366 struct perf_evsel *evsel, 439 367 struct addr_location *al) 440 368 { 441 - perl_process_tracepoint(sample, evsel, al->thread); 369 + perl_process_tracepoint(sample, evsel, al); 442 370 perl_process_event_generic(event, sample, evsel); 443 371 } 444 372 ··· 562 490 fprintf(ofp, "use Perf::Trace::Util;\n\n"); 563 491 564 492 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); 565 - fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n"); 493 + fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n"); 494 + 495 + 496 + fprintf(ofp, "\n\ 497 + sub print_backtrace\n\ 498 + {\n\ 499 + my $callchain = shift;\n\ 500 + for my $node (@$callchain)\n\ 501 + {\n\ 502 + if(exists $node->{sym})\n\ 503 + {\n\ 504 + printf( \"\\t[\\%%x] \\%%s\\n\", $node->{ip}, $node->{sym}{name});\n\ 505 + }\n\ 506 + else\n\ 507 + {\n\ 508 + printf( \"\\t[\\%%x]\\n\", $node{ip});\n\ 509 + }\n\ 510 + }\n\ 511 + }\n\n\ 512 + "); 513 + 566 514 567 515 while ((event = trace_find_next_event(pevent, event))) { 568 516 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); ··· 594 502 fprintf(ofp, "$common_secs, "); 595 503 fprintf(ofp, "$common_nsecs,\n"); 596 504 fprintf(ofp, "\t $common_pid, "); 597 - fprintf(ofp, "$common_comm,\n\t "); 505 + fprintf(ofp, "$common_comm, "); 506 + fprintf(ofp, "$common_callchain,\n\t "); 598 507 599 508 not_first = 0; 600 509 count = 0; ··· 612 519 613 520 fprintf(ofp, "\tprint_header($event_name, $common_cpu, " 614 521 "$common_secs, $common_nsecs,\n\t " 615 - "$common_pid, $common_comm);\n\n"); 522 + "$common_pid, $common_comm, $common_callchain);\n\n"); 616 523 617 524 fprintf(ofp, "\tprintf(\""); 618 525 ··· 674 581 fprintf(ofp, "$%s", f->name); 675 582 } 676 583 677 - fprintf(ofp, ");\n"); 584 + fprintf(ofp, ");\n\n"); 585 + 586 + fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); 587 + 678 588 fprintf(ofp, "}\n\n"); 679 589 } 680 590 681 591 fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, " 682 592 "$common_cpu, $common_secs, $common_nsecs,\n\t " 683 - "$common_pid, $common_comm) = @_;\n\n"); 593 + "$common_pid, $common_comm, $common_callchain) = @_;\n\n"); 684 594 685 595 fprintf(ofp, "\tprint_header($event_name, $common_cpu, " 686 596 "$common_secs, $common_nsecs,\n\t $common_pid, " 687 - "$common_comm);\n}\n\n"); 597 + "$common_comm, $common_callchain);\n"); 598 + fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); 599 + fprintf(ofp, "}\n\n"); 688 600 689 601 fprintf(ofp, "sub print_header\n{\n" 690 602 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"