diff options
Diffstat (limited to 'tools/perf')
45 files changed, 436 insertions, 194 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index e297b74471b8..ca0d3d9f4bac 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
| @@ -90,8 +90,20 @@ OPTIONS | |||
| 90 | Number of mmap data pages. Must be a power of two. | 90 | Number of mmap data pages. Must be a power of two. |
| 91 | 91 | ||
| 92 | -g:: | 92 | -g:: |
| 93 | Enables call-graph (stack chain/backtrace) recording. | ||
| 94 | |||
| 93 | --call-graph:: | 95 | --call-graph:: |
| 94 | Do call-graph (stack chain/backtrace) recording. | 96 | Setup and enable call-graph (stack chain/backtrace) recording, |
| 97 | implies -g. | ||
| 98 | |||
| 99 | Allows specifying "fp" (frame pointer) or "dwarf" | ||
| 100 | (DWARF's CFI - Call Frame Information) as the method to collect | ||
| 101 | the information used to show the call graphs. | ||
| 102 | |||
| 103 | In some systems, where binaries are build with gcc | ||
| 104 | --fomit-frame-pointer, using the "fp" method will produce bogus | ||
| 105 | call graphs, using "dwarf", if available (perf tools linked to | ||
| 106 | the libunwind library) should be used instead. | ||
| 95 | 107 | ||
| 96 | -q:: | 108 | -q:: |
| 97 | --quiet:: | 109 | --quiet:: |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 58d6598a9686..6a118e71d003 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
| @@ -140,20 +140,12 @@ Default is to monitor all CPUS. | |||
| 140 | --asm-raw:: | 140 | --asm-raw:: |
| 141 | Show raw instruction encoding of assembly instructions. | 141 | Show raw instruction encoding of assembly instructions. |
| 142 | 142 | ||
| 143 | -G [type,min,order]:: | 143 | -G:: |
| 144 | Enables call-graph (stack chain/backtrace) recording. | ||
| 145 | |||
| 144 | --call-graph:: | 146 | --call-graph:: |
| 145 | Display call chains using type, min percent threshold and order. | 147 | Setup and enable call-graph (stack chain/backtrace) recording, |
| 146 | type can be either: | 148 | implies -G. |
| 147 | - flat: single column, linear exposure of call chains. | ||
| 148 | - graph: use a graph tree, displaying absolute overhead rates. | ||
| 149 | - fractal: like graph, but displays relative rates. Each branch of | ||
| 150 | the tree is considered as a new profiled object. | ||
| 151 | |||
| 152 | order can be either: | ||
| 153 | - callee: callee based call graph. | ||
| 154 | - caller: inverted caller based call graph. | ||
| 155 | |||
| 156 | Default: fractal,0.5,callee. | ||
| 157 | 149 | ||
| 158 | --ignore-callees=<regex>:: | 150 | --ignore-callees=<regex>:: |
| 159 | Ignore callees of the function(s) matching the given regex. | 151 | Ignore callees of the function(s) matching the given regex. |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 3a0ff7fb71b6..64c043b7a438 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -770,6 +770,7 @@ check: $(OUTPUT)common-cmds.h | |||
| 770 | install-bin: all | 770 | install-bin: all |
| 771 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' | 771 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' |
| 772 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' | 772 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' |
| 773 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | ||
| 773 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 774 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
| 774 | ifndef NO_LIBPERL | 775 | ifndef NO_LIBPERL |
| 775 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' | 776 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' |
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index 9570c2b0f83c..b2519e49424f 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c | |||
| @@ -32,7 +32,7 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) | |||
| 32 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | 32 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, |
| 33 | struct perf_tsc_conversion *tc) | 33 | struct perf_tsc_conversion *tc) |
| 34 | { | 34 | { |
| 35 | bool cap_usr_time_zero; | 35 | bool cap_user_time_zero; |
| 36 | u32 seq; | 36 | u32 seq; |
| 37 | int i = 0; | 37 | int i = 0; |
| 38 | 38 | ||
| @@ -42,7 +42,7 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | |||
| 42 | tc->time_mult = pc->time_mult; | 42 | tc->time_mult = pc->time_mult; |
| 43 | tc->time_shift = pc->time_shift; | 43 | tc->time_shift = pc->time_shift; |
| 44 | tc->time_zero = pc->time_zero; | 44 | tc->time_zero = pc->time_zero; |
| 45 | cap_usr_time_zero = pc->cap_usr_time_zero; | 45 | cap_user_time_zero = pc->cap_user_time_zero; |
| 46 | rmb(); | 46 | rmb(); |
| 47 | if (pc->lock == seq && !(seq & 1)) | 47 | if (pc->lock == seq && !(seq & 1)) |
| 48 | break; | 48 | break; |
| @@ -52,7 +52,7 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | |||
| 52 | } | 52 | } |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | if (!cap_usr_time_zero) | 55 | if (!cap_user_time_zero) |
| 56 | return -EOPNOTSUPP; | 56 | return -EOPNOTSUPP; |
| 57 | 57 | ||
| 58 | return 0; | 58 | return 0; |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 423875c999b2..afe377b2884f 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
| @@ -321,8 +321,6 @@ found: | |||
| 321 | return perf_event__repipe(tool, event_sw, &sample_sw, machine); | 321 | return perf_event__repipe(tool, event_sw, &sample_sw, machine); |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | extern volatile int session_done; | ||
| 325 | |||
| 326 | static void sig_handler(int sig __maybe_unused) | 324 | static void sig_handler(int sig __maybe_unused) |
| 327 | { | 325 | { |
| 328 | session_done = 1; | 326 | session_done = 1; |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index c2dff9cb1f2c..9b5f077fee5b 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
| @@ -101,7 +101,7 @@ static int setup_cpunode_map(void) | |||
| 101 | 101 | ||
| 102 | dir1 = opendir(PATH_SYS_NODE); | 102 | dir1 = opendir(PATH_SYS_NODE); |
| 103 | if (!dir1) | 103 | if (!dir1) |
| 104 | return -1; | 104 | return 0; |
| 105 | 105 | ||
| 106 | while ((dent1 = readdir(dir1)) != NULL) { | 106 | while ((dent1 = readdir(dir1)) != NULL) { |
| 107 | if (dent1->d_type != DT_DIR || | 107 | if (dent1->d_type != DT_DIR || |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 935d52216c89..fbc2888d6495 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
| @@ -888,11 +888,18 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, | |||
| 888 | while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) { | 888 | while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) { |
| 889 | err = perf_evlist__parse_sample(kvm->evlist, event, &sample); | 889 | err = perf_evlist__parse_sample(kvm->evlist, event, &sample); |
| 890 | if (err) { | 890 | if (err) { |
| 891 | perf_evlist__mmap_consume(kvm->evlist, idx); | ||
| 891 | pr_err("Failed to parse sample\n"); | 892 | pr_err("Failed to parse sample\n"); |
| 892 | return -1; | 893 | return -1; |
| 893 | } | 894 | } |
| 894 | 895 | ||
| 895 | err = perf_session_queue_event(kvm->session, event, &sample, 0); | 896 | err = perf_session_queue_event(kvm->session, event, &sample, 0); |
| 897 | /* | ||
| 898 | * FIXME: Here we can't consume the event, as perf_session_queue_event will | ||
| 899 | * point to it, and it'll get possibly overwritten by the kernel. | ||
| 900 | */ | ||
| 901 | perf_evlist__mmap_consume(kvm->evlist, idx); | ||
| 902 | |||
| 896 | if (err) { | 903 | if (err) { |
| 897 | pr_err("Failed to enqueue sample: %d\n", err); | 904 | pr_err("Failed to enqueue sample: %d\n", err); |
| 898 | return -1; | 905 | return -1; |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a41ac41546c9..d04651484640 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -712,21 +712,12 @@ static int get_stack_size(char *str, unsigned long *_size) | |||
| 712 | } | 712 | } |
| 713 | #endif /* LIBUNWIND_SUPPORT */ | 713 | #endif /* LIBUNWIND_SUPPORT */ |
| 714 | 714 | ||
| 715 | int record_parse_callchain_opt(const struct option *opt, | 715 | int record_parse_callchain(const char *arg, struct perf_record_opts *opts) |
| 716 | const char *arg, int unset) | ||
| 717 | { | 716 | { |
| 718 | struct perf_record_opts *opts = opt->value; | ||
| 719 | char *tok, *name, *saveptr = NULL; | 717 | char *tok, *name, *saveptr = NULL; |
| 720 | char *buf; | 718 | char *buf; |
| 721 | int ret = -1; | 719 | int ret = -1; |
| 722 | 720 | ||
| 723 | /* --no-call-graph */ | ||
| 724 | if (unset) | ||
| 725 | return 0; | ||
| 726 | |||
| 727 | /* We specified default option if none is provided. */ | ||
| 728 | BUG_ON(!arg); | ||
| 729 | |||
| 730 | /* We need buffer that we know we can write to. */ | 721 | /* We need buffer that we know we can write to. */ |
| 731 | buf = malloc(strlen(arg) + 1); | 722 | buf = malloc(strlen(arg) + 1); |
| 732 | if (!buf) | 723 | if (!buf) |
| @@ -764,13 +755,9 @@ int record_parse_callchain_opt(const struct option *opt, | |||
| 764 | ret = get_stack_size(tok, &size); | 755 | ret = get_stack_size(tok, &size); |
| 765 | opts->stack_dump_size = size; | 756 | opts->stack_dump_size = size; |
| 766 | } | 757 | } |
| 767 | |||
| 768 | if (!ret) | ||
| 769 | pr_debug("callchain: stack dump size %d\n", | ||
| 770 | opts->stack_dump_size); | ||
| 771 | #endif /* LIBUNWIND_SUPPORT */ | 758 | #endif /* LIBUNWIND_SUPPORT */ |
| 772 | } else { | 759 | } else { |
| 773 | pr_err("callchain: Unknown -g option " | 760 | pr_err("callchain: Unknown --call-graph option " |
| 774 | "value: %s\n", arg); | 761 | "value: %s\n", arg); |
| 775 | break; | 762 | break; |
| 776 | } | 763 | } |
| @@ -778,13 +765,52 @@ int record_parse_callchain_opt(const struct option *opt, | |||
| 778 | } while (0); | 765 | } while (0); |
| 779 | 766 | ||
| 780 | free(buf); | 767 | free(buf); |
| 768 | return ret; | ||
| 769 | } | ||
| 770 | |||
| 771 | static void callchain_debug(struct perf_record_opts *opts) | ||
| 772 | { | ||
| 773 | pr_debug("callchain: type %d\n", opts->call_graph); | ||
| 781 | 774 | ||
| 775 | if (opts->call_graph == CALLCHAIN_DWARF) | ||
| 776 | pr_debug("callchain: stack dump size %d\n", | ||
| 777 | opts->stack_dump_size); | ||
| 778 | } | ||
| 779 | |||
| 780 | int record_parse_callchain_opt(const struct option *opt, | ||
| 781 | const char *arg, | ||
| 782 | int unset) | ||
| 783 | { | ||
| 784 | struct perf_record_opts *opts = opt->value; | ||
| 785 | int ret; | ||
| 786 | |||
| 787 | /* --no-call-graph */ | ||
| 788 | if (unset) { | ||
| 789 | opts->call_graph = CALLCHAIN_NONE; | ||
| 790 | pr_debug("callchain: disabled\n"); | ||
| 791 | return 0; | ||
| 792 | } | ||
| 793 | |||
| 794 | ret = record_parse_callchain(arg, opts); | ||
| 782 | if (!ret) | 795 | if (!ret) |
| 783 | pr_debug("callchain: type %d\n", opts->call_graph); | 796 | callchain_debug(opts); |
| 784 | 797 | ||
| 785 | return ret; | 798 | return ret; |
| 786 | } | 799 | } |
| 787 | 800 | ||
| 801 | int record_callchain_opt(const struct option *opt, | ||
| 802 | const char *arg __maybe_unused, | ||
| 803 | int unset __maybe_unused) | ||
| 804 | { | ||
| 805 | struct perf_record_opts *opts = opt->value; | ||
| 806 | |||
| 807 | if (opts->call_graph == CALLCHAIN_NONE) | ||
| 808 | opts->call_graph = CALLCHAIN_FP; | ||
| 809 | |||
| 810 | callchain_debug(opts); | ||
| 811 | return 0; | ||
| 812 | } | ||
| 813 | |||
| 788 | static const char * const record_usage[] = { | 814 | static const char * const record_usage[] = { |
| 789 | "perf record [<options>] [<command>]", | 815 | "perf record [<options>] [<command>]", |
| 790 | "perf record [<options>] -- <command> [<options>]", | 816 | "perf record [<options>] -- <command> [<options>]", |
| @@ -813,12 +839,12 @@ static struct perf_record record = { | |||
| 813 | }, | 839 | }, |
| 814 | }; | 840 | }; |
| 815 | 841 | ||
| 816 | #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " | 842 | #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " |
| 817 | 843 | ||
| 818 | #ifdef LIBUNWIND_SUPPORT | 844 | #ifdef LIBUNWIND_SUPPORT |
| 819 | const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; | 845 | const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf"; |
| 820 | #else | 846 | #else |
| 821 | const char record_callchain_help[] = CALLCHAIN_HELP "[fp]"; | 847 | const char record_callchain_help[] = CALLCHAIN_HELP "fp"; |
| 822 | #endif | 848 | #endif |
| 823 | 849 | ||
| 824 | /* | 850 | /* |
| @@ -858,9 +884,12 @@ const struct option record_options[] = { | |||
| 858 | "number of mmap data pages"), | 884 | "number of mmap data pages"), |
| 859 | OPT_BOOLEAN(0, "group", &record.opts.group, | 885 | OPT_BOOLEAN(0, "group", &record.opts.group, |
| 860 | "put the counters into a counter group"), | 886 | "put the counters into a counter group"), |
| 861 | OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, | 887 | OPT_CALLBACK_NOOPT('g', NULL, &record.opts, |
| 862 | "mode[,dump_size]", record_callchain_help, | 888 | NULL, "enables call-graph recording" , |
| 863 | &record_parse_callchain_opt, "fp"), | 889 | &record_callchain_opt), |
| 890 | OPT_CALLBACK(0, "call-graph", &record.opts, | ||
| 891 | "mode[,dump_size]", record_callchain_help, | ||
| 892 | &record_parse_callchain_opt), | ||
| 864 | OPT_INCR('v', "verbose", &verbose, | 893 | OPT_INCR('v', "verbose", &verbose, |
| 865 | "be more verbose (show counter open errors, etc)"), | 894 | "be more verbose (show counter open errors, etc)"), |
| 866 | OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), | 895 | OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8e50d8d77419..72eae7498c09 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -401,8 +401,6 @@ static int perf_report__setup_sample_type(struct perf_report *rep) | |||
| 401 | return 0; | 401 | return 0; |
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | extern volatile int session_done; | ||
| 405 | |||
| 406 | static void sig_handler(int sig __maybe_unused) | 404 | static void sig_handler(int sig __maybe_unused) |
| 407 | { | 405 | { |
| 408 | session_done = 1; | 406 | session_done = 1; |
| @@ -568,6 +566,9 @@ static int __cmd_report(struct perf_report *rep) | |||
| 568 | } | 566 | } |
| 569 | } | 567 | } |
| 570 | 568 | ||
| 569 | if (session_done()) | ||
| 570 | return 0; | ||
| 571 | |||
| 571 | if (nr_samples == 0) { | 572 | if (nr_samples == 0) { |
| 572 | ui__error("The %s file has no samples!\n", session->filename); | 573 | ui__error("The %s file has no samples!\n", session->filename); |
| 573 | return 0; | 574 | return 0; |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 7f31a3ded1b6..9c333ff3dfeb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -553,8 +553,6 @@ static struct perf_tool perf_script = { | |||
| 553 | .ordering_requires_timestamps = true, | 553 | .ordering_requires_timestamps = true, |
| 554 | }; | 554 | }; |
| 555 | 555 | ||
| 556 | extern volatile int session_done; | ||
| 557 | |||
| 558 | static void sig_handler(int sig __maybe_unused) | 556 | static void sig_handler(int sig __maybe_unused) |
| 559 | { | 557 | { |
| 560 | session_done = 1; | 558 | session_done = 1; |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f686d5ff594e..5098f144b92d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -457,6 +457,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
| 457 | perror("failed to prepare workload"); | 457 | perror("failed to prepare workload"); |
| 458 | return -1; | 458 | return -1; |
| 459 | } | 459 | } |
| 460 | child_pid = evsel_list->workload.pid; | ||
| 460 | } | 461 | } |
| 461 | 462 | ||
| 462 | if (group) | 463 | if (group) |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 212214162bb2..5a11f13e56f9 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -810,7 +810,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
| 810 | ret = perf_evlist__parse_sample(top->evlist, event, &sample); | 810 | ret = perf_evlist__parse_sample(top->evlist, event, &sample); |
| 811 | if (ret) { | 811 | if (ret) { |
| 812 | pr_err("Can't parse sample, err = %d\n", ret); | 812 | pr_err("Can't parse sample, err = %d\n", ret); |
| 813 | continue; | 813 | goto next_event; |
| 814 | } | 814 | } |
| 815 | 815 | ||
| 816 | evsel = perf_evlist__id2evsel(session->evlist, sample.id); | 816 | evsel = perf_evlist__id2evsel(session->evlist, sample.id); |
| @@ -825,13 +825,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
| 825 | case PERF_RECORD_MISC_USER: | 825 | case PERF_RECORD_MISC_USER: |
| 826 | ++top->us_samples; | 826 | ++top->us_samples; |
| 827 | if (top->hide_user_symbols) | 827 | if (top->hide_user_symbols) |
| 828 | continue; | 828 | goto next_event; |
| 829 | machine = &session->machines.host; | 829 | machine = &session->machines.host; |
| 830 | break; | 830 | break; |
| 831 | case PERF_RECORD_MISC_KERNEL: | 831 | case PERF_RECORD_MISC_KERNEL: |
| 832 | ++top->kernel_samples; | 832 | ++top->kernel_samples; |
| 833 | if (top->hide_kernel_symbols) | 833 | if (top->hide_kernel_symbols) |
| 834 | continue; | 834 | goto next_event; |
| 835 | machine = &session->machines.host; | 835 | machine = &session->machines.host; |
| 836 | break; | 836 | break; |
| 837 | case PERF_RECORD_MISC_GUEST_KERNEL: | 837 | case PERF_RECORD_MISC_GUEST_KERNEL: |
| @@ -847,7 +847,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
| 847 | */ | 847 | */ |
| 848 | /* Fall thru */ | 848 | /* Fall thru */ |
| 849 | default: | 849 | default: |
| 850 | continue; | 850 | goto next_event; |
| 851 | } | 851 | } |
| 852 | 852 | ||
| 853 | 853 | ||
| @@ -859,6 +859,8 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
| 859 | machine__process_event(machine, event); | 859 | machine__process_event(machine, event); |
| 860 | } else | 860 | } else |
| 861 | ++session->stats.nr_unknown_events; | 861 | ++session->stats.nr_unknown_events; |
| 862 | next_event: | ||
| 863 | perf_evlist__mmap_consume(top->evlist, idx); | ||
| 862 | } | 864 | } |
| 863 | } | 865 | } |
| 864 | 866 | ||
| @@ -1016,16 +1018,16 @@ out_delete: | |||
| 1016 | } | 1018 | } |
| 1017 | 1019 | ||
| 1018 | static int | 1020 | static int |
| 1019 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 1021 | callchain_opt(const struct option *opt, const char *arg, int unset) |
| 1020 | { | 1022 | { |
| 1021 | /* | ||
| 1022 | * --no-call-graph | ||
| 1023 | */ | ||
| 1024 | if (unset) | ||
| 1025 | return 0; | ||
| 1026 | |||
| 1027 | symbol_conf.use_callchain = true; | 1023 | symbol_conf.use_callchain = true; |
| 1024 | return record_callchain_opt(opt, arg, unset); | ||
| 1025 | } | ||
| 1028 | 1026 | ||
| 1027 | static int | ||
| 1028 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | ||
| 1029 | { | ||
| 1030 | symbol_conf.use_callchain = true; | ||
| 1029 | return record_parse_callchain_opt(opt, arg, unset); | 1031 | return record_parse_callchain_opt(opt, arg, unset); |
| 1030 | } | 1032 | } |
| 1031 | 1033 | ||
| @@ -1106,9 +1108,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1106 | "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"), | 1108 | "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"), |
| 1107 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1109 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
| 1108 | "Show a column with the number of samples"), | 1110 | "Show a column with the number of samples"), |
| 1109 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, | 1111 | OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts, |
| 1110 | "mode[,dump_size]", record_callchain_help, | 1112 | NULL, "enables call-graph recording", |
| 1111 | &parse_callchain_opt, "fp"), | 1113 | &callchain_opt), |
| 1114 | OPT_CALLBACK(0, "call-graph", &top.record_opts, | ||
| 1115 | "mode[,dump_size]", record_callchain_help, | ||
| 1116 | &parse_callchain_opt), | ||
| 1112 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | 1117 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", |
| 1113 | "ignore callees of these functions in call graphs", | 1118 | "ignore callees of these functions in call graphs", |
| 1114 | report_parse_ignore_callees_opt), | 1119 | report_parse_ignore_callees_opt), |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index f5aa6375e3e9..99c8d9ad6729 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -16,6 +16,23 @@ | |||
| 16 | #include <sys/mman.h> | 16 | #include <sys/mman.h> |
| 17 | #include <linux/futex.h> | 17 | #include <linux/futex.h> |
| 18 | 18 | ||
| 19 | /* For older distros: */ | ||
| 20 | #ifndef MAP_STACK | ||
| 21 | # define MAP_STACK 0x20000 | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #ifndef MADV_HWPOISON | ||
| 25 | # define MADV_HWPOISON 100 | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #ifndef MADV_MERGEABLE | ||
| 29 | # define MADV_MERGEABLE 12 | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #ifndef MADV_UNMERGEABLE | ||
| 33 | # define MADV_UNMERGEABLE 13 | ||
| 34 | #endif | ||
| 35 | |||
| 19 | static size_t syscall_arg__scnprintf_hex(char *bf, size_t size, | 36 | static size_t syscall_arg__scnprintf_hex(char *bf, size_t size, |
| 20 | unsigned long arg, | 37 | unsigned long arg, |
| 21 | u8 arg_idx __maybe_unused, | 38 | u8 arg_idx __maybe_unused, |
| @@ -970,7 +987,7 @@ again: | |||
| 970 | err = perf_evlist__parse_sample(evlist, event, &sample); | 987 | err = perf_evlist__parse_sample(evlist, event, &sample); |
| 971 | if (err) { | 988 | if (err) { |
| 972 | fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err); | 989 | fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err); |
| 973 | continue; | 990 | goto next_event; |
| 974 | } | 991 | } |
| 975 | 992 | ||
| 976 | if (trace->base_time == 0) | 993 | if (trace->base_time == 0) |
| @@ -984,18 +1001,20 @@ again: | |||
| 984 | evsel = perf_evlist__id2evsel(evlist, sample.id); | 1001 | evsel = perf_evlist__id2evsel(evlist, sample.id); |
| 985 | if (evsel == NULL) { | 1002 | if (evsel == NULL) { |
| 986 | fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); | 1003 | fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); |
| 987 | continue; | 1004 | goto next_event; |
| 988 | } | 1005 | } |
| 989 | 1006 | ||
| 990 | if (sample.raw_data == NULL) { | 1007 | if (sample.raw_data == NULL) { |
| 991 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", | 1008 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", |
| 992 | perf_evsel__name(evsel), sample.tid, | 1009 | perf_evsel__name(evsel), sample.tid, |
| 993 | sample.cpu, sample.raw_size); | 1010 | sample.cpu, sample.raw_size); |
| 994 | continue; | 1011 | goto next_event; |
| 995 | } | 1012 | } |
| 996 | 1013 | ||
| 997 | handler = evsel->handler.func; | 1014 | handler = evsel->handler.func; |
| 998 | handler(trace, evsel, &sample); | 1015 | handler(trace, evsel, &sample); |
| 1016 | next_event: | ||
| 1017 | perf_evlist__mmap_consume(evlist, i); | ||
| 999 | 1018 | ||
| 1000 | if (done) | 1019 | if (done) |
| 1001 | goto out_unmap_evlist; | 1020 | goto out_unmap_evlist; |
| @@ -1038,6 +1057,7 @@ static int trace__replay(struct trace *trace) | |||
| 1038 | 1057 | ||
| 1039 | trace->tool.sample = trace__process_sample; | 1058 | trace->tool.sample = trace__process_sample; |
| 1040 | trace->tool.mmap = perf_event__process_mmap; | 1059 | trace->tool.mmap = perf_event__process_mmap; |
| 1060 | trace->tool.mmap2 = perf_event__process_mmap2; | ||
| 1041 | trace->tool.comm = perf_event__process_comm; | 1061 | trace->tool.comm = perf_event__process_comm; |
| 1042 | trace->tool.exit = perf_event__process_exit; | 1062 | trace->tool.exit = perf_event__process_exit; |
| 1043 | trace->tool.fork = perf_event__process_fork; | 1063 | trace->tool.fork = perf_event__process_fork; |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 214e17e97e5c..5f6f9b3271bb 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
| @@ -87,7 +87,7 @@ CFLAGS += -Wall | |||
| 87 | CFLAGS += -Wextra | 87 | CFLAGS += -Wextra |
| 88 | CFLAGS += -std=gnu99 | 88 | CFLAGS += -std=gnu99 |
| 89 | 89 | ||
| 90 | EXTLIBS = -lelf -lpthread -lrt -lm | 90 | EXTLIBS = -lelf -lpthread -lrt -lm -ldl |
| 91 | 91 | ||
| 92 | ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) | 92 | ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) |
| 93 | CFLAGS += -fstack-protector-all | 93 | CFLAGS += -fstack-protector-all |
| @@ -180,6 +180,9 @@ FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) | |||
| 180 | ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y) | 180 | ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y) |
| 181 | CFLAGS += -DLIBELF_MMAP | 181 | CFLAGS += -DLIBELF_MMAP |
| 182 | endif | 182 | endif |
| 183 | ifeq ($(call try-cc,$(SOURCE_ELF_GETPHDRNUM),$(FLAGS_LIBELF),-DHAVE_ELF_GETPHDRNUM),y) | ||
| 184 | CFLAGS += -DHAVE_ELF_GETPHDRNUM | ||
| 185 | endif | ||
| 183 | 186 | ||
| 184 | # include ARCH specific config | 187 | # include ARCH specific config |
| 185 | -include $(src-perf)/arch/$(ARCH)/Makefile | 188 | -include $(src-perf)/arch/$(ARCH)/Makefile |
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak index 708fb8e9822a..f79305739ecc 100644 --- a/tools/perf/config/feature-tests.mak +++ b/tools/perf/config/feature-tests.mak | |||
| @@ -61,6 +61,15 @@ int main(void) | |||
| 61 | } | 61 | } |
| 62 | endef | 62 | endef |
| 63 | 63 | ||
| 64 | define SOURCE_ELF_GETPHDRNUM | ||
| 65 | #include <libelf.h> | ||
| 66 | int main(void) | ||
| 67 | { | ||
| 68 | size_t dst; | ||
| 69 | return elf_getphdrnum(0, &dst); | ||
| 70 | } | ||
| 71 | endef | ||
| 72 | |||
| 64 | ifndef NO_SLANG | 73 | ifndef NO_SLANG |
| 65 | define SOURCE_SLANG | 74 | define SOURCE_SLANG |
| 66 | #include <slang.h> | 75 | #include <slang.h> |
| @@ -210,6 +219,7 @@ define SOURCE_LIBAUDIT | |||
| 210 | 219 | ||
| 211 | int main(void) | 220 | int main(void) |
| 212 | { | 221 | { |
| 222 | printf(\"error message: %s\", audit_errno_to_name(0)); | ||
| 213 | return audit_open(); | 223 | return audit_open(); |
| 214 | } | 224 | } |
| 215 | endef | 225 | endef |
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 6fb781d5586c..e3fedfa2906e 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
| @@ -290,6 +290,7 @@ static int process_events(struct machine *machine, struct perf_evlist *evlist, | |||
| 290 | for (i = 0; i < evlist->nr_mmaps; i++) { | 290 | for (i = 0; i < evlist->nr_mmaps; i++) { |
| 291 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { | 291 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { |
| 292 | ret = process_event(machine, evlist, event, state); | 292 | ret = process_event(machine, evlist, event, state); |
| 293 | perf_evlist__mmap_consume(evlist, i); | ||
| 293 | if (ret < 0) | 294 | if (ret < 0) |
| 294 | return ret; | 295 | return ret; |
| 295 | } | 296 | } |
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index d444ea2c47d9..376c35608534 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c | |||
| @@ -36,6 +36,7 @@ static int find_comm(struct perf_evlist *evlist, const char *comm) | |||
| 36 | (pid_t)event->comm.tid == getpid() && | 36 | (pid_t)event->comm.tid == getpid() && |
| 37 | strcmp(event->comm.comm, comm) == 0) | 37 | strcmp(event->comm.comm, comm) == 0) |
| 38 | found += 1; | 38 | found += 1; |
| 39 | perf_evlist__mmap_consume(evlist, i); | ||
| 39 | } | 40 | } |
| 40 | } | 41 | } |
| 41 | return found; | 42 | return found; |
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index c4185b9aeb80..a7232c204eb9 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c | |||
| @@ -122,6 +122,7 @@ int test__basic_mmap(void) | |||
| 122 | goto out_munmap; | 122 | goto out_munmap; |
| 123 | } | 123 | } |
| 124 | nr_events[evsel->idx]++; | 124 | nr_events[evsel->idx]++; |
| 125 | perf_evlist__mmap_consume(evlist, 0); | ||
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | err = 0; | 128 | err = 0; |
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c index fc5b9fca8b47..524b221b829b 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c | |||
| @@ -77,8 +77,10 @@ int test__syscall_open_tp_fields(void) | |||
| 77 | 77 | ||
| 78 | ++nr_events; | 78 | ++nr_events; |
| 79 | 79 | ||
| 80 | if (type != PERF_RECORD_SAMPLE) | 80 | if (type != PERF_RECORD_SAMPLE) { |
| 81 | perf_evlist__mmap_consume(evlist, i); | ||
| 81 | continue; | 82 | continue; |
| 83 | } | ||
| 82 | 84 | ||
| 83 | err = perf_evsel__parse_sample(evsel, event, &sample); | 85 | err = perf_evsel__parse_sample(evsel, event, &sample); |
| 84 | if (err) { | 86 | if (err) { |
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index b8a7056519ac..7923b06ffc91 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
| @@ -263,6 +263,8 @@ int test__PERF_RECORD(void) | |||
| 263 | type); | 263 | type); |
| 264 | ++errs; | 264 | ++errs; |
| 265 | } | 265 | } |
| 266 | |||
| 267 | perf_evlist__mmap_consume(evlist, i); | ||
| 266 | } | 268 | } |
| 267 | } | 269 | } |
| 268 | 270 | ||
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index 0ab61b1f408e..4ca1b938f6a6 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c | |||
| @@ -122,7 +122,7 @@ int test__perf_time_to_tsc(void) | |||
| 122 | if (event->header.type != PERF_RECORD_COMM || | 122 | if (event->header.type != PERF_RECORD_COMM || |
| 123 | (pid_t)event->comm.pid != getpid() || | 123 | (pid_t)event->comm.pid != getpid() || |
| 124 | (pid_t)event->comm.tid != getpid()) | 124 | (pid_t)event->comm.tid != getpid()) |
| 125 | continue; | 125 | goto next_event; |
| 126 | 126 | ||
| 127 | if (strcmp(event->comm.comm, comm1) == 0) { | 127 | if (strcmp(event->comm.comm, comm1) == 0) { |
| 128 | CHECK__(perf_evsel__parse_sample(evsel, event, | 128 | CHECK__(perf_evsel__parse_sample(evsel, event, |
| @@ -134,6 +134,8 @@ int test__perf_time_to_tsc(void) | |||
| 134 | &sample)); | 134 | &sample)); |
| 135 | comm2_time = sample.time; | 135 | comm2_time = sample.time; |
| 136 | } | 136 | } |
| 137 | next_event: | ||
| 138 | perf_evlist__mmap_consume(evlist, i); | ||
| 137 | } | 139 | } |
| 138 | } | 140 | } |
| 139 | 141 | ||
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index 2e41e2d32ccc..6e2b44ec0749 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c | |||
| @@ -78,7 +78,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) | |||
| 78 | struct perf_sample sample; | 78 | struct perf_sample sample; |
| 79 | 79 | ||
| 80 | if (event->header.type != PERF_RECORD_SAMPLE) | 80 | if (event->header.type != PERF_RECORD_SAMPLE) |
| 81 | continue; | 81 | goto next_event; |
| 82 | 82 | ||
| 83 | err = perf_evlist__parse_sample(evlist, event, &sample); | 83 | err = perf_evlist__parse_sample(evlist, event, &sample); |
| 84 | if (err < 0) { | 84 | if (err < 0) { |
| @@ -88,6 +88,8 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) | |||
| 88 | 88 | ||
| 89 | total_periods += sample.period; | 89 | total_periods += sample.period; |
| 90 | nr_samples++; | 90 | nr_samples++; |
| 91 | next_event: | ||
| 92 | perf_evlist__mmap_consume(evlist, 0); | ||
| 91 | } | 93 | } |
| 92 | 94 | ||
| 93 | if ((u64) nr_samples == total_periods) { | 95 | if ((u64) nr_samples == total_periods) { |
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index 28fe5894b061..a3e64876e940 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c | |||
| @@ -96,10 +96,10 @@ int test__task_exit(void) | |||
| 96 | 96 | ||
| 97 | retry: | 97 | retry: |
| 98 | while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) { | 98 | while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) { |
| 99 | if (event->header.type != PERF_RECORD_EXIT) | 99 | if (event->header.type == PERF_RECORD_EXIT) |
| 100 | continue; | 100 | nr_exit++; |
| 101 | 101 | ||
| 102 | nr_exit++; | 102 | perf_evlist__mmap_consume(evlist, 0); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | if (!exited || !nr_exit) { | 105 | if (!exited || !nr_exit) { |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 194e2f42ff5d..6c152686e837 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
| @@ -315,8 +315,7 @@ static inline void advance_hpp(struct perf_hpp *hpp, int inc) | |||
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | static int hist_entry__period_snprintf(struct perf_hpp *hpp, | 317 | static int hist_entry__period_snprintf(struct perf_hpp *hpp, |
| 318 | struct hist_entry *he, | 318 | struct hist_entry *he) |
| 319 | bool color) | ||
| 320 | { | 319 | { |
| 321 | const char *sep = symbol_conf.field_sep; | 320 | const char *sep = symbol_conf.field_sep; |
| 322 | struct perf_hpp_fmt *fmt; | 321 | struct perf_hpp_fmt *fmt; |
| @@ -338,7 +337,7 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp, | |||
| 338 | } else | 337 | } else |
| 339 | first = false; | 338 | first = false; |
| 340 | 339 | ||
| 341 | if (color && fmt->color) | 340 | if (perf_hpp__use_color() && fmt->color) |
| 342 | ret = fmt->color(fmt, hpp, he); | 341 | ret = fmt->color(fmt, hpp, he); |
| 343 | else | 342 | else |
| 344 | ret = fmt->entry(fmt, hpp, he); | 343 | ret = fmt->entry(fmt, hpp, he); |
| @@ -358,12 +357,11 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, | |||
| 358 | .buf = bf, | 357 | .buf = bf, |
| 359 | .size = size, | 358 | .size = size, |
| 360 | }; | 359 | }; |
| 361 | bool color = !symbol_conf.field_sep; | ||
| 362 | 360 | ||
| 363 | if (size == 0 || size > bfsz) | 361 | if (size == 0 || size > bfsz) |
| 364 | size = hpp.size = bfsz; | 362 | size = hpp.size = bfsz; |
| 365 | 363 | ||
| 366 | ret = hist_entry__period_snprintf(&hpp, he, color); | 364 | ret = hist_entry__period_snprintf(&hpp, he); |
| 367 | hist_entry__sort_snprintf(he, bf + ret, size - ret, hists); | 365 | hist_entry__sort_snprintf(he, bf + ret, size - ret, hists); |
| 368 | 366 | ||
| 369 | ret = fprintf(fp, "%s\n", bf); | 367 | ret = fprintf(fp, "%s\n", bf); |
| @@ -482,6 +480,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
| 482 | 480 | ||
| 483 | print_entries: | 481 | print_entries: |
| 484 | linesz = hists__sort_list_width(hists) + 3 + 1; | 482 | linesz = hists__sort_list_width(hists) + 3 + 1; |
| 483 | linesz += perf_hpp__color_overhead(); | ||
| 485 | line = malloc(linesz); | 484 | line = malloc(linesz); |
| 486 | if (line == NULL) { | 485 | if (line == NULL) { |
| 487 | ret = -1; | 486 | ret = -1; |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index bfc5a27597d6..7eae5488ecea 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
| @@ -809,7 +809,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
| 809 | end = map__rip_2objdump(map, sym->end); | 809 | end = map__rip_2objdump(map, sym->end); |
| 810 | 810 | ||
| 811 | offset = line_ip - start; | 811 | offset = line_ip - start; |
| 812 | if (offset < 0 || (u64)line_ip > end) | 812 | if ((u64)line_ip < start || (u64)line_ip > end) |
| 813 | offset = -1; | 813 | offset = -1; |
| 814 | else | 814 | else |
| 815 | parsed_line = tmp2 + 1; | 815 | parsed_line = tmp2 + 1; |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 2b585bc308cf..9e99060408ae 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
| @@ -147,6 +147,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) | |||
| 147 | 147 | ||
| 148 | struct option; | 148 | struct option; |
| 149 | 149 | ||
| 150 | int record_parse_callchain(const char *arg, struct perf_record_opts *opts); | ||
| 150 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); | 151 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); |
| 152 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); | ||
| 153 | |||
| 151 | extern const char record_callchain_help[]; | 154 | extern const char record_callchain_help[]; |
| 152 | #endif /* __PERF_CALLCHAIN_H */ | 155 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 3e5f5430a28a..7defd77105d0 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
| @@ -263,6 +263,21 @@ bool die_is_signed_type(Dwarf_Die *tp_die) | |||
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | /** | 265 | /** |
| 266 | * die_is_func_def - Ensure that this DIE is a subprogram and definition | ||
| 267 | * @dw_die: a DIE | ||
| 268 | * | ||
| 269 | * Ensure that this DIE is a subprogram and NOT a declaration. This | ||
| 270 | * returns true if @dw_die is a function definition. | ||
| 271 | **/ | ||
| 272 | bool die_is_func_def(Dwarf_Die *dw_die) | ||
| 273 | { | ||
| 274 | Dwarf_Attribute attr; | ||
| 275 | |||
| 276 | return (dwarf_tag(dw_die) == DW_TAG_subprogram && | ||
| 277 | dwarf_attr(dw_die, DW_AT_declaration, &attr) == NULL); | ||
| 278 | } | ||
| 279 | |||
| 280 | /** | ||
| 266 | * die_get_data_member_location - Get the data-member offset | 281 | * die_get_data_member_location - Get the data-member offset |
| 267 | * @mb_die: a DIE of a member of a data structure | 282 | * @mb_die: a DIE of a member of a data structure |
| 268 | * @offs: The offset of the member in the data structure | 283 | * @offs: The offset of the member in the data structure |
| @@ -392,6 +407,10 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | |||
| 392 | { | 407 | { |
| 393 | struct __addr_die_search_param *ad = data; | 408 | struct __addr_die_search_param *ad = data; |
| 394 | 409 | ||
| 410 | /* | ||
| 411 | * Since a declaration entry doesn't has given pc, this always returns | ||
| 412 | * function definition entry. | ||
| 413 | */ | ||
| 395 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && | 414 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && |
| 396 | dwarf_haspc(fn_die, ad->addr)) { | 415 | dwarf_haspc(fn_die, ad->addr)) { |
| 397 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); | 416 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); |
| @@ -407,7 +426,7 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | |||
| 407 | * @die_mem: a buffer for result DIE | 426 | * @die_mem: a buffer for result DIE |
| 408 | * | 427 | * |
| 409 | * Search a non-inlined function DIE which includes @addr. Stores the | 428 | * Search a non-inlined function DIE which includes @addr. Stores the |
| 410 | * DIE to @die_mem and returns it if found. Returns NULl if failed. | 429 | * DIE to @die_mem and returns it if found. Returns NULL if failed. |
| 411 | */ | 430 | */ |
| 412 | Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | 431 | Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, |
| 413 | Dwarf_Die *die_mem) | 432 | Dwarf_Die *die_mem) |
| @@ -435,15 +454,32 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) | |||
| 435 | } | 454 | } |
| 436 | 455 | ||
| 437 | /** | 456 | /** |
| 457 | * die_find_top_inlinefunc - Search the top inlined function at given address | ||
| 458 | * @sp_die: a subprogram DIE which including @addr | ||
| 459 | * @addr: target address | ||
| 460 | * @die_mem: a buffer for result DIE | ||
| 461 | * | ||
| 462 | * Search an inlined function DIE which includes @addr. Stores the | ||
| 463 | * DIE to @die_mem and returns it if found. Returns NULL if failed. | ||
| 464 | * Even if several inlined functions are expanded recursively, this | ||
| 465 | * doesn't trace it down, and returns the topmost one. | ||
| 466 | */ | ||
| 467 | Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | ||
| 468 | Dwarf_Die *die_mem) | ||
| 469 | { | ||
| 470 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); | ||
| 471 | } | ||
| 472 | |||
| 473 | /** | ||
| 438 | * die_find_inlinefunc - Search an inlined function at given address | 474 | * die_find_inlinefunc - Search an inlined function at given address |
| 439 | * @cu_die: a CU DIE which including @addr | 475 | * @sp_die: a subprogram DIE which including @addr |
| 440 | * @addr: target address | 476 | * @addr: target address |
| 441 | * @die_mem: a buffer for result DIE | 477 | * @die_mem: a buffer for result DIE |
| 442 | * | 478 | * |
| 443 | * Search an inlined function DIE which includes @addr. Stores the | 479 | * Search an inlined function DIE which includes @addr. Stores the |
| 444 | * DIE to @die_mem and returns it if found. Returns NULl if failed. | 480 | * DIE to @die_mem and returns it if found. Returns NULL if failed. |
| 445 | * If several inlined functions are expanded recursively, this trace | 481 | * If several inlined functions are expanded recursively, this trace |
| 446 | * it and returns deepest one. | 482 | * it down and returns deepest one. |
| 447 | */ | 483 | */ |
| 448 | Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 484 | Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
| 449 | Dwarf_Die *die_mem) | 485 | Dwarf_Die *die_mem) |
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 6ce1717784b7..b4fe90c6cb2d 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
| @@ -38,6 +38,9 @@ extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, | |||
| 38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | 38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, |
| 39 | int (*callback)(Dwarf_Die *, void *), void *data); | 39 | int (*callback)(Dwarf_Die *, void *), void *data); |
| 40 | 40 | ||
| 41 | /* Ensure that this DIE is a subprogram and definition (not declaration) */ | ||
| 42 | extern bool die_is_func_def(Dwarf_Die *dw_die); | ||
| 43 | |||
| 41 | /* Compare diename and tname */ | 44 | /* Compare diename and tname */ |
| 42 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); | 45 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); |
| 43 | 46 | ||
| @@ -76,7 +79,11 @@ extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die, | |||
| 76 | extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | 79 | extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, |
| 77 | Dwarf_Die *die_mem); | 80 | Dwarf_Die *die_mem); |
| 78 | 81 | ||
| 79 | /* Search an inlined function including given address */ | 82 | /* Search the top inlined function including given address */ |
| 83 | extern Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | ||
| 84 | Dwarf_Die *die_mem); | ||
| 85 | |||
| 86 | /* Search the deepest inlined function including given address */ | ||
| 80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 87 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
| 81 | Dwarf_Die *die_mem); | 88 | Dwarf_Die *die_mem); |
| 82 | 89 | ||
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 9b393e7dca6f..49096ea58a15 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -187,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
| 187 | return -1; | 187 | return -1; |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | event->header.type = PERF_RECORD_MMAP2; | 190 | event->header.type = PERF_RECORD_MMAP; |
| 191 | /* | 191 | /* |
| 192 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c | 192 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c |
| 193 | */ | 193 | */ |
| @@ -198,7 +198,6 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
| 198 | char prot[5]; | 198 | char prot[5]; |
| 199 | char execname[PATH_MAX]; | 199 | char execname[PATH_MAX]; |
| 200 | char anonstr[] = "//anon"; | 200 | char anonstr[] = "//anon"; |
| 201 | unsigned int ino; | ||
| 202 | size_t size; | 201 | size_t size; |
| 203 | ssize_t n; | 202 | ssize_t n; |
| 204 | 203 | ||
| @@ -209,15 +208,12 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
| 209 | strcpy(execname, ""); | 208 | strcpy(execname, ""); |
| 210 | 209 | ||
| 211 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ | 210 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ |
| 212 | n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", | 211 | n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", |
| 213 | &event->mmap2.start, &event->mmap2.len, prot, | 212 | &event->mmap.start, &event->mmap.len, prot, |
| 214 | &event->mmap2.pgoff, &event->mmap2.maj, | 213 | &event->mmap.pgoff, |
| 215 | &event->mmap2.min, | 214 | execname); |
| 216 | &ino, execname); | ||
| 217 | |||
| 218 | event->mmap2.ino = (u64)ino; | ||
| 219 | 215 | ||
| 220 | if (n != 8) | 216 | if (n != 5) |
| 221 | continue; | 217 | continue; |
| 222 | 218 | ||
| 223 | if (prot[2] != 'x') | 219 | if (prot[2] != 'x') |
| @@ -227,15 +223,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
| 227 | strcpy(execname, anonstr); | 223 | strcpy(execname, anonstr); |
| 228 | 224 | ||
| 229 | size = strlen(execname) + 1; | 225 | size = strlen(execname) + 1; |
| 230 | memcpy(event->mmap2.filename, execname, size); | 226 | memcpy(event->mmap.filename, execname, size); |
| 231 | size = PERF_ALIGN(size, sizeof(u64)); | 227 | size = PERF_ALIGN(size, sizeof(u64)); |
| 232 | event->mmap2.len -= event->mmap.start; | 228 | event->mmap.len -= event->mmap.start; |
| 233 | event->mmap2.header.size = (sizeof(event->mmap2) - | 229 | event->mmap.header.size = (sizeof(event->mmap) - |
| 234 | (sizeof(event->mmap2.filename) - size)); | 230 | (sizeof(event->mmap.filename) - size)); |
| 235 | memset(event->mmap2.filename + size, 0, machine->id_hdr_size); | 231 | memset(event->mmap.filename + size, 0, machine->id_hdr_size); |
| 236 | event->mmap2.header.size += machine->id_hdr_size; | 232 | event->mmap.header.size += machine->id_hdr_size; |
| 237 | event->mmap2.pid = tgid; | 233 | event->mmap.pid = tgid; |
| 238 | event->mmap2.tid = pid; | 234 | event->mmap.tid = pid; |
| 239 | 235 | ||
| 240 | if (process(tool, event, &synth_sample, machine) != 0) { | 236 | if (process(tool, event, &synth_sample, machine) != 0) { |
| 241 | rc = -1; | 237 | rc = -1; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index f9f77bee0b1b..e584cd30b0f2 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -545,12 +545,19 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
| 545 | 545 | ||
| 546 | md->prev = old; | 546 | md->prev = old; |
| 547 | 547 | ||
| 548 | if (!evlist->overwrite) | ||
| 549 | perf_mmap__write_tail(md, old); | ||
| 550 | |||
| 551 | return event; | 548 | return event; |
| 552 | } | 549 | } |
| 553 | 550 | ||
| 551 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) | ||
| 552 | { | ||
| 553 | if (!evlist->overwrite) { | ||
| 554 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
| 555 | unsigned int old = md->prev; | ||
| 556 | |||
| 557 | perf_mmap__write_tail(md, old); | ||
| 558 | } | ||
| 559 | } | ||
| 560 | |||
| 554 | static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) | 561 | static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) |
| 555 | { | 562 | { |
| 556 | if (evlist->mmap[idx].base != NULL) { | 563 | if (evlist->mmap[idx].base != NULL) { |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 880d7139d2fb..206d09339306 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -89,6 +89,8 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); | |||
| 89 | 89 | ||
| 90 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | 90 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); |
| 91 | 91 | ||
| 92 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); | ||
| 93 | |||
| 92 | int perf_evlist__open(struct perf_evlist *evlist); | 94 | int perf_evlist__open(struct perf_evlist *evlist); |
| 93 | void perf_evlist__close(struct perf_evlist *evlist); | 95 | void perf_evlist__close(struct perf_evlist *evlist); |
| 94 | 96 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0ce9febf1ba0..9f1ef9bee2d0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -678,7 +678,6 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
| 678 | attr->sample_type |= PERF_SAMPLE_WEIGHT; | 678 | attr->sample_type |= PERF_SAMPLE_WEIGHT; |
| 679 | 679 | ||
| 680 | attr->mmap = track; | 680 | attr->mmap = track; |
| 681 | attr->mmap2 = track && !perf_missing_features.mmap2; | ||
| 682 | attr->comm = track; | 681 | attr->comm = track; |
| 683 | 682 | ||
| 684 | /* | 683 | /* |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 26441d0e571b..c3e5a3b817ab 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -199,9 +199,11 @@ static int write_buildid(char *name, size_t name_len, u8 *build_id, | |||
| 199 | return write_padded(fd, name, name_len + 1, len); | 199 | return write_padded(fd, name, name_len + 1, len); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, | 202 | static int __dsos__write_buildid_table(struct list_head *head, |
| 203 | u16 misc, int fd) | 203 | struct machine *machine, |
| 204 | pid_t pid, u16 misc, int fd) | ||
| 204 | { | 205 | { |
| 206 | char nm[PATH_MAX]; | ||
| 205 | struct dso *pos; | 207 | struct dso *pos; |
| 206 | 208 | ||
| 207 | dsos__for_each_with_build_id(pos, head) { | 209 | dsos__for_each_with_build_id(pos, head) { |
| @@ -215,6 +217,10 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, | |||
| 215 | if (is_vdso_map(pos->short_name)) { | 217 | if (is_vdso_map(pos->short_name)) { |
| 216 | name = (char *) VDSO__MAP_NAME; | 218 | name = (char *) VDSO__MAP_NAME; |
| 217 | name_len = sizeof(VDSO__MAP_NAME) + 1; | 219 | name_len = sizeof(VDSO__MAP_NAME) + 1; |
| 220 | } else if (dso__is_kcore(pos)) { | ||
| 221 | machine__mmap_name(machine, nm, sizeof(nm)); | ||
| 222 | name = nm; | ||
| 223 | name_len = strlen(nm) + 1; | ||
| 218 | } else { | 224 | } else { |
| 219 | name = pos->long_name; | 225 | name = pos->long_name; |
| 220 | name_len = pos->long_name_len + 1; | 226 | name_len = pos->long_name_len + 1; |
| @@ -240,10 +246,10 @@ static int machine__write_buildid_table(struct machine *machine, int fd) | |||
| 240 | umisc = PERF_RECORD_MISC_GUEST_USER; | 246 | umisc = PERF_RECORD_MISC_GUEST_USER; |
| 241 | } | 247 | } |
| 242 | 248 | ||
| 243 | err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, | 249 | err = __dsos__write_buildid_table(&machine->kernel_dsos, machine, |
| 244 | kmisc, fd); | 250 | machine->pid, kmisc, fd); |
| 245 | if (err == 0) | 251 | if (err == 0) |
| 246 | err = __dsos__write_buildid_table(&machine->user_dsos, | 252 | err = __dsos__write_buildid_table(&machine->user_dsos, machine, |
| 247 | machine->pid, umisc, fd); | 253 | machine->pid, umisc, fd); |
| 248 | return err; | 254 | return err; |
| 249 | } | 255 | } |
| @@ -375,23 +381,31 @@ out_free: | |||
| 375 | return err; | 381 | return err; |
| 376 | } | 382 | } |
| 377 | 383 | ||
| 378 | static int dso__cache_build_id(struct dso *dso, const char *debugdir) | 384 | static int dso__cache_build_id(struct dso *dso, struct machine *machine, |
| 385 | const char *debugdir) | ||
| 379 | { | 386 | { |
| 380 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; | 387 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; |
| 381 | bool is_vdso = is_vdso_map(dso->short_name); | 388 | bool is_vdso = is_vdso_map(dso->short_name); |
| 389 | char *name = dso->long_name; | ||
| 390 | char nm[PATH_MAX]; | ||
| 382 | 391 | ||
| 383 | return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), | 392 | if (dso__is_kcore(dso)) { |
| 384 | dso->long_name, debugdir, | 393 | is_kallsyms = true; |
| 385 | is_kallsyms, is_vdso); | 394 | machine__mmap_name(machine, nm, sizeof(nm)); |
| 395 | name = nm; | ||
| 396 | } | ||
| 397 | return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name, | ||
| 398 | debugdir, is_kallsyms, is_vdso); | ||
| 386 | } | 399 | } |
| 387 | 400 | ||
| 388 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | 401 | static int __dsos__cache_build_ids(struct list_head *head, |
| 402 | struct machine *machine, const char *debugdir) | ||
| 389 | { | 403 | { |
| 390 | struct dso *pos; | 404 | struct dso *pos; |
| 391 | int err = 0; | 405 | int err = 0; |
| 392 | 406 | ||
| 393 | dsos__for_each_with_build_id(pos, head) | 407 | dsos__for_each_with_build_id(pos, head) |
| 394 | if (dso__cache_build_id(pos, debugdir)) | 408 | if (dso__cache_build_id(pos, machine, debugdir)) |
| 395 | err = -1; | 409 | err = -1; |
| 396 | 410 | ||
| 397 | return err; | 411 | return err; |
| @@ -399,8 +413,9 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | |||
| 399 | 413 | ||
| 400 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) | 414 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) |
| 401 | { | 415 | { |
| 402 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); | 416 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos, machine, |
| 403 | ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); | 417 | debugdir); |
| 418 | ret |= __dsos__cache_build_ids(&machine->user_dsos, machine, debugdir); | ||
| 404 | return ret; | 419 | return ret; |
| 405 | } | 420 | } |
| 406 | 421 | ||
| @@ -2753,6 +2768,18 @@ int perf_session__read_header(struct perf_session *session) | |||
| 2753 | if (perf_file_header__read(&f_header, header, fd) < 0) | 2768 | if (perf_file_header__read(&f_header, header, fd) < 0) |
| 2754 | return -EINVAL; | 2769 | return -EINVAL; |
| 2755 | 2770 | ||
| 2771 | /* | ||
| 2772 | * Sanity check that perf.data was written cleanly; data size is | ||
| 2773 | * initialized to 0 and updated only if the on_exit function is run. | ||
| 2774 | * If data size is still 0 then the file contains only partial | ||
| 2775 | * information. Just warn user and process it as much as it can. | ||
| 2776 | */ | ||
| 2777 | if (f_header.data.size == 0) { | ||
| 2778 | pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n" | ||
| 2779 | "Was the 'perf record' command properly terminated?\n", | ||
| 2780 | session->filename); | ||
| 2781 | } | ||
| 2782 | |||
| 2756 | nr_attrs = f_header.attrs.size / f_header.attr_size; | 2783 | nr_attrs = f_header.attrs.size / f_header.attr_size; |
| 2757 | lseek(fd, f_header.attrs.offset, SEEK_SET); | 2784 | lseek(fd, f_header.attrs.offset, SEEK_SET); |
| 2758 | 2785 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 46a0d35a05e1..9ff6cf3e9a99 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -611,6 +611,8 @@ void hists__collapse_resort(struct hists *hists) | |||
| 611 | next = rb_first(root); | 611 | next = rb_first(root); |
| 612 | 612 | ||
| 613 | while (next) { | 613 | while (next) { |
| 614 | if (session_done()) | ||
| 615 | break; | ||
| 614 | n = rb_entry(next, struct hist_entry, rb_node_in); | 616 | n = rb_entry(next, struct hist_entry, rb_node_in); |
| 615 | next = rb_next(&n->rb_node_in); | 617 | next = rb_next(&n->rb_node_in); |
| 616 | 618 | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 1329b6b6ffe6..ce8dc61ce2c3 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <pthread.h> | 5 | #include <pthread.h> |
| 6 | #include "callchain.h" | 6 | #include "callchain.h" |
| 7 | #include "header.h" | 7 | #include "header.h" |
| 8 | #include "color.h" | ||
| 8 | 9 | ||
| 9 | extern struct callchain_param callchain_param; | 10 | extern struct callchain_param callchain_param; |
| 10 | 11 | ||
| @@ -175,6 +176,18 @@ void perf_hpp__init(void); | |||
| 175 | void perf_hpp__column_register(struct perf_hpp_fmt *format); | 176 | void perf_hpp__column_register(struct perf_hpp_fmt *format); |
| 176 | void perf_hpp__column_enable(unsigned col); | 177 | void perf_hpp__column_enable(unsigned col); |
| 177 | 178 | ||
| 179 | static inline size_t perf_hpp__use_color(void) | ||
| 180 | { | ||
| 181 | return !symbol_conf.field_sep; | ||
| 182 | } | ||
| 183 | |||
| 184 | static inline size_t perf_hpp__color_overhead(void) | ||
| 185 | { | ||
| 186 | return perf_hpp__use_color() ? | ||
| 187 | (COLOR_MAXLEN + sizeof(PERF_COLOR_RESET)) * PERF_HPP__MAX_INDEX | ||
| 188 | : 0; | ||
| 189 | } | ||
| 190 | |||
| 178 | struct perf_evlist; | 191 | struct perf_evlist; |
| 179 | 192 | ||
| 180 | struct hist_browser_timer { | 193 | struct hist_browser_timer { |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 933d14f287ca..6188d2876a71 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
| @@ -792,7 +792,7 @@ static int machine__create_modules(struct machine *machine) | |||
| 792 | modules = path; | 792 | modules = path; |
| 793 | } | 793 | } |
| 794 | 794 | ||
| 795 | if (symbol__restricted_filename(path, "/proc/modules")) | 795 | if (symbol__restricted_filename(modules, "/proc/modules")) |
| 796 | return -1; | 796 | return -1; |
| 797 | 797 | ||
| 798 | file = fopen(modules, "r"); | 798 | file = fopen(modules, "r"); |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index be0329394d56..f0692737ebf1 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -118,7 +118,6 @@ static const Dwfl_Callbacks offline_callbacks = { | |||
| 118 | static int debuginfo__init_offline_dwarf(struct debuginfo *self, | 118 | static int debuginfo__init_offline_dwarf(struct debuginfo *self, |
| 119 | const char *path) | 119 | const char *path) |
| 120 | { | 120 | { |
| 121 | Dwfl_Module *mod; | ||
| 122 | int fd; | 121 | int fd; |
| 123 | 122 | ||
| 124 | fd = open(path, O_RDONLY); | 123 | fd = open(path, O_RDONLY); |
| @@ -129,11 +128,11 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *self, | |||
| 129 | if (!self->dwfl) | 128 | if (!self->dwfl) |
| 130 | goto error; | 129 | goto error; |
| 131 | 130 | ||
| 132 | mod = dwfl_report_offline(self->dwfl, "", "", fd); | 131 | self->mod = dwfl_report_offline(self->dwfl, "", "", fd); |
| 133 | if (!mod) | 132 | if (!self->mod) |
| 134 | goto error; | 133 | goto error; |
| 135 | 134 | ||
| 136 | self->dbg = dwfl_module_getdwarf(mod, &self->bias); | 135 | self->dbg = dwfl_module_getdwarf(self->mod, &self->bias); |
| 137 | if (!self->dbg) | 136 | if (!self->dbg) |
| 138 | goto error; | 137 | goto error; |
| 139 | 138 | ||
| @@ -676,37 +675,42 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
| 676 | } | 675 | } |
| 677 | 676 | ||
| 678 | /* Convert subprogram DIE to trace point */ | 677 | /* Convert subprogram DIE to trace point */ |
| 679 | static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, | 678 | static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, |
| 680 | bool retprobe, struct probe_trace_point *tp) | 679 | Dwarf_Addr paddr, bool retprobe, |
| 680 | struct probe_trace_point *tp) | ||
| 681 | { | 681 | { |
| 682 | Dwarf_Addr eaddr, highaddr; | 682 | Dwarf_Addr eaddr, highaddr; |
| 683 | const char *name; | 683 | GElf_Sym sym; |
| 684 | 684 | const char *symbol; | |
| 685 | /* Copy the name of probe point */ | 685 | |
| 686 | name = dwarf_diename(sp_die); | 686 | /* Verify the address is correct */ |
| 687 | if (name) { | 687 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { |
| 688 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { | 688 | pr_warning("Failed to get entry address of %s\n", |
| 689 | pr_warning("Failed to get entry address of %s\n", | 689 | dwarf_diename(sp_die)); |
| 690 | dwarf_diename(sp_die)); | 690 | return -ENOENT; |
| 691 | return -ENOENT; | 691 | } |
| 692 | } | 692 | if (dwarf_highpc(sp_die, &highaddr) != 0) { |
| 693 | if (dwarf_highpc(sp_die, &highaddr) != 0) { | 693 | pr_warning("Failed to get end address of %s\n", |
| 694 | pr_warning("Failed to get end address of %s\n", | 694 | dwarf_diename(sp_die)); |
| 695 | dwarf_diename(sp_die)); | 695 | return -ENOENT; |
| 696 | return -ENOENT; | 696 | } |
| 697 | } | 697 | if (paddr > highaddr) { |
| 698 | if (paddr > highaddr) { | 698 | pr_warning("Offset specified is greater than size of %s\n", |
| 699 | pr_warning("Offset specified is greater than size of %s\n", | 699 | dwarf_diename(sp_die)); |
| 700 | dwarf_diename(sp_die)); | 700 | return -EINVAL; |
| 701 | return -EINVAL; | 701 | } |
| 702 | } | 702 | |
| 703 | tp->symbol = strdup(name); | 703 | /* Get an appropriate symbol from symtab */ |
| 704 | if (tp->symbol == NULL) | 704 | symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); |
| 705 | return -ENOMEM; | 705 | if (!symbol) { |
| 706 | tp->offset = (unsigned long)(paddr - eaddr); | 706 | pr_warning("Failed to find symbol at 0x%lx\n", |
| 707 | } else | 707 | (unsigned long)paddr); |
| 708 | /* This function has no name. */ | 708 | return -ENOENT; |
| 709 | tp->offset = (unsigned long)paddr; | 709 | } |
| 710 | tp->offset = (unsigned long)(paddr - sym.st_value); | ||
| 711 | tp->symbol = strdup(symbol); | ||
| 712 | if (!tp->symbol) | ||
| 713 | return -ENOMEM; | ||
| 710 | 714 | ||
| 711 | /* Return probe must be on the head of a subprogram */ | 715 | /* Return probe must be on the head of a subprogram */ |
| 712 | if (retprobe) { | 716 | if (retprobe) { |
| @@ -734,7 +738,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
| 734 | } | 738 | } |
| 735 | 739 | ||
| 736 | /* If not a real subprogram, find a real one */ | 740 | /* If not a real subprogram, find a real one */ |
| 737 | if (dwarf_tag(sc_die) != DW_TAG_subprogram) { | 741 | if (!die_is_func_def(sc_die)) { |
| 738 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { | 742 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { |
| 739 | pr_warning("Failed to find probe point in any " | 743 | pr_warning("Failed to find probe point in any " |
| 740 | "functions.\n"); | 744 | "functions.\n"); |
| @@ -980,12 +984,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
| 980 | struct dwarf_callback_param *param = data; | 984 | struct dwarf_callback_param *param = data; |
| 981 | struct probe_finder *pf = param->data; | 985 | struct probe_finder *pf = param->data; |
| 982 | struct perf_probe_point *pp = &pf->pev->point; | 986 | struct perf_probe_point *pp = &pf->pev->point; |
| 983 | Dwarf_Attribute attr; | ||
| 984 | 987 | ||
| 985 | /* Check tag and diename */ | 988 | /* Check tag and diename */ |
| 986 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || | 989 | if (!die_is_func_def(sp_die) || |
| 987 | !die_compare_name(sp_die, pp->function) || | 990 | !die_compare_name(sp_die, pp->function)) |
| 988 | dwarf_attr(sp_die, DW_AT_declaration, &attr)) | ||
| 989 | return DWARF_CB_OK; | 991 | return DWARF_CB_OK; |
| 990 | 992 | ||
| 991 | /* Check declared file */ | 993 | /* Check declared file */ |
| @@ -1151,7 +1153,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
| 1151 | tev = &tf->tevs[tf->ntevs++]; | 1153 | tev = &tf->tevs[tf->ntevs++]; |
| 1152 | 1154 | ||
| 1153 | /* Trace point should be converted from subprogram DIE */ | 1155 | /* Trace point should be converted from subprogram DIE */ |
| 1154 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, | 1156 | ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, |
| 1155 | pf->pev->point.retprobe, &tev->point); | 1157 | pf->pev->point.retprobe, &tev->point); |
| 1156 | if (ret < 0) | 1158 | if (ret < 0) |
| 1157 | return ret; | 1159 | return ret; |
| @@ -1183,7 +1185,7 @@ int debuginfo__find_trace_events(struct debuginfo *self, | |||
| 1183 | { | 1185 | { |
| 1184 | struct trace_event_finder tf = { | 1186 | struct trace_event_finder tf = { |
| 1185 | .pf = {.pev = pev, .callback = add_probe_trace_event}, | 1187 | .pf = {.pev = pev, .callback = add_probe_trace_event}, |
| 1186 | .max_tevs = max_tevs}; | 1188 | .mod = self->mod, .max_tevs = max_tevs}; |
| 1187 | int ret; | 1189 | int ret; |
| 1188 | 1190 | ||
| 1189 | /* Allocate result tevs array */ | 1191 | /* Allocate result tevs array */ |
| @@ -1252,7 +1254,7 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
| 1252 | vl = &af->vls[af->nvls++]; | 1254 | vl = &af->vls[af->nvls++]; |
| 1253 | 1255 | ||
| 1254 | /* Trace point should be converted from subprogram DIE */ | 1256 | /* Trace point should be converted from subprogram DIE */ |
| 1255 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, | 1257 | ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, |
| 1256 | pf->pev->point.retprobe, &vl->point); | 1258 | pf->pev->point.retprobe, &vl->point); |
| 1257 | if (ret < 0) | 1259 | if (ret < 0) |
| 1258 | return ret; | 1260 | return ret; |
| @@ -1291,6 +1293,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self, | |||
| 1291 | { | 1293 | { |
| 1292 | struct available_var_finder af = { | 1294 | struct available_var_finder af = { |
| 1293 | .pf = {.pev = pev, .callback = add_available_vars}, | 1295 | .pf = {.pev = pev, .callback = add_available_vars}, |
| 1296 | .mod = self->mod, | ||
| 1294 | .max_vls = max_vls, .externs = externs}; | 1297 | .max_vls = max_vls, .externs = externs}; |
| 1295 | int ret; | 1298 | int ret; |
| 1296 | 1299 | ||
| @@ -1324,8 +1327,8 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | |||
| 1324 | struct perf_probe_point *ppt) | 1327 | struct perf_probe_point *ppt) |
| 1325 | { | 1328 | { |
| 1326 | Dwarf_Die cudie, spdie, indie; | 1329 | Dwarf_Die cudie, spdie, indie; |
| 1327 | Dwarf_Addr _addr, baseaddr; | 1330 | Dwarf_Addr _addr = 0, baseaddr = 0; |
| 1328 | const char *fname = NULL, *func = NULL, *tmp; | 1331 | const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; |
| 1329 | int baseline = 0, lineno = 0, ret = 0; | 1332 | int baseline = 0, lineno = 0, ret = 0; |
| 1330 | 1333 | ||
| 1331 | /* Adjust address with bias */ | 1334 | /* Adjust address with bias */ |
| @@ -1346,27 +1349,36 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | |||
| 1346 | /* Find a corresponding function (name, baseline and baseaddr) */ | 1349 | /* Find a corresponding function (name, baseline and baseaddr) */ |
| 1347 | if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1350 | if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { |
| 1348 | /* Get function entry information */ | 1351 | /* Get function entry information */ |
| 1349 | tmp = dwarf_diename(&spdie); | 1352 | func = basefunc = dwarf_diename(&spdie); |
| 1350 | if (!tmp || | 1353 | if (!func || |
| 1351 | dwarf_entrypc(&spdie, &baseaddr) != 0 || | 1354 | dwarf_entrypc(&spdie, &baseaddr) != 0 || |
| 1352 | dwarf_decl_line(&spdie, &baseline) != 0) | 1355 | dwarf_decl_line(&spdie, &baseline) != 0) { |
| 1356 | lineno = 0; | ||
| 1353 | goto post; | 1357 | goto post; |
| 1354 | func = tmp; | 1358 | } |
| 1355 | 1359 | ||
| 1356 | if (addr == (unsigned long)baseaddr) | 1360 | fname = dwarf_decl_file(&spdie); |
| 1361 | if (addr == (unsigned long)baseaddr) { | ||
| 1357 | /* Function entry - Relative line number is 0 */ | 1362 | /* Function entry - Relative line number is 0 */ |
| 1358 | lineno = baseline; | 1363 | lineno = baseline; |
| 1359 | else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | 1364 | goto post; |
| 1360 | &indie)) { | 1365 | } |
| 1366 | |||
| 1367 | /* Track down the inline functions step by step */ | ||
| 1368 | while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, | ||
| 1369 | &indie)) { | ||
| 1370 | /* There is an inline function */ | ||
| 1361 | if (dwarf_entrypc(&indie, &_addr) == 0 && | 1371 | if (dwarf_entrypc(&indie, &_addr) == 0 && |
| 1362 | _addr == addr) | 1372 | _addr == addr) { |
| 1363 | /* | 1373 | /* |
| 1364 | * addr is at an inline function entry. | 1374 | * addr is at an inline function entry. |
| 1365 | * In this case, lineno should be the call-site | 1375 | * In this case, lineno should be the call-site |
| 1366 | * line number. | 1376 | * line number. (overwrite lineinfo) |
| 1367 | */ | 1377 | */ |
| 1368 | lineno = die_get_call_lineno(&indie); | 1378 | lineno = die_get_call_lineno(&indie); |
| 1369 | else { | 1379 | fname = die_get_call_file(&indie); |
| 1380 | break; | ||
| 1381 | } else { | ||
| 1370 | /* | 1382 | /* |
| 1371 | * addr is in an inline function body. | 1383 | * addr is in an inline function body. |
| 1372 | * Since lineno points one of the lines | 1384 | * Since lineno points one of the lines |
| @@ -1374,19 +1386,27 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | |||
| 1374 | * be the entry line of the inline function. | 1386 | * be the entry line of the inline function. |
| 1375 | */ | 1387 | */ |
| 1376 | tmp = dwarf_diename(&indie); | 1388 | tmp = dwarf_diename(&indie); |
| 1377 | if (tmp && | 1389 | if (!tmp || |
| 1378 | dwarf_decl_line(&spdie, &baseline) == 0) | 1390 | dwarf_decl_line(&indie, &baseline) != 0) |
| 1379 | func = tmp; | 1391 | break; |
| 1392 | func = tmp; | ||
| 1393 | spdie = indie; | ||
| 1380 | } | 1394 | } |
| 1381 | } | 1395 | } |
| 1396 | /* Verify the lineno and baseline are in a same file */ | ||
| 1397 | tmp = dwarf_decl_file(&spdie); | ||
| 1398 | if (!tmp || strcmp(tmp, fname) != 0) | ||
| 1399 | lineno = 0; | ||
| 1382 | } | 1400 | } |
| 1383 | 1401 | ||
| 1384 | post: | 1402 | post: |
| 1385 | /* Make a relative line number or an offset */ | 1403 | /* Make a relative line number or an offset */ |
| 1386 | if (lineno) | 1404 | if (lineno) |
| 1387 | ppt->line = lineno - baseline; | 1405 | ppt->line = lineno - baseline; |
| 1388 | else if (func) | 1406 | else if (basefunc) { |
| 1389 | ppt->offset = addr - (unsigned long)baseaddr; | 1407 | ppt->offset = addr - (unsigned long)baseaddr; |
| 1408 | func = basefunc; | ||
| 1409 | } | ||
| 1390 | 1410 | ||
| 1391 | /* Duplicate strings */ | 1411 | /* Duplicate strings */ |
| 1392 | if (func) { | 1412 | if (func) { |
| @@ -1474,7 +1494,7 @@ static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | |||
| 1474 | return 0; | 1494 | return 0; |
| 1475 | } | 1495 | } |
| 1476 | 1496 | ||
| 1477 | /* Search function from function name */ | 1497 | /* Search function definition from function name */ |
| 1478 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | 1498 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) |
| 1479 | { | 1499 | { |
| 1480 | struct dwarf_callback_param *param = data; | 1500 | struct dwarf_callback_param *param = data; |
| @@ -1485,7 +1505,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
| 1485 | if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) | 1505 | if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) |
| 1486 | return DWARF_CB_OK; | 1506 | return DWARF_CB_OK; |
| 1487 | 1507 | ||
| 1488 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1508 | if (die_is_func_def(sp_die) && |
| 1489 | die_compare_name(sp_die, lr->function)) { | 1509 | die_compare_name(sp_die, lr->function)) { |
| 1490 | lf->fname = dwarf_decl_file(sp_die); | 1510 | lf->fname = dwarf_decl_file(sp_die); |
| 1491 | dwarf_decl_line(sp_die, &lr->offset); | 1511 | dwarf_decl_line(sp_die, &lr->offset); |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 17e94d0c36f9..3b7d63018960 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
| @@ -23,6 +23,7 @@ static inline int is_c_varname(const char *name) | |||
| 23 | /* debug information structure */ | 23 | /* debug information structure */ |
| 24 | struct debuginfo { | 24 | struct debuginfo { |
| 25 | Dwarf *dbg; | 25 | Dwarf *dbg; |
| 26 | Dwfl_Module *mod; | ||
| 26 | Dwfl *dwfl; | 27 | Dwfl *dwfl; |
| 27 | Dwarf_Addr bias; | 28 | Dwarf_Addr bias; |
| 28 | }; | 29 | }; |
| @@ -77,6 +78,7 @@ struct probe_finder { | |||
| 77 | 78 | ||
| 78 | struct trace_event_finder { | 79 | struct trace_event_finder { |
| 79 | struct probe_finder pf; | 80 | struct probe_finder pf; |
| 81 | Dwfl_Module *mod; /* For solving symbols */ | ||
| 80 | struct probe_trace_event *tevs; /* Found trace events */ | 82 | struct probe_trace_event *tevs; /* Found trace events */ |
| 81 | int ntevs; /* Number of trace events */ | 83 | int ntevs; /* Number of trace events */ |
| 82 | int max_tevs; /* Max number of trace events */ | 84 | int max_tevs; /* Max number of trace events */ |
| @@ -84,6 +86,7 @@ struct trace_event_finder { | |||
| 84 | 86 | ||
| 85 | struct available_var_finder { | 87 | struct available_var_finder { |
| 86 | struct probe_finder pf; | 88 | struct probe_finder pf; |
| 89 | Dwfl_Module *mod; /* For solving symbols */ | ||
| 87 | struct variable_list *vls; /* Found variable lists */ | 90 | struct variable_list *vls; /* Found variable lists */ |
| 88 | int nvls; /* Number of variable lists */ | 91 | int nvls; /* Number of variable lists */ |
| 89 | int max_vls; /* Max no. of variable lists */ | 92 | int max_vls; /* Max no. of variable lists */ |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 71b5412bbbb9..2ac4bc92bb1f 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
| @@ -822,6 +822,8 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, | |||
| 822 | PyObject *pyevent = pyrf_event__new(event); | 822 | PyObject *pyevent = pyrf_event__new(event); |
| 823 | struct pyrf_event *pevent = (struct pyrf_event *)pyevent; | 823 | struct pyrf_event *pevent = (struct pyrf_event *)pyevent; |
| 824 | 824 | ||
| 825 | perf_evlist__mmap_consume(evlist, cpu); | ||
| 826 | |||
| 825 | if (pyevent == NULL) | 827 | if (pyevent == NULL) |
| 826 | return PyErr_NoMemory(); | 828 | return PyErr_NoMemory(); |
| 827 | 829 | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index a85e4ae5f3ac..c0c9795c4f02 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
| @@ -282,7 +282,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, | |||
| 282 | 282 | ||
| 283 | event = find_cache_event(evsel); | 283 | event = find_cache_event(evsel); |
| 284 | if (!event) | 284 | if (!event) |
| 285 | die("ug! no event found for type %" PRIu64, evsel->attr.config); | 285 | die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config); |
| 286 | 286 | ||
| 287 | pid = raw_field_value(event, "common_pid", data); | 287 | pid = raw_field_value(event, "common_pid", data); |
| 288 | 288 | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index cc75a3cef388..95d91a0b23af 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
| @@ -56,6 +56,17 @@ static void handler_call_die(const char *handler_name) | |||
| 56 | Py_FatalError("problem in Python trace event handler"); | 56 | Py_FatalError("problem in Python trace event handler"); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | /* | ||
| 60 | * Insert val into into the dictionary and decrement the reference counter. | ||
| 61 | * This is necessary for dictionaries since PyDict_SetItemString() does not | ||
| 62 | * steal a reference, as opposed to PyTuple_SetItem(). | ||
| 63 | */ | ||
| 64 | static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObject *val) | ||
| 65 | { | ||
| 66 | PyDict_SetItemString(dict, key, val); | ||
| 67 | Py_DECREF(val); | ||
| 68 | } | ||
| 69 | |||
| 59 | static void define_value(enum print_arg_type field_type, | 70 | static void define_value(enum print_arg_type field_type, |
| 60 | const char *ev_name, | 71 | const char *ev_name, |
| 61 | const char *field_name, | 72 | const char *field_name, |
| @@ -279,11 +290,11 @@ static void python_process_tracepoint(union perf_event *perf_event | |||
| 279 | PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); | 290 | PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); |
| 280 | PyTuple_SetItem(t, n++, PyString_FromString(comm)); | 291 | PyTuple_SetItem(t, n++, PyString_FromString(comm)); |
| 281 | } else { | 292 | } else { |
| 282 | PyDict_SetItemString(dict, "common_cpu", PyInt_FromLong(cpu)); | 293 | pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu)); |
| 283 | PyDict_SetItemString(dict, "common_s", PyInt_FromLong(s)); | 294 | pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s)); |
| 284 | PyDict_SetItemString(dict, "common_ns", PyInt_FromLong(ns)); | 295 | pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns)); |
| 285 | PyDict_SetItemString(dict, "common_pid", PyInt_FromLong(pid)); | 296 | pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid)); |
| 286 | PyDict_SetItemString(dict, "common_comm", PyString_FromString(comm)); | 297 | pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm)); |
| 287 | } | 298 | } |
| 288 | for (field = event->format.fields; field; field = field->next) { | 299 | for (field = event->format.fields; field; field = field->next) { |
| 289 | if (field->flags & FIELD_IS_STRING) { | 300 | if (field->flags & FIELD_IS_STRING) { |
| @@ -313,7 +324,7 @@ static void python_process_tracepoint(union perf_event *perf_event | |||
| 313 | if (handler) | 324 | if (handler) |
| 314 | PyTuple_SetItem(t, n++, obj); | 325 | PyTuple_SetItem(t, n++, obj); |
| 315 | else | 326 | else |
| 316 | PyDict_SetItemString(dict, field->name, obj); | 327 | pydict_set_item_string_decref(dict, field->name, obj); |
| 317 | 328 | ||
| 318 | } | 329 | } |
| 319 | if (!handler) | 330 | if (!handler) |
| @@ -370,21 +381,21 @@ static void python_process_general_event(union perf_event *perf_event | |||
| 370 | if (!handler || !PyCallable_Check(handler)) | 381 | if (!handler || !PyCallable_Check(handler)) |
| 371 | goto exit; | 382 | goto exit; |
| 372 | 383 | ||
| 373 | PyDict_SetItemString(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); | 384 | pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); |
| 374 | PyDict_SetItemString(dict, "attr", PyString_FromStringAndSize( | 385 | pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( |
| 375 | (const char *)&evsel->attr, sizeof(evsel->attr))); | 386 | (const char *)&evsel->attr, sizeof(evsel->attr))); |
| 376 | PyDict_SetItemString(dict, "sample", PyString_FromStringAndSize( | 387 | pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize( |
| 377 | (const char *)sample, sizeof(*sample))); | 388 | (const char *)sample, sizeof(*sample))); |
| 378 | PyDict_SetItemString(dict, "raw_buf", PyString_FromStringAndSize( | 389 | pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( |
| 379 | (const char *)sample->raw_data, sample->raw_size)); | 390 | (const char *)sample->raw_data, sample->raw_size)); |
| 380 | PyDict_SetItemString(dict, "comm", | 391 | pydict_set_item_string_decref(dict, "comm", |
| 381 | PyString_FromString(thread->comm)); | 392 | PyString_FromString(thread->comm)); |
| 382 | if (al->map) { | 393 | if (al->map) { |
| 383 | PyDict_SetItemString(dict, "dso", | 394 | pydict_set_item_string_decref(dict, "dso", |
| 384 | PyString_FromString(al->map->dso->name)); | 395 | PyString_FromString(al->map->dso->name)); |
| 385 | } | 396 | } |
| 386 | if (al->sym) { | 397 | if (al->sym) { |
| 387 | PyDict_SetItemString(dict, "symbol", | 398 | pydict_set_item_string_decref(dict, "symbol", |
| 388 | PyString_FromString(al->sym->name)); | 399 | PyString_FromString(al->sym->name)); |
| 389 | } | 400 | } |
| 390 | 401 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 51f5edf2a6d0..568b750c01f6 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -256,6 +256,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
| 256 | tool->sample = process_event_sample_stub; | 256 | tool->sample = process_event_sample_stub; |
| 257 | if (tool->mmap == NULL) | 257 | if (tool->mmap == NULL) |
| 258 | tool->mmap = process_event_stub; | 258 | tool->mmap = process_event_stub; |
| 259 | if (tool->mmap2 == NULL) | ||
| 260 | tool->mmap2 = process_event_stub; | ||
| 259 | if (tool->comm == NULL) | 261 | if (tool->comm == NULL) |
| 260 | tool->comm = process_event_stub; | 262 | tool->comm = process_event_stub; |
| 261 | if (tool->fork == NULL) | 263 | if (tool->fork == NULL) |
| @@ -531,6 +533,9 @@ static int flush_sample_queue(struct perf_session *s, | |||
| 531 | return 0; | 533 | return 0; |
| 532 | 534 | ||
| 533 | list_for_each_entry_safe(iter, tmp, head, list) { | 535 | list_for_each_entry_safe(iter, tmp, head, list) { |
| 536 | if (session_done()) | ||
| 537 | return 0; | ||
| 538 | |||
| 534 | if (iter->timestamp > limit) | 539 | if (iter->timestamp > limit) |
| 535 | break; | 540 | break; |
| 536 | 541 | ||
| @@ -1160,7 +1165,6 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
| 1160 | } | 1165 | } |
| 1161 | } | 1166 | } |
| 1162 | 1167 | ||
| 1163 | #define session_done() (*(volatile int *)(&session_done)) | ||
| 1164 | volatile int session_done; | 1168 | volatile int session_done; |
| 1165 | 1169 | ||
| 1166 | static int __perf_session__process_pipe_events(struct perf_session *self, | 1170 | static int __perf_session__process_pipe_events(struct perf_session *self, |
| @@ -1308,7 +1312,7 @@ int __perf_session__process_events(struct perf_session *session, | |||
| 1308 | file_offset = page_offset; | 1312 | file_offset = page_offset; |
| 1309 | head = data_offset - page_offset; | 1313 | head = data_offset - page_offset; |
| 1310 | 1314 | ||
| 1311 | if (data_offset + data_size < file_size) | 1315 | if (data_size && (data_offset + data_size < file_size)) |
| 1312 | file_size = data_offset + data_size; | 1316 | file_size = data_offset + data_size; |
| 1313 | 1317 | ||
| 1314 | progress_next = file_size / 16; | 1318 | progress_next = file_size / 16; |
| @@ -1372,10 +1376,13 @@ more: | |||
| 1372 | "Processing events..."); | 1376 | "Processing events..."); |
| 1373 | } | 1377 | } |
| 1374 | 1378 | ||
| 1379 | err = 0; | ||
| 1380 | if (session_done()) | ||
| 1381 | goto out_err; | ||
| 1382 | |||
| 1375 | if (file_pos < file_size) | 1383 | if (file_pos < file_size) |
| 1376 | goto more; | 1384 | goto more; |
| 1377 | 1385 | ||
| 1378 | err = 0; | ||
| 1379 | /* do the final flush for ordered samples */ | 1386 | /* do the final flush for ordered samples */ |
| 1380 | session->ordered_samples.next_flush = ULLONG_MAX; | 1387 | session->ordered_samples.next_flush = ULLONG_MAX; |
| 1381 | err = flush_sample_queue(session, tool); | 1388 | err = flush_sample_queue(session, tool); |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 3aa75fb2225f..04bf7373a7e5 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
| @@ -124,4 +124,8 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session, | |||
| 124 | 124 | ||
| 125 | #define perf_session__set_tracepoints_handlers(session, array) \ | 125 | #define perf_session__set_tracepoints_handlers(session, array) \ |
| 126 | __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array)) | 126 | __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array)) |
| 127 | |||
| 128 | extern volatile int session_done; | ||
| 129 | |||
| 130 | #define session_done() (*(volatile int *)(&session_done)) | ||
| 127 | #endif /* __PERF_SESSION_H */ | 131 | #endif /* __PERF_SESSION_H */ |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index a7b9ab557380..a9c829be5216 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
| @@ -8,6 +8,22 @@ | |||
| 8 | #include "symbol.h" | 8 | #include "symbol.h" |
| 9 | #include "debug.h" | 9 | #include "debug.h" |
| 10 | 10 | ||
| 11 | #ifndef HAVE_ELF_GETPHDRNUM | ||
| 12 | static int elf_getphdrnum(Elf *elf, size_t *dst) | ||
| 13 | { | ||
| 14 | GElf_Ehdr gehdr; | ||
| 15 | GElf_Ehdr *ehdr; | ||
| 16 | |||
| 17 | ehdr = gelf_getehdr(elf, &gehdr); | ||
| 18 | if (!ehdr) | ||
| 19 | return -1; | ||
| 20 | |||
| 21 | *dst = ehdr->e_phnum; | ||
| 22 | |||
| 23 | return 0; | ||
| 24 | } | ||
| 25 | #endif | ||
| 26 | |||
| 11 | #ifndef NT_GNU_BUILD_ID | 27 | #ifndef NT_GNU_BUILD_ID |
| 12 | #define NT_GNU_BUILD_ID 3 | 28 | #define NT_GNU_BUILD_ID 3 |
| 13 | #endif | 29 | #endif |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index fe7a27d67d2b..e9e1c03f927d 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
| @@ -186,7 +186,7 @@ void parse_proc_kallsyms(struct pevent *pevent, | |||
| 186 | char *next = NULL; | 186 | char *next = NULL; |
| 187 | char *addr_str; | 187 | char *addr_str; |
| 188 | char *mod; | 188 | char *mod; |
| 189 | char *fmt; | 189 | char *fmt = NULL; |
| 190 | 190 | ||
| 191 | line = strtok_r(file, "\n", &next); | 191 | line = strtok_r(file, "\n", &next); |
| 192 | while (line) { | 192 | while (line) { |
