diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-11-15 03:45:04 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-11-15 03:45:04 -0500 |
commit | 6a6b12e2125591e24891e6860410795ea53aed11 (patch) | |
tree | 9c186d798b75b708f663cbd286d0b842768fb873 /tools | |
parent | 91a79e5fa696fa626bfbd47f827eaf3eb7d76dc5 (diff) | |
parent | fef51ecd1056b5e090c9fb73e0833bd751389572 (diff) |
Merge tag 'perf-core-for-mingo-20161114' 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:
New features:
- Allow querying and setting .perfconfig variables (Taeung Song)
- Show branch information in callchains (predicted, TSX aborts, loop
iteractions, etc) (Jin Yao)
Infrastructure changes:
- Support kbuild's CFLAGS_REMOVE_ in tools/build (Jiri Olsa)
- Plug building jvmti to the main perf Makefile (Jiri Olsa)
Documentation changes:
- Update Intel PT documentation about context switch events (Arnaldo Carvalho de Melo)
- Fix 'perf record --call-graph dwarf' help/config in builds not linking
with a unwind library, mentioning that is a possible record option (Rabin Vincent)
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/build/Build.include | 4 | ||||
-rw-r--r-- | tools/build/Documentation/Build.txt | 6 | ||||
-rw-r--r-- | tools/build/feature/Makefile | 6 | ||||
-rw-r--r-- | tools/build/feature/test-jvmti.c | 13 | ||||
-rw-r--r-- | tools/perf/Documentation/intel-pt.txt | 19 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-config.txt | 35 | ||||
-rw-r--r-- | tools/perf/Makefile.config | 26 | ||||
-rw-r--r-- | tools/perf/Makefile.perf | 24 | ||||
-rw-r--r-- | tools/perf/builtin-config.c | 137 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 3 | ||||
-rw-r--r-- | tools/perf/jvmti/Build | 8 | ||||
-rw-r--r-- | tools/perf/jvmti/Makefile | 89 | ||||
-rw-r--r-- | tools/perf/tests/make | 2 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 20 | ||||
-rw-r--r-- | tools/perf/ui/stdio/hist.c | 35 | ||||
-rw-r--r-- | tools/perf/util/callchain.c | 205 | ||||
-rw-r--r-- | tools/perf/util/callchain.h | 26 | ||||
-rw-r--r-- | tools/perf/util/config.c | 20 | ||||
-rw-r--r-- | tools/perf/util/config.h | 4 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 82 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 1 |
21 files changed, 634 insertions, 131 deletions
diff --git a/tools/build/Build.include b/tools/build/Build.include index 1dcb95e76f70..c4ae12a5d0a5 100644 --- a/tools/build/Build.include +++ b/tools/build/Build.include | |||
@@ -89,7 +89,9 @@ if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ | |||
89 | # - per target C flags | 89 | # - per target C flags |
90 | # - per object C flags | 90 | # - per object C flags |
91 | # - BUILD_STR macro to allow '-D"$(variable)"' constructs | 91 | # - BUILD_STR macro to allow '-D"$(variable)"' constructs |
92 | c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj)) | 92 | c_flags_1 = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj)) |
93 | c_flags_2 = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(c_flags_1)) | ||
94 | c_flags = $(filter-out $(CFLAGS_REMOVE_$(obj)), $(c_flags_2)) | ||
93 | cxx_flags = -Wp,-MD,$(depfile),-MT,$@ $(CXXFLAGS) -D"BUILD_STR(s)=\#s" $(CXXFLAGS_$(basetarget).o) $(CXXFLAGS_$(obj)) | 95 | cxx_flags = -Wp,-MD,$(depfile),-MT,$@ $(CXXFLAGS) -D"BUILD_STR(s)=\#s" $(CXXFLAGS_$(basetarget).o) $(CXXFLAGS_$(obj)) |
94 | 96 | ||
95 | ### | 97 | ### |
diff --git a/tools/build/Documentation/Build.txt b/tools/build/Documentation/Build.txt index a47bffbae159..a22587475dbe 100644 --- a/tools/build/Documentation/Build.txt +++ b/tools/build/Documentation/Build.txt | |||
@@ -135,8 +135,10 @@ CFLAGS | |||
135 | 135 | ||
136 | It's possible to alter the standard object C flags in the following way: | 136 | It's possible to alter the standard object C flags in the following way: |
137 | 137 | ||
138 | CFLAGS_perf.o += '...' - alters CFLAGS for perf.o object | 138 | CFLAGS_perf.o += '...' - adds CFLAGS for perf.o object |
139 | CFLAGS_gtk += '...' - alters CFLAGS for gtk build object | 139 | CFLAGS_gtk += '...' - adds CFLAGS for gtk build object |
140 | CFLAGS_REMOVE_perf.o += '...' - removes CFLAGS for perf.o object | ||
141 | CFLAGS_REMOVE_gtk += '...' - removes CFLAGS for gtk build object | ||
140 | 142 | ||
141 | This C flags changes has the scope of the Build makefile they are defined in. | 143 | This C flags changes has the scope of the Build makefile they are defined in. |
142 | 144 | ||
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index ac9c477a2a48..8f668bce8996 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile | |||
@@ -47,7 +47,8 @@ FILES= \ | |||
47 | test-bpf.bin \ | 47 | test-bpf.bin \ |
48 | test-get_cpuid.bin \ | 48 | test-get_cpuid.bin \ |
49 | test-sdt.bin \ | 49 | test-sdt.bin \ |
50 | test-cxx.bin | 50 | test-cxx.bin \ |
51 | test-jvmti.bin | ||
51 | 52 | ||
52 | FILES := $(addprefix $(OUTPUT),$(FILES)) | 53 | FILES := $(addprefix $(OUTPUT),$(FILES)) |
53 | 54 | ||
@@ -225,6 +226,9 @@ $(OUTPUT)test-sdt.bin: | |||
225 | $(OUTPUT)test-cxx.bin: | 226 | $(OUTPUT)test-cxx.bin: |
226 | $(BUILDXX) -std=gnu++11 | 227 | $(BUILDXX) -std=gnu++11 |
227 | 228 | ||
229 | $(OUTPUT)test-jvmti.bin: | ||
230 | $(BUILD) | ||
231 | |||
228 | -include $(OUTPUT)*.d | 232 | -include $(OUTPUT)*.d |
229 | 233 | ||
230 | ############################### | 234 | ############################### |
diff --git a/tools/build/feature/test-jvmti.c b/tools/build/feature/test-jvmti.c new file mode 100644 index 000000000000..1c665f09b9d6 --- /dev/null +++ b/tools/build/feature/test-jvmti.c | |||
@@ -0,0 +1,13 @@ | |||
1 | #include <jvmti.h> | ||
2 | #include <jvmticmlr.h> | ||
3 | |||
4 | int main(void) | ||
5 | { | ||
6 | JavaVM jvm __attribute__((unused)); | ||
7 | jvmtiEventCallbacks cb __attribute__((unused)); | ||
8 | jvmtiCapabilities caps __attribute__((unused)); | ||
9 | jvmtiJlocationFormat format __attribute__((unused)); | ||
10 | jvmtiEnv jvmti __attribute__((unused)); | ||
11 | |||
12 | return 0; | ||
13 | } | ||
diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index c6c8318e38a2..b0b3007d3c9c 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt | |||
@@ -550,6 +550,18 @@ Unless /proc/sys/kernel/perf_event_paranoid is set to -1, unprivileged users | |||
550 | have memory limits imposed upon them. That affects what buffer sizes they can | 550 | have memory limits imposed upon them. That affects what buffer sizes they can |
551 | have as outlined above. | 551 | have as outlined above. |
552 | 552 | ||
553 | The v4.2 kernel introduced support for a context switch metadata event, | ||
554 | PERF_RECORD_SWITCH, which allows unprivileged users to see when their processes | ||
555 | are scheduled out and in, just not by whom, which is left for the | ||
556 | PERF_RECORD_SWITCH_CPU_WIDE, that is only accessible in system wide context, | ||
557 | which in turn requires CAP_SYS_ADMIN. | ||
558 | |||
559 | Please see the 45ac1403f564 ("perf: Add PERF_RECORD_SWITCH to indicate context | ||
560 | switches") commit, that introduces these metadata events for further info. | ||
561 | |||
562 | When working with kernels < v4.2, the following considerations must be taken, | ||
563 | as the sched:sched_switch tracepoints will be used to receive such information: | ||
564 | |||
553 | Unless /proc/sys/kernel/perf_event_paranoid is set to -1, unprivileged users are | 565 | Unless /proc/sys/kernel/perf_event_paranoid is set to -1, unprivileged users are |
554 | not permitted to use tracepoints which means there is insufficient side-band | 566 | not permitted to use tracepoints which means there is insufficient side-band |
555 | information to decode Intel PT in per-cpu mode, and potentially workload-only | 567 | information to decode Intel PT in per-cpu mode, and potentially workload-only |
@@ -564,8 +576,11 @@ sched_switch tracepoint | |||
564 | ----------------------- | 576 | ----------------------- |
565 | 577 | ||
566 | The sched_switch tracepoint is used to provide side-band data for Intel PT | 578 | The sched_switch tracepoint is used to provide side-band data for Intel PT |
567 | decoding. sched_switch events are automatically added. e.g. the second event | 579 | decoding in kernels where the PERF_RECORD_SWITCH metadata event isn't |
568 | shown below | 580 | available. |
581 | |||
582 | The sched_switch events are automatically added. e.g. the second event shown | ||
583 | below: | ||
569 | 584 | ||
570 | $ perf record -vv -e intel_pt//u uname | 585 | $ perf record -vv -e intel_pt//u uname |
571 | ------------------------------------------------------------ | 586 | ------------------------------------------------------------ |
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index cb081ac59fd1..9365b75fd04f 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt | |||
@@ -8,6 +8,8 @@ perf-config - Get and set variables in a configuration file. | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf config' [<file-option>] [section.name[=value] ...] | ||
12 | or | ||
11 | 'perf config' [<file-option>] -l | --list | 13 | 'perf config' [<file-option>] -l | --list |
12 | 14 | ||
13 | DESCRIPTION | 15 | DESCRIPTION |
@@ -118,6 +120,39 @@ Given a $HOME/.perfconfig like this: | |||
118 | children = true | 120 | children = true |
119 | group = true | 121 | group = true |
120 | 122 | ||
123 | You can hide source code of annotate feature setting the config to false with | ||
124 | |||
125 | % perf config annotate.hide_src_code=true | ||
126 | |||
127 | If you want to add or modify several config items, you can do like | ||
128 | |||
129 | % perf config ui.show-headers=false kmem.default=slab | ||
130 | |||
131 | To modify the sort order of report functionality in user config file(i.e. `~/.perfconfig`), do | ||
132 | |||
133 | % perf config --user report sort-order=srcline | ||
134 | |||
135 | To change colors of selected line to other foreground and background colors | ||
136 | in system config file (i.e. `$(sysconf)/perfconfig`), do | ||
137 | |||
138 | % perf config --system colors.selected=yellow,green | ||
139 | |||
140 | To query the record mode of call graph, do | ||
141 | |||
142 | % perf config call-graph.record-mode | ||
143 | |||
144 | If you want to know multiple config key/value pairs, you can do like | ||
145 | |||
146 | % perf config report.queue-size call-graph.order report.children | ||
147 | |||
148 | To query the config value of sort order of call graph in user config file (i.e. `~/.perfconfig`), do | ||
149 | |||
150 | % perf config --user call-graph.sort-order | ||
151 | |||
152 | To query the config value of buildid directory in system config file (i.e. `$(sysconf)/perfconfig`), do | ||
153 | |||
154 | % perf config --system buildid.dir | ||
155 | |||
121 | Variables | 156 | Variables |
122 | ~~~~~~~~~ | 157 | ~~~~~~~~~ |
123 | 158 | ||
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index cffdd9cf3ebf..8a493d46fab9 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config | |||
@@ -758,6 +758,31 @@ ifndef NO_AUXTRACE | |||
758 | endif | 758 | endif |
759 | endif | 759 | endif |
760 | 760 | ||
761 | ifndef NO_JVMTI | ||
762 | ifneq (,$(wildcard /usr/sbin/update-java-alternatives)) | ||
763 | JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | awk '{print $$3}') | ||
764 | else | ||
765 | ifneq (,$(wildcard /usr/sbin/alternatives)) | ||
766 | JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g') | ||
767 | endif | ||
768 | endif | ||
769 | ifndef JDIR | ||
770 | $(warning No alternatives command found, you need to set JDIR= to point to the root of your Java directory) | ||
771 | NO_JVMTI := 1 | ||
772 | endif | ||
773 | endif | ||
774 | |||
775 | ifndef NO_JVMTI | ||
776 | FEATURE_CHECK_CFLAGS-jvmti := -I$(JDIR)/include -I$(JDIR)/include/linux | ||
777 | $(call feature_check,jvmti) | ||
778 | ifeq ($(feature-jvmti), 1) | ||
779 | $(call detected_var,JDIR) | ||
780 | else | ||
781 | $(warning No openjdk development package found, please install JDK package) | ||
782 | NO_JVMTI := 1 | ||
783 | endif | ||
784 | endif | ||
785 | |||
761 | # Among the variables below, these: | 786 | # Among the variables below, these: |
762 | # perfexecdir | 787 | # perfexecdir |
763 | # template_dir | 788 | # template_dir |
@@ -850,6 +875,7 @@ ifeq ($(VF),1) | |||
850 | $(call print_var,sysconfdir) | 875 | $(call print_var,sysconfdir) |
851 | $(call print_var,LIBUNWIND_DIR) | 876 | $(call print_var,LIBUNWIND_DIR) |
852 | $(call print_var,LIBDW_DIR) | 877 | $(call print_var,LIBDW_DIR) |
878 | $(call print_var,JDIR) | ||
853 | 879 | ||
854 | ifeq ($(dwarf-post-unwind),1) | 880 | ifeq ($(dwarf-post-unwind),1) |
855 | $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text)) | 881 | $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text)) |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 7de14f470f3c..3cb1df43ad3e 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -86,6 +86,8 @@ include ../scripts/utilities.mak | |||
86 | # | 86 | # |
87 | # Define FEATURES_DUMP to provide features detection dump file | 87 | # Define FEATURES_DUMP to provide features detection dump file |
88 | # and bypass the feature detection | 88 | # and bypass the feature detection |
89 | # | ||
90 | # Define NO_JVMTI if you do not want jvmti agent built | ||
89 | 91 | ||
90 | # As per kernel Makefile, avoid funny character set dependencies | 92 | # As per kernel Makefile, avoid funny character set dependencies |
91 | unexport LC_ALL | 93 | unexport LC_ALL |
@@ -283,6 +285,12 @@ ifndef NO_PERF_READ_VDSOX32 | |||
283 | PROGRAMS += $(OUTPUT)perf-read-vdsox32 | 285 | PROGRAMS += $(OUTPUT)perf-read-vdsox32 |
284 | endif | 286 | endif |
285 | 287 | ||
288 | LIBJVMTI = libperf-jvmti.so | ||
289 | |||
290 | ifndef NO_JVMTI | ||
291 | PROGRAMS += $(OUTPUT)$(LIBJVMTI) | ||
292 | endif | ||
293 | |||
286 | # what 'all' will build and 'install' will install, in perfexecdir | 294 | # what 'all' will build and 'install' will install, in perfexecdir |
287 | ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) | 295 | ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) |
288 | 296 | ||
@@ -551,6 +559,16 @@ $(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c | |||
551 | $(QUIET_CC)$(CC) -mx32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c | 559 | $(QUIET_CC)$(CC) -mx32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c |
552 | endif | 560 | endif |
553 | 561 | ||
562 | ifndef NO_JVMTI | ||
563 | LIBJVMTI_IN := $(OUTPUT)jvmti/jvmti-in.o | ||
564 | |||
565 | $(LIBJVMTI_IN): FORCE | ||
566 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=jvmti obj=jvmti | ||
567 | |||
568 | $(OUTPUT)$(LIBJVMTI): $(LIBJVMTI_IN) | ||
569 | $(QUIET_LINK)$(CC) -shared -Wl,-soname -Wl,$(LIBJVMTI) -o $@ $< -lelf -lrt | ||
570 | endif | ||
571 | |||
554 | $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) | 572 | $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) |
555 | 573 | ||
556 | LIBPERF_IN := $(OUTPUT)libperf-in.o | 574 | LIBPERF_IN := $(OUTPUT)libperf-in.o |
@@ -688,6 +706,10 @@ ifndef NO_PERF_READ_VDSOX32 | |||
688 | $(call QUIET_INSTALL, perf-read-vdsox32) \ | 706 | $(call QUIET_INSTALL, perf-read-vdsox32) \ |
689 | $(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)'; | 707 | $(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)'; |
690 | endif | 708 | endif |
709 | ifndef NO_JVMTI | ||
710 | $(call QUIET_INSTALL, $(LIBJVMTI)) \ | ||
711 | $(INSTALL) $(OUTPUT)$(LIBJVMTI) '$(DESTDIR_SQ)$(libdir_SQ)'; | ||
712 | endif | ||
691 | $(call QUIET_INSTALL, libexec) \ | 713 | $(call QUIET_INSTALL, libexec) \ |
692 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 714 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
693 | $(call QUIET_INSTALL, perf-archive) \ | 715 | $(call QUIET_INSTALL, perf-archive) \ |
@@ -754,7 +776,7 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea | |||
754 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) | 776 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) |
755 | $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete | 777 | $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete |
756 | $(Q)$(RM) $(OUTPUT).config-detected | 778 | $(Q)$(RM) $(OUTPUT).config-detected |
757 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)pmu-events/jevents | 779 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)pmu-events/jevents $(OUTPUT)$(LIBJVMTI).so |
758 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \ | 780 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \ |
759 | $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \ | 781 | $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \ |
760 | $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \ | 782 | $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \ |
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index e4207a23b52c..8c0d93b7c2f0 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c | |||
@@ -17,7 +17,7 @@ | |||
17 | static bool use_system_config, use_user_config; | 17 | static bool use_system_config, use_user_config; |
18 | 18 | ||
19 | static const char * const config_usage[] = { | 19 | static const char * const config_usage[] = { |
20 | "perf config [<file-option>] [options]", | 20 | "perf config [<file-option>] [options] [section.name[=value] ...]", |
21 | NULL | 21 | NULL |
22 | }; | 22 | }; |
23 | 23 | ||
@@ -33,6 +33,73 @@ static struct option config_options[] = { | |||
33 | OPT_END() | 33 | OPT_END() |
34 | }; | 34 | }; |
35 | 35 | ||
36 | static int set_config(struct perf_config_set *set, const char *file_name, | ||
37 | const char *var, const char *value) | ||
38 | { | ||
39 | struct perf_config_section *section = NULL; | ||
40 | struct perf_config_item *item = NULL; | ||
41 | const char *first_line = "# this file is auto-generated."; | ||
42 | FILE *fp; | ||
43 | |||
44 | if (set == NULL) | ||
45 | return -1; | ||
46 | |||
47 | fp = fopen(file_name, "w"); | ||
48 | if (!fp) | ||
49 | return -1; | ||
50 | |||
51 | perf_config_set__collect(set, file_name, var, value); | ||
52 | fprintf(fp, "%s\n", first_line); | ||
53 | |||
54 | /* overwrite configvariables */ | ||
55 | perf_config_items__for_each_entry(&set->sections, section) { | ||
56 | if (!use_system_config && section->from_system_config) | ||
57 | continue; | ||
58 | fprintf(fp, "[%s]\n", section->name); | ||
59 | |||
60 | perf_config_items__for_each_entry(§ion->items, item) { | ||
61 | if (!use_system_config && section->from_system_config) | ||
62 | continue; | ||
63 | if (item->value) | ||
64 | fprintf(fp, "\t%s = %s\n", | ||
65 | item->name, item->value); | ||
66 | } | ||
67 | } | ||
68 | fclose(fp); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int show_spec_config(struct perf_config_set *set, const char *var) | ||
74 | { | ||
75 | struct perf_config_section *section; | ||
76 | struct perf_config_item *item; | ||
77 | |||
78 | if (set == NULL) | ||
79 | return -1; | ||
80 | |||
81 | perf_config_items__for_each_entry(&set->sections, section) { | ||
82 | if (prefixcmp(var, section->name) != 0) | ||
83 | continue; | ||
84 | |||
85 | perf_config_items__for_each_entry(§ion->items, item) { | ||
86 | const char *name = var + strlen(section->name) + 1; | ||
87 | |||
88 | if (strcmp(name, item->name) == 0) { | ||
89 | char *value = item->value; | ||
90 | |||
91 | if (value) { | ||
92 | printf("%s=%s\n", var, value); | ||
93 | return 0; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | } | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
36 | static int show_config(struct perf_config_set *set) | 103 | static int show_config(struct perf_config_set *set) |
37 | { | 104 | { |
38 | struct perf_config_section *section; | 105 | struct perf_config_section *section; |
@@ -52,9 +119,44 @@ static int show_config(struct perf_config_set *set) | |||
52 | return 0; | 119 | return 0; |
53 | } | 120 | } |
54 | 121 | ||
122 | static int parse_config_arg(char *arg, char **var, char **value) | ||
123 | { | ||
124 | const char *last_dot = strchr(arg, '.'); | ||
125 | |||
126 | /* | ||
127 | * Since "var" actually contains the section name and the real | ||
128 | * config variable name separated by a dot, we have to know where the dot is. | ||
129 | */ | ||
130 | if (last_dot == NULL || last_dot == arg) { | ||
131 | pr_err("The config variable does not contain a section name: %s\n", arg); | ||
132 | return -1; | ||
133 | } | ||
134 | if (!last_dot[1]) { | ||
135 | pr_err("The config variable does not contain a variable name: %s\n", arg); | ||
136 | return -1; | ||
137 | } | ||
138 | |||
139 | *value = strchr(arg, '='); | ||
140 | if (*value == NULL) | ||
141 | *var = arg; | ||
142 | else if (!strcmp(*value, "=")) { | ||
143 | pr_err("The config variable does not contain a value: %s\n", arg); | ||
144 | return -1; | ||
145 | } else { | ||
146 | *value = *value + 1; /* excluding a first character '=' */ | ||
147 | *var = strsep(&arg, "="); | ||
148 | if (*var[0] == '\0') { | ||
149 | pr_err("invalid config variable: %s\n", arg); | ||
150 | return -1; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
55 | int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) | 157 | int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) |
56 | { | 158 | { |
57 | int ret = 0; | 159 | int i, ret = 0; |
58 | struct perf_config_set *set; | 160 | struct perf_config_set *set; |
59 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); | 161 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); |
60 | 162 | ||
@@ -100,7 +202,36 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) | |||
100 | } | 202 | } |
101 | break; | 203 | break; |
102 | default: | 204 | default: |
103 | usage_with_options(config_usage, config_options); | 205 | if (argc) { |
206 | for (i = 0; argv[i]; i++) { | ||
207 | char *var, *value; | ||
208 | char *arg = strdup(argv[i]); | ||
209 | |||
210 | if (!arg) { | ||
211 | pr_err("%s: strdup failed\n", __func__); | ||
212 | ret = -1; | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | if (parse_config_arg(arg, &var, &value) < 0) { | ||
217 | free(arg); | ||
218 | ret = -1; | ||
219 | break; | ||
220 | } | ||
221 | |||
222 | if (value == NULL) | ||
223 | ret = show_spec_config(set, var); | ||
224 | else { | ||
225 | const char *config_filename = config_exclusive_filename; | ||
226 | |||
227 | if (!config_exclusive_filename) | ||
228 | config_filename = user_config; | ||
229 | ret = set_config(set, config_filename, var, value); | ||
230 | } | ||
231 | free(arg); | ||
232 | } | ||
233 | } else | ||
234 | usage_with_options(config_usage, config_options); | ||
104 | } | 235 | } |
105 | 236 | ||
106 | perf_config_set__delete(set); | 237 | perf_config_set__delete(set); |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8064de8ceedc..3dfbfffe2ecd 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -911,6 +911,9 @@ repeat: | |||
911 | if (itrace_synth_opts.last_branch) | 911 | if (itrace_synth_opts.last_branch) |
912 | has_br_stack = true; | 912 | has_br_stack = true; |
913 | 913 | ||
914 | if (has_br_stack && branch_call_mode) | ||
915 | symbol_conf.show_branchflag_count = true; | ||
916 | |||
914 | /* | 917 | /* |
915 | * Branch mode is a tristate: | 918 | * Branch mode is a tristate: |
916 | * -1 means default, so decide based on the file having branch data. | 919 | * -1 means default, so decide based on the file having branch data. |
diff --git a/tools/perf/jvmti/Build b/tools/perf/jvmti/Build new file mode 100644 index 000000000000..eaeb8cb5379b --- /dev/null +++ b/tools/perf/jvmti/Build | |||
@@ -0,0 +1,8 @@ | |||
1 | jvmti-y += libjvmti.o | ||
2 | jvmti-y += jvmti_agent.o | ||
3 | |||
4 | CFLAGS_jvmti = -fPIC -DPIC -I$(JDIR)/include -I$(JDIR)/include/linux | ||
5 | CFLAGS_REMOVE_jvmti = -Wmissing-declarations | ||
6 | CFLAGS_REMOVE_jvmti += -Wstrict-prototypes | ||
7 | CFLAGS_REMOVE_jvmti += -Wextra | ||
8 | CFLAGS_REMOVE_jvmti += -Wwrite-strings | ||
diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile deleted file mode 100644 index df14e6b67b63..000000000000 --- a/tools/perf/jvmti/Makefile +++ /dev/null | |||
@@ -1,89 +0,0 @@ | |||
1 | ARCH=$(shell uname -m) | ||
2 | |||
3 | ifeq ($(ARCH), x86_64) | ||
4 | JARCH=amd64 | ||
5 | endif | ||
6 | ifeq ($(ARCH), armv7l) | ||
7 | JARCH=armhf | ||
8 | endif | ||
9 | ifeq ($(ARCH), armv6l) | ||
10 | JARCH=armhf | ||
11 | endif | ||
12 | ifeq ($(ARCH), aarch64) | ||
13 | JARCH=aarch64 | ||
14 | endif | ||
15 | ifeq ($(ARCH), ppc64) | ||
16 | JARCH=powerpc | ||
17 | endif | ||
18 | ifeq ($(ARCH), ppc64le) | ||
19 | JARCH=powerpc | ||
20 | endif | ||
21 | |||
22 | DESTDIR=/usr/local | ||
23 | |||
24 | VERSION=1 | ||
25 | REVISION=0 | ||
26 | AGE=0 | ||
27 | |||
28 | LN=ln -sf | ||
29 | RM=rm | ||
30 | |||
31 | SLIBJVMTI=libjvmti.so.$(VERSION).$(REVISION).$(AGE) | ||
32 | VLIBJVMTI=libjvmti.so.$(VERSION) | ||
33 | SLDFLAGS=-shared -Wl,-soname -Wl,$(VLIBJVMTI) | ||
34 | SOLIBEXT=so | ||
35 | |||
36 | # The following works at least on fedora 23, you may need the next | ||
37 | # line for other distros. | ||
38 | ifneq (,$(wildcard /usr/sbin/update-java-alternatives)) | ||
39 | JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | awk '{print $$3}') | ||
40 | else | ||
41 | ifneq (,$(wildcard /usr/sbin/alternatives)) | ||
42 | JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g') | ||
43 | endif | ||
44 | endif | ||
45 | ifndef JDIR | ||
46 | $(error Could not find alternatives command, you need to set JDIR= to point to the root of your Java directory) | ||
47 | else | ||
48 | ifeq (,$(wildcard $(JDIR)/include/jvmti.h)) | ||
49 | $(error the openjdk development package appears to me missing, install and try again) | ||
50 | endif | ||
51 | endif | ||
52 | $(info Using Java from $(JDIR)) | ||
53 | # -lrt required in 32-bit mode for clock_gettime() | ||
54 | LIBS=-lelf -lrt | ||
55 | INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux | ||
56 | |||
57 | TARGETS=$(SLIBJVMTI) | ||
58 | |||
59 | SRCS=libjvmti.c jvmti_agent.c | ||
60 | OBJS=$(SRCS:.c=.o) | ||
61 | SOBJS=$(OBJS:.o=.lo) | ||
62 | OPT=-O2 -g -Werror -Wall | ||
63 | |||
64 | CFLAGS=$(INCDIR) $(OPT) | ||
65 | |||
66 | all: $(TARGETS) | ||
67 | |||
68 | .c.o: | ||
69 | $(CC) $(CFLAGS) -c $*.c | ||
70 | .c.lo: | ||
71 | $(CC) -fPIC -DPIC $(CFLAGS) -c $*.c -o $*.lo | ||
72 | |||
73 | $(OBJS) $(SOBJS): Makefile jvmti_agent.h ../util/jitdump.h | ||
74 | |||
75 | $(SLIBJVMTI): $(SOBJS) | ||
76 | $(CC) $(CFLAGS) $(SLDFLAGS) -o $@ $(SOBJS) $(LIBS) | ||
77 | $(LN) $@ libjvmti.$(SOLIBEXT) | ||
78 | |||
79 | clean: | ||
80 | $(RM) -f *.o *.so.* *.so *.lo | ||
81 | |||
82 | install: | ||
83 | -mkdir -p $(DESTDIR)/lib | ||
84 | install -m 755 $(SLIBJVMTI) $(DESTDIR)/lib/ | ||
85 | (cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) $(VLIBJVMTI)) | ||
86 | (cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) libjvmti.$(SOLIBEXT)) | ||
87 | ldconfig | ||
88 | |||
89 | .SUFFIXES: .c .S .o .lo | ||
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 143f4d549769..08ed7f12cc37 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -106,7 +106,7 @@ make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 | |||
106 | make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 | 106 | make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 |
107 | make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 | 107 | make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 |
108 | make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 | 108 | make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 |
109 | make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 | 109 | make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 NO_JVMTI=1 |
110 | 110 | ||
111 | # $(run) contains all available tests | 111 | # $(run) contains all available tests |
112 | run := make_pure | 112 | run := make_pure |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 84f5dd2fb59c..66676cb8effe 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -738,6 +738,7 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser, | |||
738 | struct callchain_print_arg *arg) | 738 | struct callchain_print_arg *arg) |
739 | { | 739 | { |
740 | char bf[1024], *alloc_str; | 740 | char bf[1024], *alloc_str; |
741 | char buf[64], *alloc_str2; | ||
741 | const char *str; | 742 | const char *str; |
742 | 743 | ||
743 | if (arg->row_offset != 0) { | 744 | if (arg->row_offset != 0) { |
@@ -746,12 +747,26 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser, | |||
746 | } | 747 | } |
747 | 748 | ||
748 | alloc_str = NULL; | 749 | alloc_str = NULL; |
750 | alloc_str2 = NULL; | ||
751 | |||
749 | str = callchain_list__sym_name(chain, bf, sizeof(bf), | 752 | str = callchain_list__sym_name(chain, bf, sizeof(bf), |
750 | browser->show_dso); | 753 | browser->show_dso); |
751 | 754 | ||
752 | if (need_percent) { | 755 | if (symbol_conf.show_branchflag_count) { |
753 | char buf[64]; | 756 | if (need_percent) |
757 | callchain_list_counts__printf_value(node, chain, NULL, | ||
758 | buf, sizeof(buf)); | ||
759 | else | ||
760 | callchain_list_counts__printf_value(NULL, chain, NULL, | ||
761 | buf, sizeof(buf)); | ||
762 | |||
763 | if (asprintf(&alloc_str2, "%s%s", str, buf) < 0) | ||
764 | str = "Not enough memory!"; | ||
765 | else | ||
766 | str = alloc_str2; | ||
767 | } | ||
754 | 768 | ||
769 | if (need_percent) { | ||
755 | callchain_node__scnprintf_value(node, buf, sizeof(buf), | 770 | callchain_node__scnprintf_value(node, buf, sizeof(buf), |
756 | total); | 771 | total); |
757 | 772 | ||
@@ -764,6 +779,7 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser, | |||
764 | print(browser, chain, str, offset, row, arg); | 779 | print(browser, chain, str, offset, row, arg); |
765 | 780 | ||
766 | free(alloc_str); | 781 | free(alloc_str); |
782 | free(alloc_str2); | ||
767 | return 1; | 783 | return 1; |
768 | } | 784 | } |
769 | 785 | ||
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 89d8441f9890..668f4aecf2e6 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -41,7 +41,9 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node, | |||
41 | { | 41 | { |
42 | int i; | 42 | int i; |
43 | size_t ret = 0; | 43 | size_t ret = 0; |
44 | char bf[1024]; | 44 | char bf[1024], *alloc_str = NULL; |
45 | char buf[64]; | ||
46 | const char *str; | ||
45 | 47 | ||
46 | ret += callchain__fprintf_left_margin(fp, left_margin); | 48 | ret += callchain__fprintf_left_margin(fp, left_margin); |
47 | for (i = 0; i < depth; i++) { | 49 | for (i = 0; i < depth; i++) { |
@@ -56,8 +58,26 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node, | |||
56 | } else | 58 | } else |
57 | ret += fprintf(fp, "%s", " "); | 59 | ret += fprintf(fp, "%s", " "); |
58 | } | 60 | } |
59 | fputs(callchain_list__sym_name(chain, bf, sizeof(bf), false), fp); | 61 | |
62 | str = callchain_list__sym_name(chain, bf, sizeof(bf), false); | ||
63 | |||
64 | if (symbol_conf.show_branchflag_count) { | ||
65 | if (!period) | ||
66 | callchain_list_counts__printf_value(node, chain, NULL, | ||
67 | buf, sizeof(buf)); | ||
68 | else | ||
69 | callchain_list_counts__printf_value(NULL, chain, NULL, | ||
70 | buf, sizeof(buf)); | ||
71 | |||
72 | if (asprintf(&alloc_str, "%s%s", str, buf) < 0) | ||
73 | str = "Not enough memory!"; | ||
74 | else | ||
75 | str = alloc_str; | ||
76 | } | ||
77 | |||
78 | fputs(str, fp); | ||
60 | fputc('\n', fp); | 79 | fputc('\n', fp); |
80 | free(alloc_str); | ||
61 | return ret; | 81 | return ret; |
62 | } | 82 | } |
63 | 83 | ||
@@ -219,8 +239,15 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, | |||
219 | } else | 239 | } else |
220 | ret += callchain__fprintf_left_margin(fp, left_margin); | 240 | ret += callchain__fprintf_left_margin(fp, left_margin); |
221 | 241 | ||
222 | ret += fprintf(fp, "%s\n", callchain_list__sym_name(chain, bf, sizeof(bf), | 242 | ret += fprintf(fp, "%s", |
223 | false)); | 243 | callchain_list__sym_name(chain, bf, |
244 | sizeof(bf), | ||
245 | false)); | ||
246 | |||
247 | if (symbol_conf.show_branchflag_count) | ||
248 | ret += callchain_list_counts__printf_value( | ||
249 | NULL, chain, fp, NULL, 0); | ||
250 | ret += fprintf(fp, "\n"); | ||
224 | 251 | ||
225 | if (++entries_printed == callchain_param.print_limit) | 252 | if (++entries_printed == callchain_param.print_limit) |
226 | break; | 253 | break; |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 07fd30bc2f81..823befd8209a 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -193,7 +193,6 @@ int perf_callchain_config(const char *var, const char *value) | |||
193 | 193 | ||
194 | if (!strcmp(var, "record-mode")) | 194 | if (!strcmp(var, "record-mode")) |
195 | return parse_callchain_record_opt(value, &callchain_param); | 195 | return parse_callchain_record_opt(value, &callchain_param); |
196 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
197 | if (!strcmp(var, "dump-size")) { | 196 | if (!strcmp(var, "dump-size")) { |
198 | unsigned long size = 0; | 197 | unsigned long size = 0; |
199 | int ret; | 198 | int ret; |
@@ -203,7 +202,6 @@ int perf_callchain_config(const char *var, const char *value) | |||
203 | 202 | ||
204 | return ret; | 203 | return ret; |
205 | } | 204 | } |
206 | #endif | ||
207 | if (!strcmp(var, "print-type")) | 205 | if (!strcmp(var, "print-type")) |
208 | return parse_callchain_mode(value); | 206 | return parse_callchain_mode(value); |
209 | if (!strcmp(var, "order")) | 207 | if (!strcmp(var, "order")) |
@@ -440,6 +438,21 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor) | |||
440 | call->ip = cursor_node->ip; | 438 | call->ip = cursor_node->ip; |
441 | call->ms.sym = cursor_node->sym; | 439 | call->ms.sym = cursor_node->sym; |
442 | call->ms.map = cursor_node->map; | 440 | call->ms.map = cursor_node->map; |
441 | |||
442 | if (cursor_node->branch) { | ||
443 | call->branch_count = 1; | ||
444 | |||
445 | if (cursor_node->branch_flags.predicted) | ||
446 | call->predicted_count = 1; | ||
447 | |||
448 | if (cursor_node->branch_flags.abort) | ||
449 | call->abort_count = 1; | ||
450 | |||
451 | call->cycles_count = cursor_node->branch_flags.cycles; | ||
452 | call->iter_count = cursor_node->nr_loop_iter; | ||
453 | call->samples_count = cursor_node->samples; | ||
454 | } | ||
455 | |||
443 | list_add_tail(&call->list, &node->val); | 456 | list_add_tail(&call->list, &node->val); |
444 | 457 | ||
445 | callchain_cursor_advance(cursor); | 458 | callchain_cursor_advance(cursor); |
@@ -499,8 +512,23 @@ static enum match_result match_chain(struct callchain_cursor_node *node, | |||
499 | right = node->ip; | 512 | right = node->ip; |
500 | } | 513 | } |
501 | 514 | ||
502 | if (left == right) | 515 | if (left == right) { |
516 | if (node->branch) { | ||
517 | cnode->branch_count++; | ||
518 | |||
519 | if (node->branch_flags.predicted) | ||
520 | cnode->predicted_count++; | ||
521 | |||
522 | if (node->branch_flags.abort) | ||
523 | cnode->abort_count++; | ||
524 | |||
525 | cnode->cycles_count += node->branch_flags.cycles; | ||
526 | cnode->iter_count += node->nr_loop_iter; | ||
527 | cnode->samples_count += node->samples; | ||
528 | } | ||
529 | |||
503 | return MATCH_EQ; | 530 | return MATCH_EQ; |
531 | } | ||
504 | 532 | ||
505 | return left > right ? MATCH_GT : MATCH_LT; | 533 | return left > right ? MATCH_GT : MATCH_LT; |
506 | } | 534 | } |
@@ -730,7 +758,8 @@ merge_chain_branch(struct callchain_cursor *cursor, | |||
730 | 758 | ||
731 | list_for_each_entry_safe(list, next_list, &src->val, list) { | 759 | list_for_each_entry_safe(list, next_list, &src->val, list) { |
732 | callchain_cursor_append(cursor, list->ip, | 760 | callchain_cursor_append(cursor, list->ip, |
733 | list->ms.map, list->ms.sym); | 761 | list->ms.map, list->ms.sym, |
762 | false, NULL, 0, 0); | ||
734 | list_del(&list->list); | 763 | list_del(&list->list); |
735 | free(list); | 764 | free(list); |
736 | } | 765 | } |
@@ -767,7 +796,9 @@ int callchain_merge(struct callchain_cursor *cursor, | |||
767 | } | 796 | } |
768 | 797 | ||
769 | int callchain_cursor_append(struct callchain_cursor *cursor, | 798 | int callchain_cursor_append(struct callchain_cursor *cursor, |
770 | u64 ip, struct map *map, struct symbol *sym) | 799 | u64 ip, struct map *map, struct symbol *sym, |
800 | bool branch, struct branch_flags *flags, | ||
801 | int nr_loop_iter, int samples) | ||
771 | { | 802 | { |
772 | struct callchain_cursor_node *node = *cursor->last; | 803 | struct callchain_cursor_node *node = *cursor->last; |
773 | 804 | ||
@@ -782,6 +813,13 @@ int callchain_cursor_append(struct callchain_cursor *cursor, | |||
782 | node->ip = ip; | 813 | node->ip = ip; |
783 | node->map = map; | 814 | node->map = map; |
784 | node->sym = sym; | 815 | node->sym = sym; |
816 | node->branch = branch; | ||
817 | node->nr_loop_iter = nr_loop_iter; | ||
818 | node->samples = samples; | ||
819 | |||
820 | if (flags) | ||
821 | memcpy(&node->branch_flags, flags, | ||
822 | sizeof(struct branch_flags)); | ||
785 | 823 | ||
786 | cursor->nr++; | 824 | cursor->nr++; |
787 | 825 | ||
@@ -939,6 +977,163 @@ int callchain_node__fprintf_value(struct callchain_node *node, | |||
939 | return 0; | 977 | return 0; |
940 | } | 978 | } |
941 | 979 | ||
980 | static void callchain_counts_value(struct callchain_node *node, | ||
981 | u64 *branch_count, u64 *predicted_count, | ||
982 | u64 *abort_count, u64 *cycles_count) | ||
983 | { | ||
984 | struct callchain_list *clist; | ||
985 | |||
986 | list_for_each_entry(clist, &node->val, list) { | ||
987 | if (branch_count) | ||
988 | *branch_count += clist->branch_count; | ||
989 | |||
990 | if (predicted_count) | ||
991 | *predicted_count += clist->predicted_count; | ||
992 | |||
993 | if (abort_count) | ||
994 | *abort_count += clist->abort_count; | ||
995 | |||
996 | if (cycles_count) | ||
997 | *cycles_count += clist->cycles_count; | ||
998 | } | ||
999 | } | ||
1000 | |||
1001 | static int callchain_node_branch_counts_cumul(struct callchain_node *node, | ||
1002 | u64 *branch_count, | ||
1003 | u64 *predicted_count, | ||
1004 | u64 *abort_count, | ||
1005 | u64 *cycles_count) | ||
1006 | { | ||
1007 | struct callchain_node *child; | ||
1008 | struct rb_node *n; | ||
1009 | |||
1010 | n = rb_first(&node->rb_root_in); | ||
1011 | while (n) { | ||
1012 | child = rb_entry(n, struct callchain_node, rb_node_in); | ||
1013 | n = rb_next(n); | ||
1014 | |||
1015 | callchain_node_branch_counts_cumul(child, branch_count, | ||
1016 | predicted_count, | ||
1017 | abort_count, | ||
1018 | cycles_count); | ||
1019 | |||
1020 | callchain_counts_value(child, branch_count, | ||
1021 | predicted_count, abort_count, | ||
1022 | cycles_count); | ||
1023 | } | ||
1024 | |||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | int callchain_branch_counts(struct callchain_root *root, | ||
1029 | u64 *branch_count, u64 *predicted_count, | ||
1030 | u64 *abort_count, u64 *cycles_count) | ||
1031 | { | ||
1032 | if (branch_count) | ||
1033 | *branch_count = 0; | ||
1034 | |||
1035 | if (predicted_count) | ||
1036 | *predicted_count = 0; | ||
1037 | |||
1038 | if (abort_count) | ||
1039 | *abort_count = 0; | ||
1040 | |||
1041 | if (cycles_count) | ||
1042 | *cycles_count = 0; | ||
1043 | |||
1044 | return callchain_node_branch_counts_cumul(&root->node, | ||
1045 | branch_count, | ||
1046 | predicted_count, | ||
1047 | abort_count, | ||
1048 | cycles_count); | ||
1049 | } | ||
1050 | |||
1051 | static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, | ||
1052 | u64 branch_count, u64 predicted_count, | ||
1053 | u64 abort_count, u64 cycles_count, | ||
1054 | u64 iter_count, u64 samples_count) | ||
1055 | { | ||
1056 | double predicted_percent = 0.0; | ||
1057 | const char *null_str = ""; | ||
1058 | char iter_str[32]; | ||
1059 | char *str; | ||
1060 | u64 cycles = 0; | ||
1061 | |||
1062 | if (branch_count == 0) { | ||
1063 | if (fp) | ||
1064 | return fprintf(fp, " (calltrace)"); | ||
1065 | |||
1066 | return scnprintf(bf, bfsize, " (calltrace)"); | ||
1067 | } | ||
1068 | |||
1069 | if (iter_count && samples_count) { | ||
1070 | scnprintf(iter_str, sizeof(iter_str), | ||
1071 | ", iterations:%" PRId64 "", | ||
1072 | iter_count / samples_count); | ||
1073 | str = iter_str; | ||
1074 | } else | ||
1075 | str = (char *)null_str; | ||
1076 | |||
1077 | predicted_percent = predicted_count * 100.0 / branch_count; | ||
1078 | cycles = cycles_count / branch_count; | ||
1079 | |||
1080 | if ((predicted_percent >= 100.0) && (abort_count == 0)) { | ||
1081 | if (fp) | ||
1082 | return fprintf(fp, " (cycles:%" PRId64 "%s)", | ||
1083 | cycles, str); | ||
1084 | |||
1085 | return scnprintf(bf, bfsize, " (cycles:%" PRId64 "%s)", | ||
1086 | cycles, str); | ||
1087 | } | ||
1088 | |||
1089 | if ((predicted_percent < 100.0) && (abort_count == 0)) { | ||
1090 | if (fp) | ||
1091 | return fprintf(fp, | ||
1092 | " (predicted:%.1f%%, cycles:%" PRId64 "%s)", | ||
1093 | predicted_percent, cycles, str); | ||
1094 | |||
1095 | return scnprintf(bf, bfsize, | ||
1096 | " (predicted:%.1f%%, cycles:%" PRId64 "%s)", | ||
1097 | predicted_percent, cycles, str); | ||
1098 | } | ||
1099 | |||
1100 | if (fp) | ||
1101 | return fprintf(fp, | ||
1102 | " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)", | ||
1103 | predicted_percent, abort_count, cycles, str); | ||
1104 | |||
1105 | return scnprintf(bf, bfsize, | ||
1106 | " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)", | ||
1107 | predicted_percent, abort_count, cycles, str); | ||
1108 | } | ||
1109 | |||
1110 | int callchain_list_counts__printf_value(struct callchain_node *node, | ||
1111 | struct callchain_list *clist, | ||
1112 | FILE *fp, char *bf, int bfsize) | ||
1113 | { | ||
1114 | u64 branch_count, predicted_count; | ||
1115 | u64 abort_count, cycles_count; | ||
1116 | u64 iter_count = 0, samples_count = 0; | ||
1117 | |||
1118 | branch_count = clist->branch_count; | ||
1119 | predicted_count = clist->predicted_count; | ||
1120 | abort_count = clist->abort_count; | ||
1121 | cycles_count = clist->cycles_count; | ||
1122 | |||
1123 | if (node) { | ||
1124 | struct callchain_list *call; | ||
1125 | |||
1126 | list_for_each_entry(call, &node->val, list) { | ||
1127 | iter_count += call->iter_count; | ||
1128 | samples_count += call->samples_count; | ||
1129 | } | ||
1130 | } | ||
1131 | |||
1132 | return callchain_counts_printf(fp, bf, bfsize, branch_count, | ||
1133 | predicted_count, abort_count, | ||
1134 | cycles_count, iter_count, samples_count); | ||
1135 | } | ||
1136 | |||
942 | static void free_callchain_node(struct callchain_node *node) | 1137 | static void free_callchain_node(struct callchain_node *node) |
943 | { | 1138 | { |
944 | struct callchain_list *list, *tmp; | 1139 | struct callchain_list *list, *tmp; |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 13e75549c440..d9c70dccf06a 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -11,11 +11,7 @@ | |||
11 | 11 | ||
12 | #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace):\n\n" | 12 | #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace):\n\n" |
13 | 13 | ||
14 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
15 | # define RECORD_MODE_HELP HELP_PAD "record_mode:\tcall graph recording mode (fp|dwarf|lbr)\n" | 14 | # define RECORD_MODE_HELP HELP_PAD "record_mode:\tcall graph recording mode (fp|dwarf|lbr)\n" |
16 | #else | ||
17 | # define RECORD_MODE_HELP HELP_PAD "record_mode:\tcall graph recording mode (fp|lbr)\n" | ||
18 | #endif | ||
19 | 15 | ||
20 | #define RECORD_SIZE_HELP \ | 16 | #define RECORD_SIZE_HELP \ |
21 | HELP_PAD "record_size:\tif record_mode is 'dwarf', max size of stack recording (<bytes>)\n" \ | 17 | HELP_PAD "record_size:\tif record_mode is 'dwarf', max size of stack recording (<bytes>)\n" \ |
@@ -115,6 +111,12 @@ struct callchain_list { | |||
115 | bool unfolded; | 111 | bool unfolded; |
116 | bool has_children; | 112 | bool has_children; |
117 | }; | 113 | }; |
114 | u64 branch_count; | ||
115 | u64 predicted_count; | ||
116 | u64 abort_count; | ||
117 | u64 cycles_count; | ||
118 | u64 iter_count; | ||
119 | u64 samples_count; | ||
118 | char *srcline; | 120 | char *srcline; |
119 | struct list_head list; | 121 | struct list_head list; |
120 | }; | 122 | }; |
@@ -129,6 +131,10 @@ struct callchain_cursor_node { | |||
129 | u64 ip; | 131 | u64 ip; |
130 | struct map *map; | 132 | struct map *map; |
131 | struct symbol *sym; | 133 | struct symbol *sym; |
134 | bool branch; | ||
135 | struct branch_flags branch_flags; | ||
136 | int nr_loop_iter; | ||
137 | int samples; | ||
132 | struct callchain_cursor_node *next; | 138 | struct callchain_cursor_node *next; |
133 | }; | 139 | }; |
134 | 140 | ||
@@ -183,7 +189,9 @@ static inline void callchain_cursor_reset(struct callchain_cursor *cursor) | |||
183 | } | 189 | } |
184 | 190 | ||
185 | int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip, | 191 | int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip, |
186 | struct map *map, struct symbol *sym); | 192 | struct map *map, struct symbol *sym, |
193 | bool branch, struct branch_flags *flags, | ||
194 | int nr_loop_iter, int samples); | ||
187 | 195 | ||
188 | /* Close a cursor writing session. Initialize for the reader */ | 196 | /* Close a cursor writing session. Initialize for the reader */ |
189 | static inline void callchain_cursor_commit(struct callchain_cursor *cursor) | 197 | static inline void callchain_cursor_commit(struct callchain_cursor *cursor) |
@@ -261,8 +269,16 @@ char *callchain_node__scnprintf_value(struct callchain_node *node, | |||
261 | int callchain_node__fprintf_value(struct callchain_node *node, | 269 | int callchain_node__fprintf_value(struct callchain_node *node, |
262 | FILE *fp, u64 total); | 270 | FILE *fp, u64 total); |
263 | 271 | ||
272 | int callchain_list_counts__printf_value(struct callchain_node *node, | ||
273 | struct callchain_list *clist, | ||
274 | FILE *fp, char *bf, int bfsize); | ||
275 | |||
264 | void free_callchain(struct callchain_root *root); | 276 | void free_callchain(struct callchain_root *root); |
265 | void decay_callchain(struct callchain_root *root); | 277 | void decay_callchain(struct callchain_root *root); |
266 | int callchain_node__make_parent_list(struct callchain_node *node); | 278 | int callchain_node__make_parent_list(struct callchain_node *node); |
267 | 279 | ||
280 | int callchain_branch_counts(struct callchain_root *root, | ||
281 | u64 *branch_count, u64 *predicted_count, | ||
282 | u64 *abort_count, u64 *cycles_count); | ||
283 | |||
268 | #endif /* __PERF_CALLCHAIN_H */ | 284 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 18dae745034f..3d906dbbef74 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -594,6 +594,19 @@ static int collect_config(const char *var, const char *value, | |||
594 | goto out_free; | 594 | goto out_free; |
595 | } | 595 | } |
596 | 596 | ||
597 | /* perf_config_set can contain both user and system config items. | ||
598 | * So we should know where each value is from. | ||
599 | * The classification would be needed when a particular config file | ||
600 | * is overwrited by setting feature i.e. set_config(). | ||
601 | */ | ||
602 | if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) { | ||
603 | section->from_system_config = true; | ||
604 | item->from_system_config = true; | ||
605 | } else { | ||
606 | section->from_system_config = false; | ||
607 | item->from_system_config = false; | ||
608 | } | ||
609 | |||
597 | ret = set_value(item, value); | 610 | ret = set_value(item, value); |
598 | return ret; | 611 | return ret; |
599 | 612 | ||
@@ -602,6 +615,13 @@ out_free: | |||
602 | return -1; | 615 | return -1; |
603 | } | 616 | } |
604 | 617 | ||
618 | int perf_config_set__collect(struct perf_config_set *set, const char *file_name, | ||
619 | const char *var, const char *value) | ||
620 | { | ||
621 | config_file_name = file_name; | ||
622 | return collect_config(var, value, set); | ||
623 | } | ||
624 | |||
605 | static int perf_config_set__init(struct perf_config_set *set) | 625 | static int perf_config_set__init(struct perf_config_set *set) |
606 | { | 626 | { |
607 | int ret = -1; | 627 | int ret = -1; |
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index 6f813d46045e..1a59a6b43f8b 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h | |||
@@ -7,12 +7,14 @@ | |||
7 | struct perf_config_item { | 7 | struct perf_config_item { |
8 | char *name; | 8 | char *name; |
9 | char *value; | 9 | char *value; |
10 | bool from_system_config; | ||
10 | struct list_head node; | 11 | struct list_head node; |
11 | }; | 12 | }; |
12 | 13 | ||
13 | struct perf_config_section { | 14 | struct perf_config_section { |
14 | char *name; | 15 | char *name; |
15 | struct list_head items; | 16 | struct list_head items; |
17 | bool from_system_config; | ||
16 | struct list_head node; | 18 | struct list_head node; |
17 | }; | 19 | }; |
18 | 20 | ||
@@ -33,6 +35,8 @@ const char *perf_etc_perfconfig(void); | |||
33 | 35 | ||
34 | struct perf_config_set *perf_config_set__new(void); | 36 | struct perf_config_set *perf_config_set__new(void); |
35 | void perf_config_set__delete(struct perf_config_set *set); | 37 | void perf_config_set__delete(struct perf_config_set *set); |
38 | int perf_config_set__collect(struct perf_config_set *set, const char *file_name, | ||
39 | const char *var, const char *value); | ||
36 | void perf_config__init(void); | 40 | void perf_config__init(void); |
37 | void perf_config__exit(void); | 41 | void perf_config__exit(void); |
38 | void perf_config__refresh(void); | 42 | void perf_config__refresh(void); |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index df85b9efd80f..9b33bef54581 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -1616,7 +1616,11 @@ static int add_callchain_ip(struct thread *thread, | |||
1616 | struct symbol **parent, | 1616 | struct symbol **parent, |
1617 | struct addr_location *root_al, | 1617 | struct addr_location *root_al, |
1618 | u8 *cpumode, | 1618 | u8 *cpumode, |
1619 | u64 ip) | 1619 | u64 ip, |
1620 | bool branch, | ||
1621 | struct branch_flags *flags, | ||
1622 | int nr_loop_iter, | ||
1623 | int samples) | ||
1620 | { | 1624 | { |
1621 | struct addr_location al; | 1625 | struct addr_location al; |
1622 | 1626 | ||
@@ -1668,7 +1672,8 @@ static int add_callchain_ip(struct thread *thread, | |||
1668 | 1672 | ||
1669 | if (symbol_conf.hide_unresolved && al.sym == NULL) | 1673 | if (symbol_conf.hide_unresolved && al.sym == NULL) |
1670 | return 0; | 1674 | return 0; |
1671 | return callchain_cursor_append(cursor, al.addr, al.map, al.sym); | 1675 | return callchain_cursor_append(cursor, al.addr, al.map, al.sym, |
1676 | branch, flags, nr_loop_iter, samples); | ||
1672 | } | 1677 | } |
1673 | 1678 | ||
1674 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | 1679 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, |
@@ -1757,7 +1762,9 @@ static int resolve_lbr_callchain_sample(struct thread *thread, | |||
1757 | /* LBR only affects the user callchain */ | 1762 | /* LBR only affects the user callchain */ |
1758 | if (i != chain_nr) { | 1763 | if (i != chain_nr) { |
1759 | struct branch_stack *lbr_stack = sample->branch_stack; | 1764 | struct branch_stack *lbr_stack = sample->branch_stack; |
1760 | int lbr_nr = lbr_stack->nr, j; | 1765 | int lbr_nr = lbr_stack->nr, j, k; |
1766 | bool branch; | ||
1767 | struct branch_flags *flags; | ||
1761 | /* | 1768 | /* |
1762 | * LBR callstack can only get user call chain. | 1769 | * LBR callstack can only get user call chain. |
1763 | * The mix_chain_nr is kernel call chain | 1770 | * The mix_chain_nr is kernel call chain |
@@ -1772,23 +1779,41 @@ static int resolve_lbr_callchain_sample(struct thread *thread, | |||
1772 | 1779 | ||
1773 | for (j = 0; j < mix_chain_nr; j++) { | 1780 | for (j = 0; j < mix_chain_nr; j++) { |
1774 | int err; | 1781 | int err; |
1782 | branch = false; | ||
1783 | flags = NULL; | ||
1784 | |||
1775 | if (callchain_param.order == ORDER_CALLEE) { | 1785 | if (callchain_param.order == ORDER_CALLEE) { |
1776 | if (j < i + 1) | 1786 | if (j < i + 1) |
1777 | ip = chain->ips[j]; | 1787 | ip = chain->ips[j]; |
1778 | else if (j > i + 1) | 1788 | else if (j > i + 1) { |
1779 | ip = lbr_stack->entries[j - i - 2].from; | 1789 | k = j - i - 2; |
1780 | else | 1790 | ip = lbr_stack->entries[k].from; |
1791 | branch = true; | ||
1792 | flags = &lbr_stack->entries[k].flags; | ||
1793 | } else { | ||
1781 | ip = lbr_stack->entries[0].to; | 1794 | ip = lbr_stack->entries[0].to; |
1795 | branch = true; | ||
1796 | flags = &lbr_stack->entries[0].flags; | ||
1797 | } | ||
1782 | } else { | 1798 | } else { |
1783 | if (j < lbr_nr) | 1799 | if (j < lbr_nr) { |
1784 | ip = lbr_stack->entries[lbr_nr - j - 1].from; | 1800 | k = lbr_nr - j - 1; |
1801 | ip = lbr_stack->entries[k].from; | ||
1802 | branch = true; | ||
1803 | flags = &lbr_stack->entries[k].flags; | ||
1804 | } | ||
1785 | else if (j > lbr_nr) | 1805 | else if (j > lbr_nr) |
1786 | ip = chain->ips[i + 1 - (j - lbr_nr)]; | 1806 | ip = chain->ips[i + 1 - (j - lbr_nr)]; |
1787 | else | 1807 | else { |
1788 | ip = lbr_stack->entries[0].to; | 1808 | ip = lbr_stack->entries[0].to; |
1809 | branch = true; | ||
1810 | flags = &lbr_stack->entries[0].flags; | ||
1811 | } | ||
1789 | } | 1812 | } |
1790 | 1813 | ||
1791 | err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); | 1814 | err = add_callchain_ip(thread, cursor, parent, |
1815 | root_al, &cpumode, ip, | ||
1816 | branch, flags, 0, 0); | ||
1792 | if (err) | 1817 | if (err) |
1793 | return (err < 0) ? err : 0; | 1818 | return (err < 0) ? err : 0; |
1794 | } | 1819 | } |
@@ -1813,6 +1838,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1813 | int i, j, err, nr_entries; | 1838 | int i, j, err, nr_entries; |
1814 | int skip_idx = -1; | 1839 | int skip_idx = -1; |
1815 | int first_call = 0; | 1840 | int first_call = 0; |
1841 | int nr_loop_iter; | ||
1816 | 1842 | ||
1817 | if (perf_evsel__has_branch_callstack(evsel)) { | 1843 | if (perf_evsel__has_branch_callstack(evsel)) { |
1818 | err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, | 1844 | err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, |
@@ -1868,14 +1894,37 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1868 | be[i] = branch->entries[branch->nr - i - 1]; | 1894 | be[i] = branch->entries[branch->nr - i - 1]; |
1869 | } | 1895 | } |
1870 | 1896 | ||
1897 | nr_loop_iter = nr; | ||
1871 | nr = remove_loops(be, nr); | 1898 | nr = remove_loops(be, nr); |
1872 | 1899 | ||
1900 | /* | ||
1901 | * Get the number of iterations. | ||
1902 | * It's only approximation, but good enough in practice. | ||
1903 | */ | ||
1904 | if (nr_loop_iter > nr) | ||
1905 | nr_loop_iter = nr_loop_iter - nr + 1; | ||
1906 | else | ||
1907 | nr_loop_iter = 0; | ||
1908 | |||
1873 | for (i = 0; i < nr; i++) { | 1909 | for (i = 0; i < nr; i++) { |
1874 | err = add_callchain_ip(thread, cursor, parent, root_al, | 1910 | if (i == nr - 1) |
1875 | NULL, be[i].to); | 1911 | err = add_callchain_ip(thread, cursor, parent, |
1912 | root_al, | ||
1913 | NULL, be[i].to, | ||
1914 | true, &be[i].flags, | ||
1915 | nr_loop_iter, 1); | ||
1916 | else | ||
1917 | err = add_callchain_ip(thread, cursor, parent, | ||
1918 | root_al, | ||
1919 | NULL, be[i].to, | ||
1920 | true, &be[i].flags, | ||
1921 | 0, 0); | ||
1922 | |||
1876 | if (!err) | 1923 | if (!err) |
1877 | err = add_callchain_ip(thread, cursor, parent, root_al, | 1924 | err = add_callchain_ip(thread, cursor, parent, root_al, |
1878 | NULL, be[i].from); | 1925 | NULL, be[i].from, |
1926 | true, &be[i].flags, | ||
1927 | 0, 0); | ||
1879 | if (err == -EINVAL) | 1928 | if (err == -EINVAL) |
1880 | break; | 1929 | break; |
1881 | if (err) | 1930 | if (err) |
@@ -1903,7 +1952,9 @@ check_calls: | |||
1903 | if (ip < PERF_CONTEXT_MAX) | 1952 | if (ip < PERF_CONTEXT_MAX) |
1904 | ++nr_entries; | 1953 | ++nr_entries; |
1905 | 1954 | ||
1906 | err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); | 1955 | err = add_callchain_ip(thread, cursor, parent, |
1956 | root_al, &cpumode, ip, | ||
1957 | false, NULL, 0, 0); | ||
1907 | 1958 | ||
1908 | if (err) | 1959 | if (err) |
1909 | return (err < 0) ? err : 0; | 1960 | return (err < 0) ? err : 0; |
@@ -1919,7 +1970,8 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) | |||
1919 | if (symbol_conf.hide_unresolved && entry->sym == NULL) | 1970 | if (symbol_conf.hide_unresolved && entry->sym == NULL) |
1920 | return 0; | 1971 | return 0; |
1921 | return callchain_cursor_append(cursor, entry->ip, | 1972 | return callchain_cursor_append(cursor, entry->ip, |
1922 | entry->map, entry->sym); | 1973 | entry->map, entry->sym, |
1974 | false, NULL, 0, 0); | ||
1923 | } | 1975 | } |
1924 | 1976 | ||
1925 | static int thread__resolve_callchain_unwind(struct thread *thread, | 1977 | static int thread__resolve_callchain_unwind(struct thread *thread, |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index d964844eb314..2d0a905c879a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -100,6 +100,7 @@ struct symbol_conf { | |||
100 | show_total_period, | 100 | show_total_period, |
101 | use_callchain, | 101 | use_callchain, |
102 | cumulate_callchain, | 102 | cumulate_callchain, |
103 | show_branchflag_count, | ||
103 | exclude_other, | 104 | exclude_other, |
104 | show_cpu_utilization, | 105 | show_cpu_utilization, |
105 | initialized, | 106 | initialized, |