diff options
Diffstat (limited to 'tools/perf/util/session.c')
| -rw-r--r-- | tools/perf/util/session.c | 198 |
1 files changed, 144 insertions, 54 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 2437fb0b463a..8cdd23239c90 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -15,6 +15,9 @@ | |||
| 15 | #include "util.h" | 15 | #include "util.h" |
| 16 | #include "cpumap.h" | 16 | #include "cpumap.h" |
| 17 | #include "event-parse.h" | 17 | #include "event-parse.h" |
| 18 | #include "perf_regs.h" | ||
| 19 | #include "unwind.h" | ||
| 20 | #include "vdso.h" | ||
| 18 | 21 | ||
| 19 | static int perf_session__open(struct perf_session *self, bool force) | 22 | static int perf_session__open(struct perf_session *self, bool force) |
| 20 | { | 23 | { |
| @@ -209,6 +212,7 @@ void perf_session__delete(struct perf_session *self) | |||
| 209 | machine__exit(&self->host_machine); | 212 | machine__exit(&self->host_machine); |
| 210 | close(self->fd); | 213 | close(self->fd); |
| 211 | free(self); | 214 | free(self); |
| 215 | vdso__exit(); | ||
| 212 | } | 216 | } |
| 213 | 217 | ||
| 214 | void machine__remove_thread(struct machine *self, struct thread *th) | 218 | void machine__remove_thread(struct machine *self, struct thread *th) |
| @@ -288,10 +292,11 @@ struct branch_info *machine__resolve_bstack(struct machine *self, | |||
| 288 | return bi; | 292 | return bi; |
| 289 | } | 293 | } |
| 290 | 294 | ||
| 291 | int machine__resolve_callchain(struct machine *self, | 295 | static int machine__resolve_callchain_sample(struct machine *machine, |
| 292 | struct thread *thread, | 296 | struct thread *thread, |
| 293 | struct ip_callchain *chain, | 297 | struct ip_callchain *chain, |
| 294 | struct symbol **parent) | 298 | struct symbol **parent) |
| 299 | |||
| 295 | { | 300 | { |
| 296 | u8 cpumode = PERF_RECORD_MISC_USER; | 301 | u8 cpumode = PERF_RECORD_MISC_USER; |
| 297 | unsigned int i; | 302 | unsigned int i; |
| @@ -316,11 +321,14 @@ int machine__resolve_callchain(struct machine *self, | |||
| 316 | if (ip >= PERF_CONTEXT_MAX) { | 321 | if (ip >= PERF_CONTEXT_MAX) { |
| 317 | switch (ip) { | 322 | switch (ip) { |
| 318 | case PERF_CONTEXT_HV: | 323 | case PERF_CONTEXT_HV: |
| 319 | cpumode = PERF_RECORD_MISC_HYPERVISOR; break; | 324 | cpumode = PERF_RECORD_MISC_HYPERVISOR; |
| 325 | break; | ||
| 320 | case PERF_CONTEXT_KERNEL: | 326 | case PERF_CONTEXT_KERNEL: |
| 321 | cpumode = PERF_RECORD_MISC_KERNEL; break; | 327 | cpumode = PERF_RECORD_MISC_KERNEL; |
| 328 | break; | ||
| 322 | case PERF_CONTEXT_USER: | 329 | case PERF_CONTEXT_USER: |
| 323 | cpumode = PERF_RECORD_MISC_USER; break; | 330 | cpumode = PERF_RECORD_MISC_USER; |
| 331 | break; | ||
| 324 | default: | 332 | default: |
| 325 | pr_debug("invalid callchain context: " | 333 | pr_debug("invalid callchain context: " |
| 326 | "%"PRId64"\n", (s64) ip); | 334 | "%"PRId64"\n", (s64) ip); |
| @@ -335,7 +343,7 @@ int machine__resolve_callchain(struct machine *self, | |||
| 335 | } | 343 | } |
| 336 | 344 | ||
| 337 | al.filtered = false; | 345 | al.filtered = false; |
| 338 | thread__find_addr_location(thread, self, cpumode, | 346 | thread__find_addr_location(thread, machine, cpumode, |
| 339 | MAP__FUNCTION, ip, &al, NULL); | 347 | MAP__FUNCTION, ip, &al, NULL); |
| 340 | if (al.sym != NULL) { | 348 | if (al.sym != NULL) { |
| 341 | if (sort__has_parent && !*parent && | 349 | if (sort__has_parent && !*parent && |
| @@ -354,49 +362,92 @@ int machine__resolve_callchain(struct machine *self, | |||
| 354 | return 0; | 362 | return 0; |
| 355 | } | 363 | } |
| 356 | 364 | ||
| 357 | static int process_event_synth_tracing_data_stub(union perf_event *event __used, | 365 | static int unwind_entry(struct unwind_entry *entry, void *arg) |
| 358 | struct perf_session *session __used) | 366 | { |
| 367 | struct callchain_cursor *cursor = arg; | ||
| 368 | return callchain_cursor_append(cursor, entry->ip, | ||
| 369 | entry->map, entry->sym); | ||
| 370 | } | ||
| 371 | |||
| 372 | int machine__resolve_callchain(struct machine *machine, | ||
| 373 | struct perf_evsel *evsel, | ||
| 374 | struct thread *thread, | ||
| 375 | struct perf_sample *sample, | ||
| 376 | struct symbol **parent) | ||
| 377 | |||
| 378 | { | ||
| 379 | int ret; | ||
| 380 | |||
| 381 | callchain_cursor_reset(&callchain_cursor); | ||
| 382 | |||
| 383 | ret = machine__resolve_callchain_sample(machine, thread, | ||
| 384 | sample->callchain, parent); | ||
| 385 | if (ret) | ||
| 386 | return ret; | ||
| 387 | |||
| 388 | /* Can we do dwarf post unwind? */ | ||
| 389 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && | ||
| 390 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) | ||
| 391 | return 0; | ||
| 392 | |||
| 393 | /* Bail out if nothing was captured. */ | ||
| 394 | if ((!sample->user_regs.regs) || | ||
| 395 | (!sample->user_stack.size)) | ||
| 396 | return 0; | ||
| 397 | |||
| 398 | return unwind__get_entries(unwind_entry, &callchain_cursor, machine, | ||
| 399 | thread, evsel->attr.sample_regs_user, | ||
| 400 | sample); | ||
| 401 | |||
| 402 | } | ||
| 403 | |||
| 404 | static int process_event_synth_tracing_data_stub(union perf_event *event | ||
| 405 | __maybe_unused, | ||
| 406 | struct perf_session *session | ||
| 407 | __maybe_unused) | ||
| 359 | { | 408 | { |
| 360 | dump_printf(": unhandled!\n"); | 409 | dump_printf(": unhandled!\n"); |
| 361 | return 0; | 410 | return 0; |
| 362 | } | 411 | } |
| 363 | 412 | ||
| 364 | static int process_event_synth_attr_stub(union perf_event *event __used, | 413 | static int process_event_synth_attr_stub(union perf_event *event __maybe_unused, |
| 365 | struct perf_evlist **pevlist __used) | 414 | struct perf_evlist **pevlist |
| 415 | __maybe_unused) | ||
| 366 | { | 416 | { |
| 367 | dump_printf(": unhandled!\n"); | 417 | dump_printf(": unhandled!\n"); |
| 368 | return 0; | 418 | return 0; |
| 369 | } | 419 | } |
| 370 | 420 | ||
| 371 | static int process_event_sample_stub(struct perf_tool *tool __used, | 421 | static int process_event_sample_stub(struct perf_tool *tool __maybe_unused, |
| 372 | union perf_event *event __used, | 422 | union perf_event *event __maybe_unused, |
| 373 | struct perf_sample *sample __used, | 423 | struct perf_sample *sample __maybe_unused, |
| 374 | struct perf_evsel *evsel __used, | 424 | struct perf_evsel *evsel __maybe_unused, |
| 375 | struct machine *machine __used) | 425 | struct machine *machine __maybe_unused) |
| 376 | { | 426 | { |
| 377 | dump_printf(": unhandled!\n"); | 427 | dump_printf(": unhandled!\n"); |
| 378 | return 0; | 428 | return 0; |
| 379 | } | 429 | } |
| 380 | 430 | ||
| 381 | static int process_event_stub(struct perf_tool *tool __used, | 431 | static int process_event_stub(struct perf_tool *tool __maybe_unused, |
| 382 | union perf_event *event __used, | 432 | union perf_event *event __maybe_unused, |
| 383 | struct perf_sample *sample __used, | 433 | struct perf_sample *sample __maybe_unused, |
| 384 | struct machine *machine __used) | 434 | struct machine *machine __maybe_unused) |
| 385 | { | 435 | { |
| 386 | dump_printf(": unhandled!\n"); | 436 | dump_printf(": unhandled!\n"); |
| 387 | return 0; | 437 | return 0; |
| 388 | } | 438 | } |
| 389 | 439 | ||
| 390 | static int process_finished_round_stub(struct perf_tool *tool __used, | 440 | static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, |
| 391 | union perf_event *event __used, | 441 | union perf_event *event __maybe_unused, |
| 392 | struct perf_session *perf_session __used) | 442 | struct perf_session *perf_session |
| 443 | __maybe_unused) | ||
| 393 | { | 444 | { |
| 394 | dump_printf(": unhandled!\n"); | 445 | dump_printf(": unhandled!\n"); |
| 395 | return 0; | 446 | return 0; |
| 396 | } | 447 | } |
| 397 | 448 | ||
| 398 | static int process_event_type_stub(struct perf_tool *tool __used, | 449 | static int process_event_type_stub(struct perf_tool *tool __maybe_unused, |
| 399 | union perf_event *event __used) | 450 | union perf_event *event __maybe_unused) |
| 400 | { | 451 | { |
| 401 | dump_printf(": unhandled!\n"); | 452 | dump_printf(": unhandled!\n"); |
| 402 | return 0; | 453 | return 0; |
| @@ -473,7 +524,7 @@ static void swap_sample_id_all(union perf_event *event, void *data) | |||
| 473 | } | 524 | } |
| 474 | 525 | ||
| 475 | static void perf_event__all64_swap(union perf_event *event, | 526 | static void perf_event__all64_swap(union perf_event *event, |
| 476 | bool sample_id_all __used) | 527 | bool sample_id_all __maybe_unused) |
| 477 | { | 528 | { |
| 478 | struct perf_event_header *hdr = &event->header; | 529 | struct perf_event_header *hdr = &event->header; |
| 479 | mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); | 530 | mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); |
| @@ -487,7 +538,7 @@ static void perf_event__comm_swap(union perf_event *event, bool sample_id_all) | |||
| 487 | if (sample_id_all) { | 538 | if (sample_id_all) { |
| 488 | void *data = &event->comm.comm; | 539 | void *data = &event->comm.comm; |
| 489 | 540 | ||
| 490 | data += ALIGN(strlen(data) + 1, sizeof(u64)); | 541 | data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); |
| 491 | swap_sample_id_all(event, data); | 542 | swap_sample_id_all(event, data); |
| 492 | } | 543 | } |
| 493 | } | 544 | } |
| @@ -504,7 +555,7 @@ static void perf_event__mmap_swap(union perf_event *event, | |||
| 504 | if (sample_id_all) { | 555 | if (sample_id_all) { |
| 505 | void *data = &event->mmap.filename; | 556 | void *data = &event->mmap.filename; |
| 506 | 557 | ||
| 507 | data += ALIGN(strlen(data) + 1, sizeof(u64)); | 558 | data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); |
| 508 | swap_sample_id_all(event, data); | 559 | swap_sample_id_all(event, data); |
| 509 | } | 560 | } |
| 510 | } | 561 | } |
| @@ -584,7 +635,7 @@ void perf_event__attr_swap(struct perf_event_attr *attr) | |||
| 584 | } | 635 | } |
| 585 | 636 | ||
| 586 | static void perf_event__hdr_attr_swap(union perf_event *event, | 637 | static void perf_event__hdr_attr_swap(union perf_event *event, |
| 587 | bool sample_id_all __used) | 638 | bool sample_id_all __maybe_unused) |
| 588 | { | 639 | { |
| 589 | size_t size; | 640 | size_t size; |
| 590 | 641 | ||
| @@ -596,14 +647,14 @@ static void perf_event__hdr_attr_swap(union perf_event *event, | |||
| 596 | } | 647 | } |
| 597 | 648 | ||
| 598 | static void perf_event__event_type_swap(union perf_event *event, | 649 | static void perf_event__event_type_swap(union perf_event *event, |
| 599 | bool sample_id_all __used) | 650 | bool sample_id_all __maybe_unused) |
| 600 | { | 651 | { |
| 601 | event->event_type.event_type.event_id = | 652 | event->event_type.event_type.event_id = |
| 602 | bswap_64(event->event_type.event_type.event_id); | 653 | bswap_64(event->event_type.event_type.event_id); |
| 603 | } | 654 | } |
| 604 | 655 | ||
| 605 | static void perf_event__tracing_data_swap(union perf_event *event, | 656 | static void perf_event__tracing_data_swap(union perf_event *event, |
| 606 | bool sample_id_all __used) | 657 | bool sample_id_all __maybe_unused) |
| 607 | { | 658 | { |
| 608 | event->tracing_data.size = bswap_32(event->tracing_data.size); | 659 | event->tracing_data.size = bswap_32(event->tracing_data.size); |
| 609 | } | 660 | } |
| @@ -652,7 +703,7 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
| 652 | struct perf_tool *tool, | 703 | struct perf_tool *tool, |
| 653 | u64 file_offset); | 704 | u64 file_offset); |
| 654 | 705 | ||
| 655 | static void flush_sample_queue(struct perf_session *s, | 706 | static int flush_sample_queue(struct perf_session *s, |
| 656 | struct perf_tool *tool) | 707 | struct perf_tool *tool) |
| 657 | { | 708 | { |
| 658 | struct ordered_samples *os = &s->ordered_samples; | 709 | struct ordered_samples *os = &s->ordered_samples; |
| @@ -665,19 +716,21 @@ static void flush_sample_queue(struct perf_session *s, | |||
| 665 | int ret; | 716 | int ret; |
| 666 | 717 | ||
| 667 | if (!tool->ordered_samples || !limit) | 718 | if (!tool->ordered_samples || !limit) |
| 668 | return; | 719 | return 0; |
| 669 | 720 | ||
| 670 | list_for_each_entry_safe(iter, tmp, head, list) { | 721 | list_for_each_entry_safe(iter, tmp, head, list) { |
| 671 | if (iter->timestamp > limit) | 722 | if (iter->timestamp > limit) |
| 672 | break; | 723 | break; |
| 673 | 724 | ||
| 674 | ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample, | 725 | ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample); |
| 675 | s->header.needs_swap); | ||
| 676 | if (ret) | 726 | if (ret) |
| 677 | pr_err("Can't parse sample, err = %d\n", ret); | 727 | pr_err("Can't parse sample, err = %d\n", ret); |
| 678 | else | 728 | else { |
| 679 | perf_session_deliver_event(s, iter->event, &sample, tool, | 729 | ret = perf_session_deliver_event(s, iter->event, &sample, tool, |
| 680 | iter->file_offset); | 730 | iter->file_offset); |
| 731 | if (ret) | ||
| 732 | return ret; | ||
| 733 | } | ||
| 681 | 734 | ||
| 682 | os->last_flush = iter->timestamp; | 735 | os->last_flush = iter->timestamp; |
| 683 | list_del(&iter->list); | 736 | list_del(&iter->list); |
| @@ -697,6 +750,8 @@ static void flush_sample_queue(struct perf_session *s, | |||
| 697 | } | 750 | } |
| 698 | 751 | ||
| 699 | os->nr_samples = 0; | 752 | os->nr_samples = 0; |
| 753 | |||
| 754 | return 0; | ||
| 700 | } | 755 | } |
| 701 | 756 | ||
| 702 | /* | 757 | /* |
| @@ -739,13 +794,14 @@ static void flush_sample_queue(struct perf_session *s, | |||
| 739 | * etc... | 794 | * etc... |
| 740 | */ | 795 | */ |
| 741 | static int process_finished_round(struct perf_tool *tool, | 796 | static int process_finished_round(struct perf_tool *tool, |
| 742 | union perf_event *event __used, | 797 | union perf_event *event __maybe_unused, |
| 743 | struct perf_session *session) | 798 | struct perf_session *session) |
| 744 | { | 799 | { |
| 745 | flush_sample_queue(session, tool); | 800 | int ret = flush_sample_queue(session, tool); |
| 746 | session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; | 801 | if (!ret) |
| 802 | session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; | ||
| 747 | 803 | ||
| 748 | return 0; | 804 | return ret; |
| 749 | } | 805 | } |
| 750 | 806 | ||
| 751 | /* The queue is ordered by time */ | 807 | /* The queue is ordered by time */ |
| @@ -860,6 +916,34 @@ static void branch_stack__printf(struct perf_sample *sample) | |||
| 860 | sample->branch_stack->entries[i].to); | 916 | sample->branch_stack->entries[i].to); |
| 861 | } | 917 | } |
| 862 | 918 | ||
| 919 | static void regs_dump__printf(u64 mask, u64 *regs) | ||
| 920 | { | ||
| 921 | unsigned rid, i = 0; | ||
| 922 | |||
| 923 | for_each_set_bit(rid, (unsigned long *) &mask, sizeof(mask) * 8) { | ||
| 924 | u64 val = regs[i++]; | ||
| 925 | |||
| 926 | printf(".... %-5s 0x%" PRIx64 "\n", | ||
| 927 | perf_reg_name(rid), val); | ||
| 928 | } | ||
| 929 | } | ||
| 930 | |||
| 931 | static void regs_user__printf(struct perf_sample *sample, u64 mask) | ||
| 932 | { | ||
| 933 | struct regs_dump *user_regs = &sample->user_regs; | ||
| 934 | |||
| 935 | if (user_regs->regs) { | ||
| 936 | printf("... user regs: mask 0x%" PRIx64 "\n", mask); | ||
| 937 | regs_dump__printf(mask, user_regs->regs); | ||
| 938 | } | ||
| 939 | } | ||
| 940 | |||
| 941 | static void stack_user__printf(struct stack_dump *dump) | ||
| 942 | { | ||
| 943 | printf("... ustack: size %" PRIu64 ", offset 0x%x\n", | ||
| 944 | dump->size, dump->offset); | ||
| 945 | } | ||
| 946 | |||
| 863 | static void perf_session__print_tstamp(struct perf_session *session, | 947 | static void perf_session__print_tstamp(struct perf_session *session, |
| 864 | union perf_event *event, | 948 | union perf_event *event, |
| 865 | struct perf_sample *sample) | 949 | struct perf_sample *sample) |
| @@ -897,7 +981,7 @@ static void dump_event(struct perf_session *session, union perf_event *event, | |||
| 897 | event->header.size, perf_event__name(event->header.type)); | 981 | event->header.size, perf_event__name(event->header.type)); |
| 898 | } | 982 | } |
| 899 | 983 | ||
| 900 | static void dump_sample(struct perf_session *session, union perf_event *event, | 984 | static void dump_sample(struct perf_evsel *evsel, union perf_event *event, |
| 901 | struct perf_sample *sample) | 985 | struct perf_sample *sample) |
| 902 | { | 986 | { |
| 903 | u64 sample_type; | 987 | u64 sample_type; |
| @@ -909,13 +993,19 @@ static void dump_sample(struct perf_session *session, union perf_event *event, | |||
| 909 | event->header.misc, sample->pid, sample->tid, sample->ip, | 993 | event->header.misc, sample->pid, sample->tid, sample->ip, |
| 910 | sample->period, sample->addr); | 994 | sample->period, sample->addr); |
| 911 | 995 | ||
| 912 | sample_type = perf_evlist__sample_type(session->evlist); | 996 | sample_type = evsel->attr.sample_type; |
| 913 | 997 | ||
| 914 | if (sample_type & PERF_SAMPLE_CALLCHAIN) | 998 | if (sample_type & PERF_SAMPLE_CALLCHAIN) |
| 915 | callchain__printf(sample); | 999 | callchain__printf(sample); |
| 916 | 1000 | ||
| 917 | if (sample_type & PERF_SAMPLE_BRANCH_STACK) | 1001 | if (sample_type & PERF_SAMPLE_BRANCH_STACK) |
| 918 | branch_stack__printf(sample); | 1002 | branch_stack__printf(sample); |
| 1003 | |||
| 1004 | if (sample_type & PERF_SAMPLE_REGS_USER) | ||
| 1005 | regs_user__printf(sample, evsel->attr.sample_regs_user); | ||
| 1006 | |||
| 1007 | if (sample_type & PERF_SAMPLE_STACK_USER) | ||
| 1008 | stack_user__printf(&sample->user_stack); | ||
| 919 | } | 1009 | } |
| 920 | 1010 | ||
| 921 | static struct machine * | 1011 | static struct machine * |
| @@ -973,7 +1063,7 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
| 973 | 1063 | ||
| 974 | switch (event->header.type) { | 1064 | switch (event->header.type) { |
| 975 | case PERF_RECORD_SAMPLE: | 1065 | case PERF_RECORD_SAMPLE: |
| 976 | dump_sample(session, event, sample); | 1066 | dump_sample(evsel, event, sample); |
| 977 | if (evsel == NULL) { | 1067 | if (evsel == NULL) { |
| 978 | ++session->hists.stats.nr_unknown_id; | 1068 | ++session->hists.stats.nr_unknown_id; |
| 979 | return 0; | 1069 | return 0; |
| @@ -1083,8 +1173,7 @@ static int perf_session__process_event(struct perf_session *session, | |||
| 1083 | /* | 1173 | /* |
| 1084 | * For all kernel events we get the sample data | 1174 | * For all kernel events we get the sample data |
| 1085 | */ | 1175 | */ |
| 1086 | ret = perf_evlist__parse_sample(session->evlist, event, &sample, | 1176 | ret = perf_evlist__parse_sample(session->evlist, event, &sample); |
| 1087 | session->header.needs_swap); | ||
| 1088 | if (ret) | 1177 | if (ret) |
| 1089 | return ret; | 1178 | return ret; |
| 1090 | 1179 | ||
| @@ -1369,7 +1458,7 @@ more: | |||
| 1369 | err = 0; | 1458 | err = 0; |
| 1370 | /* do the final flush for ordered samples */ | 1459 | /* do the final flush for ordered samples */ |
| 1371 | session->ordered_samples.next_flush = ULLONG_MAX; | 1460 | session->ordered_samples.next_flush = ULLONG_MAX; |
| 1372 | flush_sample_queue(session, tool); | 1461 | err = flush_sample_queue(session, tool); |
| 1373 | out_err: | 1462 | out_err: |
| 1374 | perf_session__warn_about_errors(session, tool); | 1463 | perf_session__warn_about_errors(session, tool); |
| 1375 | perf_session_free_sample_buffers(session); | 1464 | perf_session_free_sample_buffers(session); |
| @@ -1498,9 +1587,9 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
| 1498 | return NULL; | 1587 | return NULL; |
| 1499 | } | 1588 | } |
| 1500 | 1589 | ||
| 1501 | void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, | 1590 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, |
| 1502 | struct machine *machine, int print_sym, | 1591 | struct perf_sample *sample, struct machine *machine, |
| 1503 | int print_dso, int print_symoffset) | 1592 | int print_sym, int print_dso, int print_symoffset) |
| 1504 | { | 1593 | { |
| 1505 | struct addr_location al; | 1594 | struct addr_location al; |
| 1506 | struct callchain_cursor_node *node; | 1595 | struct callchain_cursor_node *node; |
| @@ -1514,8 +1603,9 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, | |||
| 1514 | 1603 | ||
| 1515 | if (symbol_conf.use_callchain && sample->callchain) { | 1604 | if (symbol_conf.use_callchain && sample->callchain) { |
| 1516 | 1605 | ||
| 1517 | if (machine__resolve_callchain(machine, al.thread, | 1606 | |
| 1518 | sample->callchain, NULL) != 0) { | 1607 | if (machine__resolve_callchain(machine, evsel, al.thread, |
| 1608 | sample, NULL) != 0) { | ||
| 1519 | if (verbose) | 1609 | if (verbose) |
| 1520 | error("Failed to resolve callchain. Skipping\n"); | 1610 | error("Failed to resolve callchain. Skipping\n"); |
| 1521 | return; | 1611 | return; |
