diff options
author | Ingo Molnar <mingo@kernel.org> | 2018-04-04 01:23:52 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2018-04-04 01:23:52 -0400 |
commit | b89e7914f0291bbb58f6a1f024923ceffcde4fc7 (patch) | |
tree | 0b1074a79ae2d1b0d98f80e1d1d617fa7c93ec6f /tools | |
parent | 642e7fd23353e22290e3d51719fcb658dc252342 (diff) | |
parent | 51125a29a395048fdb3429b8c4ca0ada57097744 (diff) |
Merge tag 'perf-core-for-mingo-4.17-20180403' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
- Show only failing syscalls with 'perf trace --failure' (Arnaldo Carvalho de Melo)
e.g: See what 'openat' syscalls are failing:
# perf trace --failure -e openat
762.323 ( 0.007 ms): VideoCapture/4566 openat(dfd: CWD, filename: /dev/video2) = -1 ENOENT No such file or directory
<SNIP N /dev/videoN open attempts... sigh, where is that improvised camera lid?!? >
790.228 ( 0.008 ms): VideoCapture/4566 openat(dfd: CWD, filename: /dev/video63) = -1 ENOENT No such file or directory
^C#
- Show information about the event (freq, nr_samples, total period/nr_events) in
the annotate --tui and --stdio2 'perf annotate' output, similar to the
first line in the 'perf report --tui', but just for the samples for a
the annotated symbol (Arnaldo Carvalho de Melo)
- Introduce 'perf version --build-options' to show what features were
linked, aliased as well as a shorter 'perf -vv' (Jin Yao)
- Add a "dso_size" sort order (Kim Phillips)
- Remove redundant ')' in the tracepoint output in 'perf trace' (Changbin Du)
- Synchronize x86's cpufeatures.h, no effect on toolss (Arnaldo Carvalho de Melo)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/arch/x86/include/asm/cpufeatures.h | 2 | ||||
-rw-r--r-- | tools/include/tools/config.h | 34 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-report.txt | 1 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-trace.txt | 3 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-version.txt | 24 | ||||
-rw-r--r-- | tools/perf/Makefile.config | 8 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 11 | ||||
-rw-r--r-- | tools/perf/builtin-version.c | 82 | ||||
-rw-r--r-- | tools/perf/perf.c | 6 | ||||
-rw-r--r-- | tools/perf/perf.h | 1 | ||||
-rw-r--r-- | tools/perf/ui/browser.c | 8 | ||||
-rw-r--r-- | tools/perf/ui/browser.h | 2 | ||||
-rw-r--r-- | tools/perf/ui/browsers/annotate.c | 31 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 125 | ||||
-rw-r--r-- | tools/perf/util/annotate.c | 48 | ||||
-rw-r--r-- | tools/perf/util/annotate.h | 12 | ||||
-rw-r--r-- | tools/perf/util/dwarf-aux.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 81 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 7 | ||||
-rw-r--r-- | tools/perf/util/map.h | 4 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 41 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 1 |
22 files changed, 418 insertions, 116 deletions
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index f41079da38c5..d554c11e01ff 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h | |||
@@ -316,6 +316,7 @@ | |||
316 | #define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ | 316 | #define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ |
317 | #define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ | 317 | #define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ |
318 | #define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ | 318 | #define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ |
319 | #define X86_FEATURE_TME (16*32+13) /* Intel Total Memory Encryption */ | ||
319 | #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ | 320 | #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ |
320 | #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ | 321 | #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ |
321 | #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ | 322 | #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ |
@@ -328,6 +329,7 @@ | |||
328 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ | 329 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ |
329 | #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ | 330 | #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ |
330 | #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ | 331 | #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ |
332 | #define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ | ||
331 | #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ | 333 | #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ |
332 | #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ | 334 | #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ |
333 | #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ | 335 | #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ |
diff --git a/tools/include/tools/config.h b/tools/include/tools/config.h new file mode 100644 index 000000000000..08ade7df8132 --- /dev/null +++ b/tools/include/tools/config.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #ifndef _TOOLS_CONFIG_H | ||
3 | #define _TOOLS_CONFIG_H | ||
4 | |||
5 | /* Subset of include/linux/kconfig.h */ | ||
6 | |||
7 | #define __ARG_PLACEHOLDER_1 0, | ||
8 | #define __take_second_arg(__ignored, val, ...) val | ||
9 | |||
10 | /* | ||
11 | * Helper macros to use CONFIG_ options in C/CPP expressions. Note that | ||
12 | * these only work with boolean and tristate options. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * Getting something that works in C and CPP for an arg that may or may | ||
17 | * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1" | ||
18 | * we match on the placeholder define, insert the "0," for arg1 and generate | ||
19 | * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one). | ||
20 | * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when | ||
21 | * the last step cherry picks the 2nd arg, we get a zero. | ||
22 | */ | ||
23 | #define __is_defined(x) ___is_defined(x) | ||
24 | #define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val) | ||
25 | #define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0) | ||
26 | |||
27 | /* | ||
28 | * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0 | ||
29 | * otherwise. For boolean options, this is equivalent to | ||
30 | * IS_ENABLED(CONFIG_FOO). | ||
31 | */ | ||
32 | #define IS_BUILTIN(option) __is_defined(option) | ||
33 | |||
34 | #endif /* _TOOLS_CONFIG_H */ | ||
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index e1a660e60849..917e36fde6d8 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -80,6 +80,7 @@ OPTIONS | |||
80 | - comm: command (name) of the task which can be read via /proc/<pid>/comm | 80 | - comm: command (name) of the task which can be read via /proc/<pid>/comm |
81 | - pid: command and tid of the task | 81 | - pid: command and tid of the task |
82 | - dso: name of library or module executed at the time of sample | 82 | - dso: name of library or module executed at the time of sample |
83 | - dso_size: size of library or module executed at the time of sample | ||
83 | - symbol: name of function executed at the time of sample | 84 | - symbol: name of function executed at the time of sample |
84 | - symbol_size: size of function executed at the time of sample | 85 | - symbol_size: size of function executed at the time of sample |
85 | - parent: name of function matched to the parent regex filter. Unmatched | 86 | - parent: name of function matched to the parent regex filter. Unmatched |
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 5a7035c5c523..115db9e06ecd 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -117,6 +117,9 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. | |||
117 | --sched:: | 117 | --sched:: |
118 | Accrue thread runtime and provide a summary at the end of the session. | 118 | Accrue thread runtime and provide a summary at the end of the session. |
119 | 119 | ||
120 | --failure:: | ||
121 | Show only syscalls that failed, i.e. that returned < 0. | ||
122 | |||
120 | -i:: | 123 | -i:: |
121 | --input:: | 124 | --input:: |
122 | Process events from a given perf data file. | 125 | Process events from a given perf data file. |
diff --git a/tools/perf/Documentation/perf-version.txt b/tools/perf/Documentation/perf-version.txt new file mode 100644 index 000000000000..e207b7cfca26 --- /dev/null +++ b/tools/perf/Documentation/perf-version.txt | |||
@@ -0,0 +1,24 @@ | |||
1 | perf-version(1) | ||
2 | =============== | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | perf-version - display the version of perf binary | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | 'perf version' [--build-options] | ||
11 | |||
12 | DESCRIPTION | ||
13 | ----------- | ||
14 | With no options given, the 'perf version' prints the perf version | ||
15 | on the standard output. | ||
16 | |||
17 | If the option '--build-options' is given, then the status of | ||
18 | compiled-in libraries are printed on the standard output. | ||
19 | |||
20 | OPTIONS | ||
21 | ------- | ||
22 | --build-options:: | ||
23 | Prints the status of compiled-in libraries on the | ||
24 | standard output. | ||
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 98ff73648b51..c7abd83a8e19 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config | |||
@@ -346,12 +346,16 @@ else | |||
346 | ifneq ($(feature-dwarf_getlocations), 1) | 346 | ifneq ($(feature-dwarf_getlocations), 1) |
347 | msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157); | 347 | msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157); |
348 | else | 348 | else |
349 | CFLAGS += -DHAVE_DWARF_GETLOCATIONS | 349 | CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT |
350 | endif # dwarf_getlocations | 350 | endif # dwarf_getlocations |
351 | endif # Dwarf support | 351 | endif # Dwarf support |
352 | endif # libelf support | 352 | endif # libelf support |
353 | endif # NO_LIBELF | 353 | endif # NO_LIBELF |
354 | 354 | ||
355 | ifeq ($(feature-glibc), 1) | ||
356 | CFLAGS += -DHAVE_GLIBC_SUPPORT | ||
357 | endif | ||
358 | |||
355 | ifdef NO_DWARF | 359 | ifdef NO_DWARF |
356 | NO_LIBDW_DWARF_UNWIND := 1 | 360 | NO_LIBDW_DWARF_UNWIND := 1 |
357 | endif | 361 | endif |
@@ -635,6 +639,7 @@ else | |||
635 | else | 639 | else |
636 | LDFLAGS += $(PERL_EMBED_LDFLAGS) | 640 | LDFLAGS += $(PERL_EMBED_LDFLAGS) |
637 | EXTLIBS += $(PERL_EMBED_LIBADD) | 641 | EXTLIBS += $(PERL_EMBED_LIBADD) |
642 | CFLAGS += -DHAVE_LIBPERL_SUPPORT | ||
638 | $(call detected,CONFIG_LIBPERL) | 643 | $(call detected,CONFIG_LIBPERL) |
639 | endif | 644 | endif |
640 | endif | 645 | endif |
@@ -671,6 +676,7 @@ else | |||
671 | LDFLAGS += $(PYTHON_EMBED_LDFLAGS) | 676 | LDFLAGS += $(PYTHON_EMBED_LDFLAGS) |
672 | EXTLIBS += $(PYTHON_EMBED_LIBADD) | 677 | EXTLIBS += $(PYTHON_EMBED_LIBADD) |
673 | LANG_BINDINGS += $(obj-perf)python/perf.so | 678 | LANG_BINDINGS += $(obj-perf)python/perf.so |
679 | CFLAGS += -DHAVE_LIBPYTHON_SUPPORT | ||
674 | $(call detected,CONFIG_LIBPYTHON) | 680 | $(call detected,CONFIG_LIBPYTHON) |
675 | endif | 681 | endif |
676 | endif | 682 | endif |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 87b95c9410b4..3ad17ee89403 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -112,6 +112,7 @@ struct trace { | |||
112 | bool multiple_threads; | 112 | bool multiple_threads; |
113 | bool summary; | 113 | bool summary; |
114 | bool summary_only; | 114 | bool summary_only; |
115 | bool failure_only; | ||
115 | bool show_comm; | 116 | bool show_comm; |
116 | bool print_sample; | 117 | bool print_sample; |
117 | bool show_tool_stats; | 118 | bool show_tool_stats; |
@@ -1565,7 +1566,7 @@ static int trace__printf_interrupted_entry(struct trace *trace) | |||
1565 | struct thread_trace *ttrace; | 1566 | struct thread_trace *ttrace; |
1566 | size_t printed; | 1567 | size_t printed; |
1567 | 1568 | ||
1568 | if (trace->current == NULL) | 1569 | if (trace->failure_only || trace->current == NULL) |
1569 | return 0; | 1570 | return 0; |
1570 | 1571 | ||
1571 | ttrace = thread__priv(trace->current); | 1572 | ttrace = thread__priv(trace->current); |
@@ -1638,7 +1639,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | |||
1638 | args, trace, thread); | 1639 | args, trace, thread); |
1639 | 1640 | ||
1640 | if (sc->is_exit) { | 1641 | if (sc->is_exit) { |
1641 | if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { | 1642 | if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) { |
1642 | trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output); | 1643 | trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output); |
1643 | fprintf(trace->output, "%-70s)\n", ttrace->entry_str); | 1644 | fprintf(trace->output, "%-70s)\n", ttrace->entry_str); |
1644 | } | 1645 | } |
@@ -1742,7 +1743,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
1742 | } | 1743 | } |
1743 | } | 1744 | } |
1744 | 1745 | ||
1745 | if (trace->summary_only) | 1746 | if (trace->summary_only || (ret >= 0 && trace->failure_only)) |
1746 | goto out; | 1747 | goto out; |
1747 | 1748 | ||
1748 | trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output); | 1749 | trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output); |
@@ -1961,7 +1962,7 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
1961 | trace->output); | 1962 | trace->output); |
1962 | } | 1963 | } |
1963 | 1964 | ||
1964 | fprintf(trace->output, ")\n"); | 1965 | fprintf(trace->output, "\n"); |
1965 | 1966 | ||
1966 | if (callchain_ret > 0) | 1967 | if (callchain_ret > 0) |
1967 | trace__fprintf_callchain(trace, sample); | 1968 | trace__fprintf_callchain(trace, sample); |
@@ -3087,6 +3088,8 @@ int cmd_trace(int argc, const char **argv) | |||
3087 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | 3088 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), |
3088 | OPT_BOOLEAN('T', "time", &trace.full_time, | 3089 | OPT_BOOLEAN('T', "time", &trace.full_time, |
3089 | "Show full timestamp, not time relative to first start"), | 3090 | "Show full timestamp, not time relative to first start"), |
3091 | OPT_BOOLEAN(0, "failure", &trace.failure_only, | ||
3092 | "Show only syscalls that failed"), | ||
3090 | OPT_BOOLEAN('s', "summary", &trace.summary_only, | 3093 | OPT_BOOLEAN('s', "summary", &trace.summary_only, |
3091 | "Show only syscall summary with statistics"), | 3094 | "Show only syscall summary with statistics"), |
3092 | OPT_BOOLEAN('S', "with-summary", &trace.summary, | 3095 | OPT_BOOLEAN('S', "with-summary", &trace.summary, |
diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c index 37019c5d675f..2abe3910d6b6 100644 --- a/tools/perf/builtin-version.c +++ b/tools/perf/builtin-version.c | |||
@@ -1,11 +1,91 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include "builtin.h" | 2 | #include "builtin.h" |
3 | #include "perf.h" | 3 | #include "perf.h" |
4 | #include "color.h" | ||
4 | #include <linux/compiler.h> | 5 | #include <linux/compiler.h> |
6 | #include <tools/config.h> | ||
5 | #include <stdio.h> | 7 | #include <stdio.h> |
8 | #include <string.h> | ||
9 | #include <subcmd/parse-options.h> | ||
6 | 10 | ||
7 | int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused) | 11 | int version_verbose; |
12 | |||
13 | struct version { | ||
14 | bool build_options; | ||
15 | }; | ||
16 | |||
17 | static struct version version; | ||
18 | |||
19 | static struct option version_options[] = { | ||
20 | OPT_BOOLEAN(0, "build-options", &version.build_options, | ||
21 | "display the build options"), | ||
22 | }; | ||
23 | |||
24 | static const char * const version_usage[] = { | ||
25 | "perf version [<options>]", | ||
26 | NULL | ||
27 | }; | ||
28 | |||
29 | static void on_off_print(const char *status) | ||
30 | { | ||
31 | printf("[ "); | ||
32 | |||
33 | if (!strcmp(status, "OFF")) | ||
34 | color_fprintf(stdout, PERF_COLOR_RED, "%-3s", status); | ||
35 | else | ||
36 | color_fprintf(stdout, PERF_COLOR_GREEN, "%-3s", status); | ||
37 | |||
38 | printf(" ]"); | ||
39 | } | ||
40 | |||
41 | static void status_print(const char *name, const char *macro, | ||
42 | const char *status) | ||
8 | { | 43 | { |
44 | printf("%22s: ", name); | ||
45 | on_off_print(status); | ||
46 | printf(" # %s\n", macro); | ||
47 | } | ||
48 | |||
49 | #define STATUS(__d, __m) \ | ||
50 | do { \ | ||
51 | if (IS_BUILTIN(__d)) \ | ||
52 | status_print(#__m, #__d, "on"); \ | ||
53 | else \ | ||
54 | status_print(#__m, #__d, "OFF"); \ | ||
55 | } while (0) | ||
56 | |||
57 | static void library_status(void) | ||
58 | { | ||
59 | STATUS(HAVE_DWARF_SUPPORT, dwarf); | ||
60 | STATUS(HAVE_DWARF_GETLOCATIONS_SUPPORT, dwarf_getlocations); | ||
61 | STATUS(HAVE_GLIBC_SUPPORT, glibc); | ||
62 | STATUS(HAVE_GTK2_SUPPORT, gtk2); | ||
63 | STATUS(HAVE_LIBAUDIT_SUPPORT, libaudit); | ||
64 | STATUS(HAVE_LIBBFD_SUPPORT, libbfd); | ||
65 | STATUS(HAVE_LIBELF_SUPPORT, libelf); | ||
66 | STATUS(HAVE_LIBNUMA_SUPPORT, libnuma); | ||
67 | STATUS(HAVE_LIBNUMA_SUPPORT, numa_num_possible_cpus); | ||
68 | STATUS(HAVE_LIBPERL_SUPPORT, libperl); | ||
69 | STATUS(HAVE_LIBPYTHON_SUPPORT, libpython); | ||
70 | STATUS(HAVE_SLANG_SUPPORT, libslang); | ||
71 | STATUS(HAVE_LIBCRYPTO_SUPPORT, libcrypto); | ||
72 | STATUS(HAVE_LIBUNWIND_SUPPORT, libunwind); | ||
73 | STATUS(HAVE_DWARF_SUPPORT, libdw-dwarf-unwind); | ||
74 | STATUS(HAVE_ZLIB_SUPPORT, zlib); | ||
75 | STATUS(HAVE_LZMA_SUPPORT, lzma); | ||
76 | STATUS(HAVE_AUXTRACE_SUPPORT, get_cpuid); | ||
77 | STATUS(HAVE_LIBBPF_SUPPORT, bpf); | ||
78 | } | ||
79 | |||
80 | int cmd_version(int argc, const char **argv) | ||
81 | { | ||
82 | argc = parse_options(argc, argv, version_options, version_usage, | ||
83 | PARSE_OPT_STOP_AT_NON_OPTION); | ||
84 | |||
9 | printf("perf version %s\n", perf_version_string); | 85 | printf("perf version %s\n", perf_version_string); |
86 | |||
87 | if (version.build_options || version_verbose == 1) | ||
88 | library_status(); | ||
89 | |||
10 | return 0; | 90 | return 0; |
11 | } | 91 | } |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 1b3fc8ec0fa2..1659029d03fc 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -190,6 +190,12 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) | |||
190 | break; | 190 | break; |
191 | } | 191 | } |
192 | 192 | ||
193 | if (!strcmp(cmd, "-vv")) { | ||
194 | (*argv)[0] = "version"; | ||
195 | version_verbose = 1; | ||
196 | break; | ||
197 | } | ||
198 | |||
193 | /* | 199 | /* |
194 | * Check remaining flags. | 200 | * Check remaining flags. |
195 | */ | 201 | */ |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 8fec1abd0f1f..a1a97956136f 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -84,6 +84,7 @@ struct record_opts { | |||
84 | struct option; | 84 | struct option; |
85 | extern const char * const *record_usage; | 85 | extern const char * const *record_usage; |
86 | extern struct option *record_options; | 86 | extern struct option *record_options; |
87 | extern int version_verbose; | ||
87 | 88 | ||
88 | int record__parse_freq(const struct option *opt, const char *str, int unset); | 89 | int record__parse_freq(const struct option *opt, const char *str, int unset); |
89 | #endif | 90 | #endif |
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index 9f6ce29b83b4..d7bb2591838e 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c | |||
@@ -45,11 +45,16 @@ void ui_browser__set_percent_color(struct ui_browser *browser, | |||
45 | ui_browser__set_color(browser, color); | 45 | ui_browser__set_color(browser, color); |
46 | } | 46 | } |
47 | 47 | ||
48 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x) | 48 | void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x) |
49 | { | 49 | { |
50 | SLsmg_gotorc(browser->y + y, browser->x + x); | 50 | SLsmg_gotorc(browser->y + y, browser->x + x); |
51 | } | 51 | } |
52 | 52 | ||
53 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x) | ||
54 | { | ||
55 | SLsmg_gotorc(browser->y + y + browser->extra_title_lines, browser->x + x); | ||
56 | } | ||
57 | |||
53 | void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg, | 58 | void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg, |
54 | unsigned int width) | 59 | unsigned int width) |
55 | { | 60 | { |
@@ -191,6 +196,7 @@ void ui_browser__refresh_dimensions(struct ui_browser *browser) | |||
191 | { | 196 | { |
192 | browser->width = SLtt_Screen_Cols - 1; | 197 | browser->width = SLtt_Screen_Cols - 1; |
193 | browser->height = browser->rows = SLtt_Screen_Rows - 2; | 198 | browser->height = browser->rows = SLtt_Screen_Rows - 2; |
199 | browser->rows -= browser->extra_title_lines; | ||
194 | browser->y = 1; | 200 | browser->y = 1; |
195 | browser->x = 0; | 201 | browser->x = 0; |
196 | } | 202 | } |
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index 70057178ee34..aa5932e1d62e 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h | |||
@@ -17,6 +17,7 @@ struct ui_browser { | |||
17 | u64 index, top_idx; | 17 | u64 index, top_idx; |
18 | void *top, *entries; | 18 | void *top, *entries; |
19 | u16 y, x, width, height, rows, columns, horiz_scroll; | 19 | u16 y, x, width, height, rows, columns, horiz_scroll; |
20 | u8 extra_title_lines; | ||
20 | int current_color; | 21 | int current_color; |
21 | void *priv; | 22 | void *priv; |
22 | const char *title; | 23 | const char *title; |
@@ -38,6 +39,7 @@ bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row); | |||
38 | void ui_browser__refresh_dimensions(struct ui_browser *browser); | 39 | void ui_browser__refresh_dimensions(struct ui_browser *browser); |
39 | void ui_browser__reset_index(struct ui_browser *browser); | 40 | void ui_browser__reset_index(struct ui_browser *browser); |
40 | 41 | ||
42 | void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x); | ||
41 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x); | 43 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x); |
42 | void ui_browser__write_nstring(struct ui_browser *browser, const char *msg, | 44 | void ui_browser__write_nstring(struct ui_browser *browser, const char *msg, |
43 | unsigned int width); | 45 | unsigned int width); |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index c02fb437ac8e..78bcd220f1b6 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -592,21 +592,40 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, | |||
592 | return __annotate_browser__search_reverse(browser); | 592 | return __annotate_browser__search_reverse(browser); |
593 | } | 593 | } |
594 | 594 | ||
595 | static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) | ||
596 | { | ||
597 | struct map_symbol *ms = browser->priv; | ||
598 | struct symbol *sym = ms->sym; | ||
599 | char symbol_dso[SYM_TITLE_MAX_SIZE]; | ||
600 | |||
601 | if (ui_browser__show(browser, title, help) < 0) | ||
602 | return -1; | ||
603 | |||
604 | sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso)); | ||
605 | |||
606 | ui_browser__gotorc_title(browser, 0, 0); | ||
607 | ui_browser__set_color(browser, HE_COLORSET_ROOT); | ||
608 | ui_browser__write_nstring(browser, symbol_dso, browser->width + 1); | ||
609 | return 0; | ||
610 | } | ||
611 | |||
595 | static int annotate_browser__run(struct annotate_browser *browser, | 612 | static int annotate_browser__run(struct annotate_browser *browser, |
596 | struct perf_evsel *evsel, | 613 | struct perf_evsel *evsel, |
597 | struct hist_browser_timer *hbt) | 614 | struct hist_browser_timer *hbt) |
598 | { | 615 | { |
599 | struct rb_node *nd = NULL; | 616 | struct rb_node *nd = NULL; |
617 | struct hists *hists = evsel__hists(evsel); | ||
600 | struct map_symbol *ms = browser->b.priv; | 618 | struct map_symbol *ms = browser->b.priv; |
601 | struct symbol *sym = ms->sym; | 619 | struct symbol *sym = ms->sym; |
602 | struct annotation *notes = symbol__annotation(ms->sym); | 620 | struct annotation *notes = symbol__annotation(ms->sym); |
603 | const char *help = "Press 'h' for help on key bindings"; | 621 | const char *help = "Press 'h' for help on key bindings"; |
604 | int delay_secs = hbt ? hbt->refresh : 0; | 622 | int delay_secs = hbt ? hbt->refresh : 0; |
623 | char title[256]; | ||
605 | int key; | 624 | int key; |
606 | char title[SYM_TITLE_MAX_SIZE]; | ||
607 | 625 | ||
608 | sym_title(sym, ms->map, title, sizeof(title)); | 626 | annotation__scnprintf_samples_period(notes, title, sizeof(title), evsel); |
609 | if (ui_browser__show(&browser->b, title, help) < 0) | 627 | |
628 | if (annotate_browser__show(&browser->b, title, help) < 0) | ||
610 | return -1; | 629 | return -1; |
611 | 630 | ||
612 | annotate_browser__calc_percent(browser, evsel); | 631 | annotate_browser__calc_percent(browser, evsel); |
@@ -637,8 +656,11 @@ static int annotate_browser__run(struct annotate_browser *browser, | |||
637 | if (hbt) | 656 | if (hbt) |
638 | hbt->timer(hbt->arg); | 657 | hbt->timer(hbt->arg); |
639 | 658 | ||
640 | if (delay_secs != 0) | 659 | if (delay_secs != 0) { |
641 | symbol__annotate_decay_histogram(sym, evsel->idx); | 660 | symbol__annotate_decay_histogram(sym, evsel->idx); |
661 | hists__scnprintf_title(hists, title, sizeof(title)); | ||
662 | annotate_browser__show(&browser->b, title, help); | ||
663 | } | ||
642 | continue; | 664 | continue; |
643 | case K_TAB: | 665 | case K_TAB: |
644 | if (nd != NULL) { | 666 | if (nd != NULL) { |
@@ -812,6 +834,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, | |||
812 | .seek = ui_browser__list_head_seek, | 834 | .seek = ui_browser__list_head_seek, |
813 | .write = annotate_browser__write, | 835 | .write = annotate_browser__write, |
814 | .filter = disasm_line__filter, | 836 | .filter = disasm_line__filter, |
837 | .extra_title_lines = 1, /* for hists__scnprintf_title() */ | ||
815 | .priv = &ms, | 838 | .priv = &ms, |
816 | .use_navkeypressed = true, | 839 | .use_navkeypressed = true, |
817 | }, | 840 | }, |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 8b4e82548f8e..b06afb8f51fb 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -32,8 +32,7 @@ | |||
32 | 32 | ||
33 | extern void hist_browser__init_hpp(void); | 33 | extern void hist_browser__init_hpp(void); |
34 | 34 | ||
35 | static int perf_evsel_browser_title(struct hist_browser *browser, | 35 | static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size); |
36 | char *bf, size_t size); | ||
37 | static void hist_browser__update_nr_entries(struct hist_browser *hb); | 36 | static void hist_browser__update_nr_entries(struct hist_browser *hb); |
38 | 37 | ||
39 | static struct rb_node *hists__filter_entries(struct rb_node *nd, | 38 | static struct rb_node *hists__filter_entries(struct rb_node *nd, |
@@ -62,6 +61,15 @@ static int hist_browser__get_folding(struct hist_browser *browser) | |||
62 | return unfolded_rows; | 61 | return unfolded_rows; |
63 | } | 62 | } |
64 | 63 | ||
64 | static void hist_browser__set_title_space(struct hist_browser *hb) | ||
65 | { | ||
66 | struct ui_browser *browser = &hb->b; | ||
67 | struct hists *hists = hb->hists; | ||
68 | struct perf_hpp_list *hpp_list = hists->hpp_list; | ||
69 | |||
70 | browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0; | ||
71 | } | ||
72 | |||
65 | static u32 hist_browser__nr_entries(struct hist_browser *hb) | 73 | static u32 hist_browser__nr_entries(struct hist_browser *hb) |
66 | { | 74 | { |
67 | u32 nr_entries; | 75 | u32 nr_entries; |
@@ -82,10 +90,16 @@ static void hist_browser__update_rows(struct hist_browser *hb) | |||
82 | struct ui_browser *browser = &hb->b; | 90 | struct ui_browser *browser = &hb->b; |
83 | struct hists *hists = hb->hists; | 91 | struct hists *hists = hb->hists; |
84 | struct perf_hpp_list *hpp_list = hists->hpp_list; | 92 | struct perf_hpp_list *hpp_list = hists->hpp_list; |
85 | u16 header_offset, index_row; | 93 | u16 index_row; |
86 | 94 | ||
87 | header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0; | 95 | if (!hb->show_headers) { |
88 | browser->rows = browser->height - header_offset; | 96 | browser->rows += browser->extra_title_lines; |
97 | browser->extra_title_lines = 0; | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | browser->extra_title_lines = hpp_list->nr_header_lines; | ||
102 | browser->rows -= browser->extra_title_lines; | ||
89 | /* | 103 | /* |
90 | * Verify if we were at the last line and that line isn't | 104 | * Verify if we were at the last line and that line isn't |
91 | * visibe because we now show the header line(s). | 105 | * visibe because we now show the header line(s). |
@@ -108,17 +122,6 @@ static void hist_browser__refresh_dimensions(struct ui_browser *browser) | |||
108 | * changeset. | 122 | * changeset. |
109 | */ | 123 | */ |
110 | ui_browser__refresh_dimensions(browser); | 124 | ui_browser__refresh_dimensions(browser); |
111 | hist_browser__update_rows(hb); | ||
112 | } | ||
113 | |||
114 | static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) | ||
115 | { | ||
116 | struct hists *hists = browser->hists; | ||
117 | struct perf_hpp_list *hpp_list = hists->hpp_list; | ||
118 | u16 header_offset; | ||
119 | |||
120 | header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0; | ||
121 | ui_browser__gotorc(&browser->b, row + header_offset, column); | ||
122 | } | 125 | } |
123 | 126 | ||
124 | static void hist_browser__reset(struct hist_browser *browser) | 127 | static void hist_browser__reset(struct hist_browser *browser) |
@@ -733,7 +736,7 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser, | |||
733 | } | 736 | } |
734 | 737 | ||
735 | ui_browser__set_color(&browser->b, color); | 738 | ui_browser__set_color(&browser->b, color); |
736 | hist_browser__gotorc(browser, row, 0); | 739 | ui_browser__gotorc(&browser->b, row, 0); |
737 | ui_browser__write_nstring(&browser->b, " ", offset); | 740 | ui_browser__write_nstring(&browser->b, " ", offset); |
738 | ui_browser__printf(&browser->b, "%c", folded_sign); | 741 | ui_browser__printf(&browser->b, "%c", folded_sign); |
739 | ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); | 742 | ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); |
@@ -1249,7 +1252,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
1249 | }; | 1252 | }; |
1250 | int column = 0; | 1253 | int column = 0; |
1251 | 1254 | ||
1252 | hist_browser__gotorc(browser, row, 0); | 1255 | ui_browser__gotorc(&browser->b, row, 0); |
1253 | 1256 | ||
1254 | hists__for_each_format(browser->hists, fmt) { | 1257 | hists__for_each_format(browser->hists, fmt) { |
1255 | char s[2048]; | 1258 | char s[2048]; |
@@ -1358,7 +1361,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, | |||
1358 | goto show_callchain; | 1361 | goto show_callchain; |
1359 | } | 1362 | } |
1360 | 1363 | ||
1361 | hist_browser__gotorc(browser, row, 0); | 1364 | ui_browser__gotorc(&browser->b, row, 0); |
1362 | 1365 | ||
1363 | if (current_entry && browser->b.navkeypressed) | 1366 | if (current_entry && browser->b.navkeypressed) |
1364 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); | 1367 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); |
@@ -1507,7 +1510,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser, | |||
1507 | browser->selection = NULL; | 1510 | browser->selection = NULL; |
1508 | } | 1511 | } |
1509 | 1512 | ||
1510 | hist_browser__gotorc(browser, row, 0); | 1513 | ui_browser__gotorc(&browser->b, row, 0); |
1511 | 1514 | ||
1512 | if (current_entry && browser->b.navkeypressed) | 1515 | if (current_entry && browser->b.navkeypressed) |
1513 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); | 1516 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); |
@@ -1713,7 +1716,7 @@ static void hists_browser__headers(struct hist_browser *browser) | |||
1713 | hists_browser__scnprintf_headers(browser, headers, | 1716 | hists_browser__scnprintf_headers(browser, headers, |
1714 | sizeof(headers), line); | 1717 | sizeof(headers), line); |
1715 | 1718 | ||
1716 | ui_browser__gotorc(&browser->b, line, 0); | 1719 | ui_browser__gotorc_title(&browser->b, line, 0); |
1717 | ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); | 1720 | ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); |
1718 | ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); | 1721 | ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); |
1719 | } | 1722 | } |
@@ -2143,6 +2146,7 @@ void hist_browser__init(struct hist_browser *browser, | |||
2143 | browser->b.seek = ui_browser__hists_seek; | 2146 | browser->b.seek = ui_browser__hists_seek; |
2144 | browser->b.use_navkeypressed = true; | 2147 | browser->b.use_navkeypressed = true; |
2145 | browser->show_headers = symbol_conf.show_hist_headers; | 2148 | browser->show_headers = symbol_conf.show_hist_headers; |
2149 | hist_browser__set_title_space(browser); | ||
2146 | 2150 | ||
2147 | if (symbol_conf.report_hierarchy) { | 2151 | if (symbol_conf.report_hierarchy) { |
2148 | struct perf_hpp_list_node *fmt_node; | 2152 | struct perf_hpp_list_node *fmt_node; |
@@ -2183,7 +2187,7 @@ perf_evsel_browser__new(struct perf_evsel *evsel, | |||
2183 | if (browser) { | 2187 | if (browser) { |
2184 | browser->hbt = hbt; | 2188 | browser->hbt = hbt; |
2185 | browser->env = env; | 2189 | browser->env = env; |
2186 | browser->title = perf_evsel_browser_title; | 2190 | browser->title = hists_browser__scnprintf_title; |
2187 | } | 2191 | } |
2188 | return browser; | 2192 | return browser; |
2189 | } | 2193 | } |
@@ -2209,84 +2213,11 @@ static inline bool is_report_browser(void *timer) | |||
2209 | return timer == NULL; | 2213 | return timer == NULL; |
2210 | } | 2214 | } |
2211 | 2215 | ||
2212 | static int perf_evsel_browser_title(struct hist_browser *browser, | 2216 | static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size) |
2213 | char *bf, size_t size) | ||
2214 | { | 2217 | { |
2215 | struct hist_browser_timer *hbt = browser->hbt; | 2218 | struct hist_browser_timer *hbt = browser->hbt; |
2216 | struct hists *hists = browser->hists; | 2219 | int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt)); |
2217 | char unit; | ||
2218 | int printed; | ||
2219 | const struct dso *dso = hists->dso_filter; | ||
2220 | const struct thread *thread = hists->thread_filter; | ||
2221 | int socket_id = hists->socket_filter; | ||
2222 | unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; | ||
2223 | u64 nr_events = hists->stats.total_period; | ||
2224 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
2225 | const char *ev_name = perf_evsel__name(evsel); | ||
2226 | char buf[512], sample_freq_str[64] = ""; | ||
2227 | size_t buflen = sizeof(buf); | ||
2228 | char ref[30] = " show reference callgraph, "; | ||
2229 | bool enable_ref = false; | ||
2230 | |||
2231 | if (symbol_conf.filter_relative) { | ||
2232 | nr_samples = hists->stats.nr_non_filtered_samples; | ||
2233 | nr_events = hists->stats.total_non_filtered_period; | ||
2234 | } | ||
2235 | 2220 | ||
2236 | if (perf_evsel__is_group_event(evsel)) { | ||
2237 | struct perf_evsel *pos; | ||
2238 | |||
2239 | perf_evsel__group_desc(evsel, buf, buflen); | ||
2240 | ev_name = buf; | ||
2241 | |||
2242 | for_each_group_member(pos, evsel) { | ||
2243 | struct hists *pos_hists = evsel__hists(pos); | ||
2244 | |||
2245 | if (symbol_conf.filter_relative) { | ||
2246 | nr_samples += pos_hists->stats.nr_non_filtered_samples; | ||
2247 | nr_events += pos_hists->stats.total_non_filtered_period; | ||
2248 | } else { | ||
2249 | nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; | ||
2250 | nr_events += pos_hists->stats.total_period; | ||
2251 | } | ||
2252 | } | ||
2253 | } | ||
2254 | |||
2255 | if (symbol_conf.show_ref_callgraph && | ||
2256 | strstr(ev_name, "call-graph=no")) | ||
2257 | enable_ref = true; | ||
2258 | |||
2259 | if (!is_report_browser(hbt)) | ||
2260 | scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | ||
2261 | |||
2262 | nr_samples = convert_unit(nr_samples, &unit); | ||
2263 | printed = scnprintf(bf, size, | ||
2264 | "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | ||
2265 | nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | ||
2266 | ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | ||
2267 | |||
2268 | |||
2269 | if (hists->uid_filter_str) | ||
2270 | printed += snprintf(bf + printed, size - printed, | ||
2271 | ", UID: %s", hists->uid_filter_str); | ||
2272 | if (thread) { | ||
2273 | if (hists__has(hists, thread)) { | ||
2274 | printed += scnprintf(bf + printed, size - printed, | ||
2275 | ", Thread: %s(%d)", | ||
2276 | (thread->comm_set ? thread__comm_str(thread) : ""), | ||
2277 | thread->tid); | ||
2278 | } else { | ||
2279 | printed += scnprintf(bf + printed, size - printed, | ||
2280 | ", Thread: %s", | ||
2281 | (thread->comm_set ? thread__comm_str(thread) : "")); | ||
2282 | } | ||
2283 | } | ||
2284 | if (dso) | ||
2285 | printed += scnprintf(bf + printed, size - printed, | ||
2286 | ", DSO: %s", dso->short_name); | ||
2287 | if (socket_id > -1) | ||
2288 | printed += scnprintf(bf + printed, size - printed, | ||
2289 | ", Processor Socket: %d", socket_id); | ||
2290 | if (!is_report_browser(hbt)) { | 2221 | if (!is_report_browser(hbt)) { |
2291 | struct perf_top *top = hbt->arg; | 2222 | struct perf_top *top = hbt->arg; |
2292 | 2223 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3a428d7c59b9..fffe16af9797 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "config.h" | 17 | #include "config.h" |
18 | #include "cache.h" | 18 | #include "cache.h" |
19 | #include "symbol.h" | 19 | #include "symbol.h" |
20 | #include "units.h" | ||
20 | #include "debug.h" | 21 | #include "debug.h" |
21 | #include "annotate.h" | 22 | #include "annotate.h" |
22 | #include "evsel.h" | 23 | #include "evsel.h" |
@@ -2324,7 +2325,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, | |||
2324 | struct dso *dso = map->dso; | 2325 | struct dso *dso = map->dso; |
2325 | struct rb_root source_line = RB_ROOT; | 2326 | struct rb_root source_line = RB_ROOT; |
2326 | struct annotation_options opts = annotation__default_options; | 2327 | struct annotation_options opts = annotation__default_options; |
2327 | const char *ev_name = perf_evsel__name(evsel); | 2328 | struct annotation *notes = symbol__annotation(sym); |
2328 | char buf[1024]; | 2329 | char buf[1024]; |
2329 | 2330 | ||
2330 | if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) | 2331 | if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) |
@@ -2336,12 +2337,8 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, | |||
2336 | print_summary(&source_line, dso->long_name); | 2337 | print_summary(&source_line, dso->long_name); |
2337 | } | 2338 | } |
2338 | 2339 | ||
2339 | if (perf_evsel__is_group_event(evsel)) { | 2340 | annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel); |
2340 | perf_evsel__group_desc(evsel, buf, sizeof(buf)); | 2341 | fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name); |
2341 | ev_name = buf; | ||
2342 | } | ||
2343 | |||
2344 | fprintf(stdout, "%s() %s\nEvent: %s\n\n", sym->name, dso->long_name, ev_name); | ||
2345 | symbol__annotate_fprintf2(sym, stdout); | 2342 | symbol__annotate_fprintf2(sym, stdout); |
2346 | 2343 | ||
2347 | annotated_source__purge(symbol__annotation(sym)->src); | 2344 | annotated_source__purge(symbol__annotation(sym)->src); |
@@ -2597,6 +2594,43 @@ out_free_offsets: | |||
2597 | return -1; | 2594 | return -1; |
2598 | } | 2595 | } |
2599 | 2596 | ||
2597 | int __annotation__scnprintf_samples_period(struct annotation *notes, | ||
2598 | char *bf, size_t size, | ||
2599 | struct perf_evsel *evsel, | ||
2600 | bool show_freq) | ||
2601 | { | ||
2602 | const char *ev_name = perf_evsel__name(evsel); | ||
2603 | char ref[30] = " show reference callgraph, "; | ||
2604 | char sample_freq_str[64] = ""; | ||
2605 | unsigned long nr_samples = 0; | ||
2606 | int nr_members = 1; | ||
2607 | bool enable_ref = false; | ||
2608 | u64 nr_events = 0; | ||
2609 | char unit; | ||
2610 | int i; | ||
2611 | |||
2612 | if (perf_evsel__is_group_event(evsel)) | ||
2613 | nr_members = evsel->nr_members; | ||
2614 | |||
2615 | for (i = 0; i < nr_members; i++) { | ||
2616 | struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i); | ||
2617 | |||
2618 | nr_samples += ah->nr_samples; | ||
2619 | nr_events += ah->period; | ||
2620 | } | ||
2621 | |||
2622 | if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no")) | ||
2623 | enable_ref = true; | ||
2624 | |||
2625 | if (show_freq) | ||
2626 | scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | ||
2627 | |||
2628 | nr_samples = convert_unit(nr_samples, &unit); | ||
2629 | return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | ||
2630 | nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | ||
2631 | ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | ||
2632 | } | ||
2633 | |||
2600 | #define ANNOTATION__CFG(n) \ | 2634 | #define ANNOTATION__CFG(n) \ |
2601 | { .name = #n, .value = &annotation__default_options.n, } | 2635 | { .name = #n, .value = &annotation__default_options.n, } |
2602 | 2636 | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index ff7e3df31efa..db8d09bea07e 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -151,6 +151,18 @@ double annotation_line__max_percent(struct annotation_line *al, struct annotatio | |||
151 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, | 151 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, |
152 | struct annotation_write_ops *ops); | 152 | struct annotation_write_ops *ops); |
153 | 153 | ||
154 | int __annotation__scnprintf_samples_period(struct annotation *notes, | ||
155 | char *bf, size_t size, | ||
156 | struct perf_evsel *evsel, | ||
157 | bool show_freq); | ||
158 | |||
159 | static inline int annotation__scnprintf_samples_period(struct annotation *notes, | ||
160 | char *bf, size_t size, | ||
161 | struct perf_evsel *evsel) | ||
162 | { | ||
163 | return __annotation__scnprintf_samples_period(notes, bf, size, evsel, true); | ||
164 | } | ||
165 | |||
154 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); | 166 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); |
155 | size_t disasm__fprintf(struct list_head *head, FILE *fp); | 167 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
156 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); | 168 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index f5acda13dcfa..7eb7de5aee44 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -979,7 +979,7 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) | |||
979 | return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); | 979 | return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); |
980 | } | 980 | } |
981 | 981 | ||
982 | #ifdef HAVE_DWARF_GETLOCATIONS | 982 | #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT |
983 | /** | 983 | /** |
984 | * die_get_var_innermost_scope - Get innermost scope range of given variable DIE | 984 | * die_get_var_innermost_scope - Get innermost scope range of given variable DIE |
985 | * @sp_die: a subprogram DIE | 985 | * @sp_die: a subprogram DIE |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 7d968892ee39..4d602fba40b2 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include "session.h" | 6 | #include "session.h" |
7 | #include "namespaces.h" | 7 | #include "namespaces.h" |
8 | #include "sort.h" | 8 | #include "sort.h" |
9 | #include "units.h" | ||
9 | #include "evlist.h" | 10 | #include "evlist.h" |
10 | #include "evsel.h" | 11 | #include "evsel.h" |
11 | #include "annotate.h" | 12 | #include "annotate.h" |
@@ -14,6 +15,7 @@ | |||
14 | #include "ui/progress.h" | 15 | #include "ui/progress.h" |
15 | #include <errno.h> | 16 | #include <errno.h> |
16 | #include <math.h> | 17 | #include <math.h> |
18 | #include <inttypes.h> | ||
17 | #include <sys/param.h> | 19 | #include <sys/param.h> |
18 | 20 | ||
19 | static bool hists__filter_entry_by_dso(struct hists *hists, | 21 | static bool hists__filter_entry_by_dso(struct hists *hists, |
@@ -2454,6 +2456,85 @@ u64 hists__total_period(struct hists *hists) | |||
2454 | hists->stats.total_period; | 2456 | hists->stats.total_period; |
2455 | } | 2457 | } |
2456 | 2458 | ||
2459 | int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq) | ||
2460 | { | ||
2461 | char unit; | ||
2462 | int printed; | ||
2463 | const struct dso *dso = hists->dso_filter; | ||
2464 | const struct thread *thread = hists->thread_filter; | ||
2465 | int socket_id = hists->socket_filter; | ||
2466 | unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; | ||
2467 | u64 nr_events = hists->stats.total_period; | ||
2468 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
2469 | const char *ev_name = perf_evsel__name(evsel); | ||
2470 | char buf[512], sample_freq_str[64] = ""; | ||
2471 | size_t buflen = sizeof(buf); | ||
2472 | char ref[30] = " show reference callgraph, "; | ||
2473 | bool enable_ref = false; | ||
2474 | |||
2475 | if (symbol_conf.filter_relative) { | ||
2476 | nr_samples = hists->stats.nr_non_filtered_samples; | ||
2477 | nr_events = hists->stats.total_non_filtered_period; | ||
2478 | } | ||
2479 | |||
2480 | if (perf_evsel__is_group_event(evsel)) { | ||
2481 | struct perf_evsel *pos; | ||
2482 | |||
2483 | perf_evsel__group_desc(evsel, buf, buflen); | ||
2484 | ev_name = buf; | ||
2485 | |||
2486 | for_each_group_member(pos, evsel) { | ||
2487 | struct hists *pos_hists = evsel__hists(pos); | ||
2488 | |||
2489 | if (symbol_conf.filter_relative) { | ||
2490 | nr_samples += pos_hists->stats.nr_non_filtered_samples; | ||
2491 | nr_events += pos_hists->stats.total_non_filtered_period; | ||
2492 | } else { | ||
2493 | nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; | ||
2494 | nr_events += pos_hists->stats.total_period; | ||
2495 | } | ||
2496 | } | ||
2497 | } | ||
2498 | |||
2499 | if (symbol_conf.show_ref_callgraph && | ||
2500 | strstr(ev_name, "call-graph=no")) | ||
2501 | enable_ref = true; | ||
2502 | |||
2503 | if (show_freq) | ||
2504 | scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | ||
2505 | |||
2506 | nr_samples = convert_unit(nr_samples, &unit); | ||
2507 | printed = scnprintf(bf, size, | ||
2508 | "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | ||
2509 | nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | ||
2510 | ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | ||
2511 | |||
2512 | |||
2513 | if (hists->uid_filter_str) | ||
2514 | printed += snprintf(bf + printed, size - printed, | ||
2515 | ", UID: %s", hists->uid_filter_str); | ||
2516 | if (thread) { | ||
2517 | if (hists__has(hists, thread)) { | ||
2518 | printed += scnprintf(bf + printed, size - printed, | ||
2519 | ", Thread: %s(%d)", | ||
2520 | (thread->comm_set ? thread__comm_str(thread) : ""), | ||
2521 | thread->tid); | ||
2522 | } else { | ||
2523 | printed += scnprintf(bf + printed, size - printed, | ||
2524 | ", Thread: %s", | ||
2525 | (thread->comm_set ? thread__comm_str(thread) : "")); | ||
2526 | } | ||
2527 | } | ||
2528 | if (dso) | ||
2529 | printed += scnprintf(bf + printed, size - printed, | ||
2530 | ", DSO: %s", dso->short_name); | ||
2531 | if (socket_id > -1) | ||
2532 | printed += scnprintf(bf + printed, size - printed, | ||
2533 | ", Processor Socket: %d", socket_id); | ||
2534 | |||
2535 | return printed; | ||
2536 | } | ||
2537 | |||
2457 | int parse_filter_percentage(const struct option *opt __maybe_unused, | 2538 | int parse_filter_percentage(const struct option *opt __maybe_unused, |
2458 | const char *arg, int unset __maybe_unused) | 2539 | const char *arg, int unset __maybe_unused) |
2459 | { | 2540 | { |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index e869cad4d89f..fbabfd8a215d 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -61,6 +61,7 @@ enum hist_column { | |||
61 | HISTC_SRCLINE_TO, | 61 | HISTC_SRCLINE_TO, |
62 | HISTC_TRACE, | 62 | HISTC_TRACE, |
63 | HISTC_SYM_SIZE, | 63 | HISTC_SYM_SIZE, |
64 | HISTC_DSO_SIZE, | ||
64 | HISTC_NR_COLS, /* Last entry */ | 65 | HISTC_NR_COLS, /* Last entry */ |
65 | }; | 66 | }; |
66 | 67 | ||
@@ -503,5 +504,11 @@ int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...); | |||
503 | int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, | 504 | int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, |
504 | struct perf_hpp_list *hpp_list); | 505 | struct perf_hpp_list *hpp_list); |
505 | int hists__fprintf_headers(struct hists *hists, FILE *fp); | 506 | int hists__fprintf_headers(struct hists *hists, FILE *fp); |
507 | int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq); | ||
508 | |||
509 | static inline int hists__scnprintf_title(struct hists *hists, char *bf, size_t size) | ||
510 | { | ||
511 | return __hists__scnprintf_title(hists, bf, size, true); | ||
512 | } | ||
506 | 513 | ||
507 | #endif /* __PERF_HIST_H */ | 514 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index edeb7291c8e1..0e9bbe01b0ab 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -103,6 +103,10 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip) | |||
103 | return ip; | 103 | return ip; |
104 | } | 104 | } |
105 | 105 | ||
106 | static inline size_t map__size(const struct map *map) | ||
107 | { | ||
108 | return map->end - map->start; | ||
109 | } | ||
106 | 110 | ||
107 | /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ | 111 | /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ |
108 | u64 map__rip_2objdump(struct map *map, u64 rip); | 112 | u64 map__rip_2objdump(struct map *map, u64 rip); |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index e8514f651865..26a68dfd8a4f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -1545,6 +1545,46 @@ struct sort_entry sort_sym_size = { | |||
1545 | .se_width_idx = HISTC_SYM_SIZE, | 1545 | .se_width_idx = HISTC_SYM_SIZE, |
1546 | }; | 1546 | }; |
1547 | 1547 | ||
1548 | /* --sort dso_size */ | ||
1549 | |||
1550 | static int64_t _sort__dso_size_cmp(struct map *map_l, struct map *map_r) | ||
1551 | { | ||
1552 | int64_t size_l = map_l != NULL ? map__size(map_l) : 0; | ||
1553 | int64_t size_r = map_r != NULL ? map__size(map_r) : 0; | ||
1554 | |||
1555 | return size_l < size_r ? -1 : | ||
1556 | size_l == size_r ? 0 : 1; | ||
1557 | } | ||
1558 | |||
1559 | static int64_t | ||
1560 | sort__dso_size_cmp(struct hist_entry *left, struct hist_entry *right) | ||
1561 | { | ||
1562 | return _sort__dso_size_cmp(right->ms.map, left->ms.map); | ||
1563 | } | ||
1564 | |||
1565 | static int _hist_entry__dso_size_snprintf(struct map *map, char *bf, | ||
1566 | size_t bf_size, unsigned int width) | ||
1567 | { | ||
1568 | if (map && map->dso) | ||
1569 | return repsep_snprintf(bf, bf_size, "%*d", width, | ||
1570 | map__size(map)); | ||
1571 | |||
1572 | return repsep_snprintf(bf, bf_size, "%*s", width, "unknown"); | ||
1573 | } | ||
1574 | |||
1575 | static int hist_entry__dso_size_snprintf(struct hist_entry *he, char *bf, | ||
1576 | size_t size, unsigned int width) | ||
1577 | { | ||
1578 | return _hist_entry__dso_size_snprintf(he->ms.map, bf, size, width); | ||
1579 | } | ||
1580 | |||
1581 | struct sort_entry sort_dso_size = { | ||
1582 | .se_header = "DSO size", | ||
1583 | .se_cmp = sort__dso_size_cmp, | ||
1584 | .se_snprintf = hist_entry__dso_size_snprintf, | ||
1585 | .se_width_idx = HISTC_DSO_SIZE, | ||
1586 | }; | ||
1587 | |||
1548 | 1588 | ||
1549 | struct sort_dimension { | 1589 | struct sort_dimension { |
1550 | const char *name; | 1590 | const char *name; |
@@ -1569,6 +1609,7 @@ static struct sort_dimension common_sort_dimensions[] = { | |||
1569 | DIM(SORT_TRANSACTION, "transaction", sort_transaction), | 1609 | DIM(SORT_TRANSACTION, "transaction", sort_transaction), |
1570 | DIM(SORT_TRACE, "trace", sort_trace), | 1610 | DIM(SORT_TRACE, "trace", sort_trace), |
1571 | DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), | 1611 | DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), |
1612 | DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size), | ||
1572 | DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), | 1613 | DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), |
1573 | }; | 1614 | }; |
1574 | 1615 | ||
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index f5901c10a563..035b62e2c60b 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -220,6 +220,7 @@ enum sort_type { | |||
220 | SORT_TRANSACTION, | 220 | SORT_TRANSACTION, |
221 | SORT_TRACE, | 221 | SORT_TRACE, |
222 | SORT_SYM_SIZE, | 222 | SORT_SYM_SIZE, |
223 | SORT_DSO_SIZE, | ||
223 | SORT_CGROUP_ID, | 224 | SORT_CGROUP_ID, |
224 | 225 | ||
225 | /* branch stack specific sort keys */ | 226 | /* branch stack specific sort keys */ |