aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-11 21:14:31 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-11 21:14:31 -0500
commit090f8ccba37034cec5a5972a70abeaae7eb0222b (patch)
tree0b7cf8a4bb94601816399acfb336835fbf309a2a /tools
parentaefb058b0c27dafb15072406fbfd92d2ac2c8790 (diff)
parentcc1b39dbf9f55a438e8a21a694394c20e6a17129 (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "Lots of activity: 211 files changed, 8328 insertions(+), 4116 deletions(-) most of it on the tooling side. Main changes: * ftrace enhancements and fixes from Steve Rostedt. * uprobes fixes, cleanups and preparation for the ARM port from Oleg Nesterov. * UAPI fixes, from David Howels - prepares the arch/x86 UAPI transition * Separate perf tests into multiple objects, one per test, from Jiri Olsa. * Make hardware event translations available in sysfs, from Jiri Olsa. * Fixes to /proc/pid/maps parsing, preparatory to supporting data maps, from Namhyung Kim * Implement ui_progress for GTK, from Namhyung Kim * Add framework for automated perf_event_attr tests, where tools with different command line options will be run from a 'perf test', via python glue, and the perf syscall will be intercepted to verify that the perf_event_attr fields set by the tool are those expected, from Jiri Olsa * Add a 'link' method for hists, so that we can have the leader with buckets for all the entries in all the hists. This new method is now used in the default 'diff' output, making the sum of the 'baseline' column be 100%, eliminating blind spots. * libtraceevent fixes for compiler warnings trying to make perf it build on some distros, like fedora 14, 32-bit, some of the warnings really pointed to real bugs. * Add a browser for 'perf script' and make it available from the report and annotate browsers. It does filtering to find the scripts that handle events found in the perf.data file used. From Feng Tang * perf inject changes to allow showing where a task sleeps, from Andrew Vagin. * Makefile improvements from Namhyung Kim. * Add --pre and --post command hooks in 'stat', from Peter Zijlstra. * Don't stop synthesizing threads when one vanishes, this is for the existing threads when we start a tool like trace. * Use sched:sched_stat_runtime to provide a thread summary, this produces the same output as the 'trace summary' subcommand of tglx's original "trace" tool. * Support interrupted syscalls in 'trace' * Add an event duration column and filter in 'trace'. * There are references to the man pages in some tools, so try to build Documentation when installing, warning the user if that is not possible, from Borislav Petkov. * Give user better message if precise is not supported, from David Ahern. * Try to find cross-built objdump path by using the session environment information in the perf.data file header, from Irina Tirdea, original patch and idea by Namhyung Kim. * Diplays more output on features check for make V=1, so that one can figure out what is happening by looking at gcc output, etc. From Jiri Olsa. * Add on_exit implementation for systems without one, e.g. Android, from Bernhard Rosenkraenzer. * Only process events for vcpus of interest, helps handling large number of events, from David Ahern. * Cross compilation fixes for Android, from Irina Tirdea. * Add documentation on compiling for Android, from Irina Tirdea. * perf diff improvements from Jiri Olsa. * Target (task/user/cpu/syswide) handling improvements, from Namhyung Kim. * Add support in 'trace' for tracing workload given by command line, from Namhyung Kim. * ... and much more." * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (194 commits) uprobes: Use percpu_rw_semaphore to fix register/unregister vs dup_mmap() race perf evsel: Introduce is_group_member method perf powerpc: Use uapi/unistd.h to fix build error tools: Pass the target in descend tools: Honour the O= flag when tool build called from a higher Makefile tools: Define a Makefile function to do subdir processing perf ui: Always compile browser setup code perf ui: Add ui_progress__finish() perf ui gtk: Implement ui_progress functions perf ui: Introduce generic ui_progress helper perf ui tui: Move progress.c under ui/tui directory perf tools: Add basic event modifier sanity check perf tools: Omit group members from perf_evlist__disable/enable perf tools: Ensure single disable call per event in record comand perf tools: Fix 'disabled' attribute config for record command perf tools: Fix attributes for '{}' defined event groups perf tools: Use sscanf for parsing /proc/pid/maps perf tools: Add gtk.<command> config option for launching GTK browser perf tools: Fix compile error on NO_NEWT=1 build perf hists: Initialize all of he->stat with zeroes ...
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/traceevent/Makefile2
-rw-r--r--tools/lib/traceevent/event-parse.c22
-rw-r--r--tools/perf/Documentation/Makefile31
-rw-r--r--tools/perf/Documentation/android.txt78
-rw-r--r--tools/perf/Documentation/perf-diff.txt60
-rw-r--r--tools/perf/Documentation/perf-inject.txt11
-rw-r--r--tools/perf/Documentation/perf-stat.txt5
-rw-r--r--tools/perf/Documentation/perf-trace.txt6
-rw-r--r--tools/perf/Makefile174
-rw-r--r--tools/perf/arch/common.c211
-rw-r--r--tools/perf/arch/common.h10
-rw-r--r--tools/perf/builtin-annotate.c17
-rw-r--r--tools/perf/builtin-buildid-cache.c1
-rw-r--r--tools/perf/builtin-buildid-list.c6
-rw-r--r--tools/perf/builtin-diff.c437
-rw-r--r--tools/perf/builtin-evlist.c5
-rw-r--r--tools/perf/builtin-inject.c195
-rw-r--r--tools/perf/builtin-kmem.c5
-rw-r--r--tools/perf/builtin-kvm.c35
-rw-r--r--tools/perf/builtin-lock.c2
-rw-r--r--tools/perf/builtin-record.c66
-rw-r--r--tools/perf/builtin-report.c23
-rw-r--r--tools/perf/builtin-sched.c8
-rw-r--r--tools/perf/builtin-script.c87
-rw-r--r--tools/perf/builtin-stat.c54
-rw-r--r--tools/perf/builtin-test.c1547
-rw-r--r--tools/perf/builtin-timechart.c5
-rw-r--r--tools/perf/builtin-top.c17
-rw-r--r--tools/perf/builtin-trace.c403
-rw-r--r--tools/perf/config/feature-tests.mak25
-rw-r--r--tools/perf/config/utilities.mak10
-rw-r--r--tools/perf/perf.c20
-rw-r--r--tools/perf/perf.h18
-rw-r--r--tools/perf/tests/attr.c175
-rw-r--r--tools/perf/tests/attr.py322
-rw-r--r--tools/perf/tests/attr/README64
-rw-r--r--tools/perf/tests/attr/base-record39
-rw-r--r--tools/perf/tests/attr/base-stat39
-rw-r--r--tools/perf/tests/attr/test-record-basic5
-rw-r--r--tools/perf/tests/attr/test-record-branch-any8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-any8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-any_call8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-any_ret8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-hv8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-ind_call8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-k8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-u8
-rw-r--r--tools/perf/tests/attr/test-record-count8
-rw-r--r--tools/perf/tests/attr/test-record-data8
-rw-r--r--tools/perf/tests/attr/test-record-freq6
-rw-r--r--tools/perf/tests/attr/test-record-graph-default6
-rw-r--r--tools/perf/tests/attr/test-record-graph-dwarf10
-rw-r--r--tools/perf/tests/attr/test-record-graph-fp6
-rw-r--r--tools/perf/tests/attr/test-record-group18
-rw-r--r--tools/perf/tests/attr/test-record-group119
-rw-r--r--tools/perf/tests/attr/test-record-no-delay9
-rw-r--r--tools/perf/tests/attr/test-record-no-inherit7
-rw-r--r--tools/perf/tests/attr/test-record-no-samples6
-rw-r--r--tools/perf/tests/attr/test-record-period7
-rw-r--r--tools/perf/tests/attr/test-record-raw7
-rw-r--r--tools/perf/tests/attr/test-stat-basic6
-rw-r--r--tools/perf/tests/attr/test-stat-default64
-rw-r--r--tools/perf/tests/attr/test-stat-detailed-1101
-rw-r--r--tools/perf/tests/attr/test-stat-detailed-2155
-rw-r--r--tools/perf/tests/attr/test-stat-detailed-3173
-rw-r--r--tools/perf/tests/attr/test-stat-group15
-rw-r--r--tools/perf/tests/attr/test-stat-group115
-rw-r--r--tools/perf/tests/attr/test-stat-no-inherit7
-rw-r--r--tools/perf/tests/builtin-test.c173
-rw-r--r--tools/perf/tests/dso-data.c (renamed from tools/perf/util/dso-test-data.c)8
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c114
-rw-r--r--tools/perf/tests/evsel-tp-sched.c84
-rw-r--r--tools/perf/tests/mmap-basic.c162
-rw-r--r--tools/perf/tests/open-syscall-all-cpus.c120
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c117
-rw-r--r--tools/perf/tests/open-syscall.c66
-rw-r--r--tools/perf/tests/parse-events.c (renamed from tools/perf/util/parse-events-test.c)91
-rw-r--r--tools/perf/tests/perf-record.c312
-rw-r--r--tools/perf/tests/pmu.c178
-rw-r--r--tools/perf/tests/rdpmc.c175
-rw-r--r--tools/perf/tests/tests.h22
-rw-r--r--tools/perf/tests/util.c30
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c230
-rw-r--r--tools/perf/ui/browsers/annotate.c45
-rw-r--r--tools/perf/ui/browsers/hists.c97
-rw-r--r--tools/perf/ui/browsers/scripts.c189
-rw-r--r--tools/perf/ui/gtk/browser.c4
-rw-r--r--tools/perf/ui/gtk/gtk.h1
-rw-r--r--tools/perf/ui/gtk/progress.c59
-rw-r--r--tools/perf/ui/gtk/setup.c2
-rw-r--r--tools/perf/ui/gtk/util.c11
-rw-r--r--tools/perf/ui/hist.c138
-rw-r--r--tools/perf/ui/progress.c44
-rw-r--r--tools/perf/ui/progress.h10
-rw-r--r--tools/perf/ui/stdio/hist.c2
-rw-r--r--tools/perf/ui/tui/progress.c42
-rw-r--r--tools/perf/ui/tui/setup.c1
-rw-r--r--tools/perf/ui/ui.h28
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN14
-rw-r--r--tools/perf/util/annotate.c72
-rw-r--r--tools/perf/util/annotate.h10
-rw-r--r--tools/perf/util/build-id.c27
-rw-r--r--tools/perf/util/build-id.h11
-rw-r--r--tools/perf/util/cache.h39
-rw-r--r--tools/perf/util/debug.h1
-rw-r--r--tools/perf/util/dso.c595
-rw-r--r--tools/perf/util/dso.h148
-rw-r--r--tools/perf/util/event.c302
-rw-r--r--tools/perf/util/event.h9
-rw-r--r--tools/perf/util/evlist.c13
-rw-r--r--tools/perf/util/evsel.c52
-rw-r--r--tools/perf/util/evsel.h8
-rw-r--r--tools/perf/util/header.c11
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/hist.c99
-rw-r--r--tools/perf/util/hist.h49
-rw-r--r--tools/perf/util/machine.c464
-rw-r--r--tools/perf/util/machine.h148
-rw-r--r--tools/perf/util/map.c182
-rw-r--r--tools/perf/util/map.h93
-rw-r--r--tools/perf/util/parse-events.c54
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/parse-events.l4
-rw-r--r--tools/perf/util/parse-events.y18
-rw-r--r--tools/perf/util/pmu.c192
-rw-r--r--tools/perf/util/pmu.h4
-rw-r--r--tools/perf/util/pstack.c46
-rw-r--r--tools/perf/util/python.c2
-rw-r--r--tools/perf/util/rblist.c4
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c5
-rw-r--r--tools/perf/util/session.h5
-rw-r--r--tools/perf/util/sort.h45
-rw-r--r--tools/perf/util/string.c18
-rw-r--r--tools/perf/util/symbol.c658
-rw-r--r--tools/perf/util/symbol.h162
-rw-r--r--tools/perf/util/thread.c41
-rw-r--r--tools/perf/util/thread.h2
-rw-r--r--tools/perf/util/trace-event-read.c2
-rw-r--r--tools/perf/util/util.c35
-rw-r--r--tools/perf/util/util.h8
141 files changed, 7570 insertions, 3599 deletions
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index 04d959fa0226..a20e32033431 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -253,7 +253,7 @@ all_deps := $(all_objs:%.o=.%.d)
253# let .d file also depends on the source and header files 253# let .d file also depends on the source and header files
254define check_deps 254define check_deps
255 @set -e; $(RM) $@; \ 255 @set -e; $(RM) $@; \
256 $(CC) -M $(CFLAGS) $< > $@.$$$$; \ 256 $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
257 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ 257 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
258 $(RM) $@.$$$$ 258 $(RM) $@.$$$$
259endef 259endef
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index f2989c525e48..5a824e355d04 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -174,7 +174,7 @@ static int cmdline_init(struct pevent *pevent)
174 return 0; 174 return 0;
175} 175}
176 176
177static char *find_cmdline(struct pevent *pevent, int pid) 177static const char *find_cmdline(struct pevent *pevent, int pid)
178{ 178{
179 const struct cmdline *comm; 179 const struct cmdline *comm;
180 struct cmdline key; 180 struct cmdline key;
@@ -2637,7 +2637,7 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
2637 struct print_arg *farg; 2637 struct print_arg *farg;
2638 enum event_type type; 2638 enum event_type type;
2639 char *token; 2639 char *token;
2640 char *test; 2640 const char *test;
2641 int i; 2641 int i;
2642 2642
2643 arg->type = PRINT_FUNC; 2643 arg->type = PRINT_FUNC;
@@ -3889,7 +3889,7 @@ static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
3889 struct event_format *event, struct print_arg *arg) 3889 struct event_format *event, struct print_arg *arg)
3890{ 3890{
3891 unsigned char *buf; 3891 unsigned char *buf;
3892 char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"; 3892 const char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x";
3893 3893
3894 if (arg->type == PRINT_FUNC) { 3894 if (arg->type == PRINT_FUNC) {
3895 process_defined_func(s, data, size, event, arg); 3895 process_defined_func(s, data, size, event, arg);
@@ -3931,7 +3931,8 @@ static int is_printable_array(char *p, unsigned int len)
3931 return 1; 3931 return 1;
3932} 3932}
3933 3933
3934static void print_event_fields(struct trace_seq *s, void *data, int size, 3934static void print_event_fields(struct trace_seq *s, void *data,
3935 int size __maybe_unused,
3935 struct event_format *event) 3936 struct event_format *event)
3936{ 3937{
3937 struct format_field *field; 3938 struct format_field *field;
@@ -4408,7 +4409,7 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
4408void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 4409void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
4409 struct pevent_record *record) 4410 struct pevent_record *record)
4410{ 4411{
4411 static char *spaces = " "; /* 20 spaces */ 4412 static const char *spaces = " "; /* 20 spaces */
4412 struct event_format *event; 4413 struct event_format *event;
4413 unsigned long secs; 4414 unsigned long secs;
4414 unsigned long usecs; 4415 unsigned long usecs;
@@ -5070,8 +5071,8 @@ static const char * const pevent_error_str[] = {
5070}; 5071};
5071#undef _PE 5072#undef _PE
5072 5073
5073int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, 5074int pevent_strerror(struct pevent *pevent __maybe_unused,
5074 char *buf, size_t buflen) 5075 enum pevent_errno errnum, char *buf, size_t buflen)
5075{ 5076{
5076 int idx; 5077 int idx;
5077 const char *msg; 5078 const char *msg;
@@ -5100,6 +5101,7 @@ int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
5100 case PEVENT_ERRNO__READ_FORMAT_FAILED: 5101 case PEVENT_ERRNO__READ_FORMAT_FAILED:
5101 case PEVENT_ERRNO__READ_PRINT_FAILED: 5102 case PEVENT_ERRNO__READ_PRINT_FAILED:
5102 case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED: 5103 case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED:
5104 case PEVENT_ERRNO__INVALID_ARG_TYPE:
5103 snprintf(buf, buflen, "%s", msg); 5105 snprintf(buf, buflen, "%s", msg);
5104 break; 5106 break;
5105 5107
@@ -5362,7 +5364,7 @@ int pevent_register_print_function(struct pevent *pevent,
5362 if (type == PEVENT_FUNC_ARG_VOID) 5364 if (type == PEVENT_FUNC_ARG_VOID)
5363 break; 5365 break;
5364 5366
5365 if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) { 5367 if (type >= PEVENT_FUNC_ARG_MAX_TYPES) {
5366 do_warning("Invalid argument type %d", type); 5368 do_warning("Invalid argument type %d", type);
5367 ret = PEVENT_ERRNO__INVALID_ARG_TYPE; 5369 ret = PEVENT_ERRNO__INVALID_ARG_TYPE;
5368 goto out_free; 5370 goto out_free;
@@ -5560,7 +5562,7 @@ void pevent_free(struct pevent *pevent)
5560 } 5562 }
5561 5563
5562 if (pevent->func_map) { 5564 if (pevent->func_map) {
5563 for (i = 0; i < pevent->func_count; i++) { 5565 for (i = 0; i < (int)pevent->func_count; i++) {
5564 free(pevent->func_map[i].func); 5566 free(pevent->func_map[i].func);
5565 free(pevent->func_map[i].mod); 5567 free(pevent->func_map[i].mod);
5566 } 5568 }
@@ -5582,7 +5584,7 @@ void pevent_free(struct pevent *pevent)
5582 } 5584 }
5583 5585
5584 if (pevent->printk_map) { 5586 if (pevent->printk_map) {
5585 for (i = 0; i < pevent->printk_count; i++) 5587 for (i = 0; i < (int)pevent->printk_count; i++)
5586 free(pevent->printk_map[i].printk); 5588 free(pevent->printk_map[i].printk);
5587 free(pevent->printk_map); 5589 free(pevent->printk_map);
5588 } 5590 }
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index 9f2e44f2b17a..ef6d22e879eb 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -1,3 +1,5 @@
1include ../config/utilities.mak
2
1OUTPUT := ./ 3OUTPUT := ./
2ifeq ("$(origin O)", "command line") 4ifeq ("$(origin O)", "command line")
3 ifneq ($(O),) 5 ifneq ($(O),)
@@ -64,6 +66,7 @@ MAKEINFO=makeinfo
64INSTALL_INFO=install-info 66INSTALL_INFO=install-info
65DOCBOOK2X_TEXI=docbook2x-texi 67DOCBOOK2X_TEXI=docbook2x-texi
66DBLATEX=dblatex 68DBLATEX=dblatex
69XMLTO=xmlto
67ifndef PERL_PATH 70ifndef PERL_PATH
68 PERL_PATH = /usr/bin/perl 71 PERL_PATH = /usr/bin/perl
69endif 72endif
@@ -71,6 +74,16 @@ endif
71-include ../config.mak.autogen 74-include ../config.mak.autogen
72-include ../config.mak 75-include ../config.mak
73 76
77_tmp_tool_path := $(call get-executable,$(ASCIIDOC))
78ifeq ($(_tmp_tool_path),)
79 missing_tools = $(ASCIIDOC)
80endif
81
82_tmp_tool_path := $(call get-executable,$(XMLTO))
83ifeq ($(_tmp_tool_path),)
84 missing_tools += $(XMLTO)
85endif
86
74# 87#
75# For asciidoc ... 88# For asciidoc ...
76# -7.1.2, no extra settings are needed. 89# -7.1.2, no extra settings are needed.
@@ -170,7 +183,12 @@ pdf: $(OUTPUT)user-manual.pdf
170 183
171install: install-man 184install: install-man
172 185
173install-man: man 186check-man-tools:
187ifdef missing_tools
188 $(error "You need to install $(missing_tools) for man pages")
189endif
190
191do-install-man: man
174 $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir) 192 $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
175# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir) 193# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir)
176# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir) 194# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
@@ -178,6 +196,15 @@ install-man: man
178# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir) 196# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir)
179# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir) 197# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
180 198
199install-man: check-man-tools man
200
201try-install-man:
202ifdef missing_tools
203 $(warning Please install $(missing_tools) to have the man pages installed)
204else
205 $(MAKE) do-install-man
206endif
207
181install-info: info 208install-info: info
182 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir) 209 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
183 $(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir) 210 $(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir)
@@ -246,7 +273,7 @@ $(MAN_HTML): $(OUTPUT)%.html : %.txt
246 273
247$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml 274$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
248 $(QUIET_XMLTO)$(RM) $@ && \ 275 $(QUIET_XMLTO)$(RM) $@ && \
249 xmlto -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< 276 $(XMLTO) -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
250 277
251$(OUTPUT)%.xml : %.txt 278$(OUTPUT)%.xml : %.txt
252 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ 279 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
diff --git a/tools/perf/Documentation/android.txt b/tools/perf/Documentation/android.txt
new file mode 100644
index 000000000000..8484c3a04a6a
--- /dev/null
+++ b/tools/perf/Documentation/android.txt
@@ -0,0 +1,78 @@
1How to compile perf for Android
2=========================================
3
4I. Set the Android NDK environment
5------------------------------------------------
6
7(a). Use the Android NDK
8------------------------------------------------
91. You need to download and install the Android Native Development Kit (NDK).
10Set the NDK variable to point to the path where you installed the NDK:
11 export NDK=/path/to/android-ndk
12
132. Set cross-compiling environment variables for NDK toolchain and sysroot.
14For arm:
15 export NDK_TOOLCHAIN=${NDK}/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-
16 export NDK_SYSROOT=${NDK}/platforms/android-9/arch-arm
17For x86:
18 export NDK_TOOLCHAIN=${NDK}/toolchains/x86-4.6/prebuilt/linux-x86/bin/i686-linux-android-
19 export NDK_SYSROOT=${NDK}/platforms/android-9/arch-x86
20
21This method is not working for Android NDK versions up to Revision 8b.
22perf uses some bionic enhancements that are not included in these NDK versions.
23You can use method (b) described below instead.
24
25(b). Use the Android source tree
26-----------------------------------------------
271. Download the master branch of the Android source tree.
28Set the environment for the target you want using:
29 source build/envsetup.sh
30 lunch
31
322. Build your own NDK sysroot to contain latest bionic changes and set the
33NDK sysroot environment variable.
34 cd ${ANDROID_BUILD_TOP}/ndk
35For arm:
36 ./build/tools/build-ndk-sysroot.sh --abi=arm
37 export NDK_SYSROOT=${ANDROID_BUILD_TOP}/ndk/build/platforms/android-3/arch-arm
38For x86:
39 ./build/tools/build-ndk-sysroot.sh --abi=x86
40 export NDK_SYSROOT=${ANDROID_BUILD_TOP}/ndk/build/platforms/android-3/arch-x86
41
423. Set the NDK toolchain environment variable.
43For arm:
44 export NDK_TOOLCHAIN=${ANDROID_TOOLCHAIN}/arm-linux-androideabi-
45For x86:
46 export NDK_TOOLCHAIN=${ANDROID_TOOLCHAIN}/i686-linux-android-
47
48II. Compile perf for Android
49------------------------------------------------
50You need to run make with the NDK toolchain and sysroot defined above:
51For arm:
52 make ARCH=arm CROSS_COMPILE=${NDK_TOOLCHAIN} CFLAGS="--sysroot=${NDK_SYSROOT}"
53For x86:
54 make ARCH=x86 CROSS_COMPILE=${NDK_TOOLCHAIN} CFLAGS="--sysroot=${NDK_SYSROOT}"
55
56III. Install perf
57-----------------------------------------------
58You need to connect to your Android device/emulator using adb.
59Install perf using:
60 adb push perf /data/perf
61
62If you also want to use perf-archive you need busybox tools for Android.
63For installing perf-archive, you first need to replace #!/bin/bash with #!/system/bin/sh:
64 sed 's/#!\/bin\/bash/#!\/system\/bin\/sh/g' perf-archive >> /tmp/perf-archive
65 chmod +x /tmp/perf-archive
66 adb push /tmp/perf-archive /data/perf-archive
67
68IV. Environment settings for running perf
69------------------------------------------------
70Some perf features need environment variables to run properly.
71You need to set these before running perf on the target:
72 adb shell
73 # PERF_PAGER=cat
74
75IV. Run perf
76------------------------------------------------
77Run perf on your device/emulator to which you previously connected using adb:
78 # ./data/perf
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index ab7f667de1b1..194f37d635df 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -72,6 +72,66 @@ OPTIONS
72--symfs=<directory>:: 72--symfs=<directory>::
73 Look for files with symbols relative to this directory. 73 Look for files with symbols relative to this directory.
74 74
75-b::
76--baseline-only::
77 Show only items with match in baseline.
78
79-c::
80--compute::
81 Differential computation selection - delta,ratio,wdiff (default is delta).
82 If '+' is specified as a first character, the output is sorted based
83 on the computation results.
84 See COMPARISON METHODS section for more info.
85
86-p::
87--period::
88 Show period values for both compared hist entries.
89
90-F::
91--formula::
92 Show formula for given computation.
93
94COMPARISON METHODS
95------------------
96delta
97~~~~~
98If specified the 'Delta' column is displayed with value 'd' computed as:
99
100 d = A->period_percent - B->period_percent
101
102with:
103 - A/B being matching hist entry from first/second file specified
104 (or perf.data/perf.data.old) respectively.
105
106 - period_percent being the % of the hist entry period value within
107 single data file
108
109ratio
110~~~~~
111If specified the 'Ratio' column is displayed with value 'r' computed as:
112
113 r = A->period / B->period
114
115with:
116 - A/B being matching hist entry from first/second file specified
117 (or perf.data/perf.data.old) respectively.
118
119 - period being the hist entry period value
120
121wdiff
122~~~~~
123If specified the 'Weighted diff' column is displayed with value 'd' computed as:
124
125 d = B->period * WEIGHT-A - A->period * WEIGHT-B
126
127 - A/B being matching hist entry from first/second file specified
128 (or perf.data/perf.data.old) respectively.
129
130 - period being the hist entry period value
131
132 - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
133 behind ':' separator like '-c wdiff:1,2'.
134
75SEE ALSO 135SEE ALSO
76-------- 136--------
77linkperf:perf-record[1] 137linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index 025630d43cd2..a00a34276c54 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -29,6 +29,17 @@ OPTIONS
29-v:: 29-v::
30--verbose:: 30--verbose::
31 Be more verbose. 31 Be more verbose.
32-i::
33--input=::
34 Input file name. (default: stdin)
35-o::
36--output=::
37 Output file name. (default: stdout)
38-s::
39--sched-stat::
40 Merge sched_stat and sched_switch for getting events where and how long
41 tasks slept. sched_switch contains a callchain where a task slept and
42 sched_stat contains a timeslice how long a task slept.
32 43
33SEE ALSO 44SEE ALSO
34-------- 45--------
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 2fa173b51970..cf0c3107e06e 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -108,6 +108,11 @@ with it. --append may be used here. Examples:
108 3>results perf stat --log-fd 3 -- $cmd 108 3>results perf stat --log-fd 3 -- $cmd
109 3>>results perf stat --log-fd 3 --append -- $cmd 109 3>>results perf stat --log-fd 3 --append -- $cmd
110 110
111--pre::
112--post::
113 Pre and post measurement hooks, e.g.:
114
115perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage
111 116
112 117
113EXAMPLES 118EXAMPLES
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 3a2ae37310a9..68718ccdd178 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -48,6 +48,12 @@ comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-
48In per-thread mode with inheritance mode on (default), Events are captured only when 48In per-thread mode with inheritance mode on (default), Events are captured only when
49the thread executes on the designated CPUs. Default is to monitor all CPUs. 49the thread executes on the designated CPUs. Default is to monitor all CPUs.
50 50
51--duration:
52 Show only events that had a duration greater than N.M ms.
53
54--sched:
55 Accrue thread runtime and provide a summary at the end of the session.
56
51SEE ALSO 57SEE ALSO
52-------- 58--------
53linkperf:perf-record[1], linkperf:perf-script[1] 59linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 0a619af5be43..891bc77bdb2c 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -155,15 +155,15 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
155 155
156-include config/feature-tests.mak 156-include config/feature-tests.mak
157 157
158ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) 158ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
159 CFLAGS := $(CFLAGS) -fstack-protector-all 159 CFLAGS := $(CFLAGS) -fstack-protector-all
160endif 160endif
161 161
162ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wstack-protector),y) 162ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y)
163 CFLAGS := $(CFLAGS) -Wstack-protector 163 CFLAGS := $(CFLAGS) -Wstack-protector
164endif 164endif
165 165
166ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wvolatile-register-var),y) 166ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y)
167 CFLAGS := $(CFLAGS) -Wvolatile-register-var 167 CFLAGS := $(CFLAGS) -Wvolatile-register-var
168endif 168endif
169 169
@@ -197,8 +197,16 @@ BASIC_CFLAGS = \
197 -I. \ 197 -I. \
198 -I$(TRACE_EVENT_DIR) \ 198 -I$(TRACE_EVENT_DIR) \
199 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 199 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
200
200BASIC_LDFLAGS = 201BASIC_LDFLAGS =
201 202
203ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
204 BIONIC := 1
205 EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
206 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
207 BASIC_CFLAGS += -I.
208endif
209
202# Guard against environment variables 210# Guard against environment variables
203BUILTIN_OBJS = 211BUILTIN_OBJS =
204LIB_H = 212LIB_H =
@@ -330,6 +338,7 @@ LIB_H += util/evlist.h
330LIB_H += util/exec_cmd.h 338LIB_H += util/exec_cmd.h
331LIB_H += util/types.h 339LIB_H += util/types.h
332LIB_H += util/levenshtein.h 340LIB_H += util/levenshtein.h
341LIB_H += util/machine.h
333LIB_H += util/map.h 342LIB_H += util/map.h
334LIB_H += util/parse-options.h 343LIB_H += util/parse-options.h
335LIB_H += util/parse-events.h 344LIB_H += util/parse-events.h
@@ -346,6 +355,7 @@ LIB_H += util/svghelper.h
346LIB_H += util/tool.h 355LIB_H += util/tool.h
347LIB_H += util/run-command.h 356LIB_H += util/run-command.h
348LIB_H += util/sigchain.h 357LIB_H += util/sigchain.h
358LIB_H += util/dso.h
349LIB_H += util/symbol.h 359LIB_H += util/symbol.h
350LIB_H += util/color.h 360LIB_H += util/color.h
351LIB_H += util/values.h 361LIB_H += util/values.h
@@ -389,7 +399,6 @@ LIB_OBJS += $(OUTPUT)util/help.o
389LIB_OBJS += $(OUTPUT)util/levenshtein.o 399LIB_OBJS += $(OUTPUT)util/levenshtein.o
390LIB_OBJS += $(OUTPUT)util/parse-options.o 400LIB_OBJS += $(OUTPUT)util/parse-options.o
391LIB_OBJS += $(OUTPUT)util/parse-events.o 401LIB_OBJS += $(OUTPUT)util/parse-events.o
392LIB_OBJS += $(OUTPUT)util/parse-events-test.o
393LIB_OBJS += $(OUTPUT)util/path.o 402LIB_OBJS += $(OUTPUT)util/path.o
394LIB_OBJS += $(OUTPUT)util/rbtree.o 403LIB_OBJS += $(OUTPUT)util/rbtree.o
395LIB_OBJS += $(OUTPUT)util/bitmap.o 404LIB_OBJS += $(OUTPUT)util/bitmap.o
@@ -404,15 +413,16 @@ LIB_OBJS += $(OUTPUT)util/top.o
404LIB_OBJS += $(OUTPUT)util/usage.o 413LIB_OBJS += $(OUTPUT)util/usage.o
405LIB_OBJS += $(OUTPUT)util/wrapper.o 414LIB_OBJS += $(OUTPUT)util/wrapper.o
406LIB_OBJS += $(OUTPUT)util/sigchain.o 415LIB_OBJS += $(OUTPUT)util/sigchain.o
416LIB_OBJS += $(OUTPUT)util/dso.o
407LIB_OBJS += $(OUTPUT)util/symbol.o 417LIB_OBJS += $(OUTPUT)util/symbol.o
408LIB_OBJS += $(OUTPUT)util/symbol-elf.o 418LIB_OBJS += $(OUTPUT)util/symbol-elf.o
409LIB_OBJS += $(OUTPUT)util/dso-test-data.o
410LIB_OBJS += $(OUTPUT)util/color.o 419LIB_OBJS += $(OUTPUT)util/color.o
411LIB_OBJS += $(OUTPUT)util/pager.o 420LIB_OBJS += $(OUTPUT)util/pager.o
412LIB_OBJS += $(OUTPUT)util/header.o 421LIB_OBJS += $(OUTPUT)util/header.o
413LIB_OBJS += $(OUTPUT)util/callchain.o 422LIB_OBJS += $(OUTPUT)util/callchain.o
414LIB_OBJS += $(OUTPUT)util/values.o 423LIB_OBJS += $(OUTPUT)util/values.o
415LIB_OBJS += $(OUTPUT)util/debug.o 424LIB_OBJS += $(OUTPUT)util/debug.o
425LIB_OBJS += $(OUTPUT)util/machine.o
416LIB_OBJS += $(OUTPUT)util/map.o 426LIB_OBJS += $(OUTPUT)util/map.o
417LIB_OBJS += $(OUTPUT)util/pstack.o 427LIB_OBJS += $(OUTPUT)util/pstack.o
418LIB_OBJS += $(OUTPUT)util/session.o 428LIB_OBJS += $(OUTPUT)util/session.o
@@ -440,10 +450,29 @@ LIB_OBJS += $(OUTPUT)util/intlist.o
440LIB_OBJS += $(OUTPUT)util/vdso.o 450LIB_OBJS += $(OUTPUT)util/vdso.o
441LIB_OBJS += $(OUTPUT)util/stat.o 451LIB_OBJS += $(OUTPUT)util/stat.o
442 452
453LIB_OBJS += $(OUTPUT)ui/setup.o
443LIB_OBJS += $(OUTPUT)ui/helpline.o 454LIB_OBJS += $(OUTPUT)ui/helpline.o
455LIB_OBJS += $(OUTPUT)ui/progress.o
444LIB_OBJS += $(OUTPUT)ui/hist.o 456LIB_OBJS += $(OUTPUT)ui/hist.o
445LIB_OBJS += $(OUTPUT)ui/stdio/hist.o 457LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
446 458
459LIB_OBJS += $(OUTPUT)arch/common.o
460
461LIB_OBJS += $(OUTPUT)tests/parse-events.o
462LIB_OBJS += $(OUTPUT)tests/dso-data.o
463LIB_OBJS += $(OUTPUT)tests/attr.o
464LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
465LIB_OBJS += $(OUTPUT)tests/open-syscall.o
466LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
467LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
468LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
469LIB_OBJS += $(OUTPUT)tests/perf-record.o
470LIB_OBJS += $(OUTPUT)tests/rdpmc.o
471LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
472LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
473LIB_OBJS += $(OUTPUT)tests/pmu.o
474LIB_OBJS += $(OUTPUT)tests/util.o
475
447BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 476BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
448BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 477BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
449# Benchmark modules 478# Benchmark modules
@@ -473,8 +502,8 @@ BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
473BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o 502BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
474BUILTIN_OBJS += $(OUTPUT)builtin-lock.o 503BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
475BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o 504BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
476BUILTIN_OBJS += $(OUTPUT)builtin-test.o
477BUILTIN_OBJS += $(OUTPUT)builtin-inject.o 505BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
506BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
478 507
479PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) 508PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
480 509
@@ -495,18 +524,33 @@ ifdef NO_LIBELF
495 NO_LIBUNWIND := 1 524 NO_LIBUNWIND := 1
496else 525else
497FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) 526FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
498ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y) 527ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
499 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS) 528 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
500 ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y) 529 ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
501 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 530 LIBC_SUPPORT := 1
502 else 531 endif
532 ifeq ($(BIONIC),1)
533 LIBC_SUPPORT := 1
534 endif
535 ifeq ($(LIBC_SUPPORT),1)
536 msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
537
503 NO_LIBELF := 1 538 NO_LIBELF := 1
504 NO_DWARF := 1 539 NO_DWARF := 1
505 NO_DEMANGLE := 1 540 NO_DEMANGLE := 1
541 else
542 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
506 endif 543 endif
507else 544else
508 FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) 545 # for linking with debug library, run like:
509 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) 546 # make DEBUG=1 LIBDW_DIR=/opt/libdw/
547 ifdef LIBDW_DIR
548 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
549 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
550 endif
551
552 FLAGS_DWARF=$(ALL_CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
553 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
510 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); 554 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
511 NO_DWARF := 1 555 NO_DWARF := 1
512 endif # Dwarf support 556 endif # Dwarf support
@@ -522,7 +566,7 @@ ifdef LIBUNWIND_DIR
522endif 566endif
523 567
524FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS) 568FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
525ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND)),y) 569ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
526 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99); 570 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
527 NO_LIBUNWIND := 1 571 NO_LIBUNWIND := 1
528endif # Libunwind support 572endif # Libunwind support
@@ -551,7 +595,8 @@ LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
551else # NO_LIBELF 595else # NO_LIBELF
552BASIC_CFLAGS += -DLIBELF_SUPPORT 596BASIC_CFLAGS += -DLIBELF_SUPPORT
553 597
554ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) 598FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
599ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
555 BASIC_CFLAGS += -DLIBELF_MMAP 600 BASIC_CFLAGS += -DLIBELF_MMAP
556endif 601endif
557 602
@@ -559,7 +604,8 @@ ifndef NO_DWARF
559ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) 604ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
560 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); 605 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
561else 606else
562 BASIC_CFLAGS += -DDWARF_SUPPORT 607 BASIC_CFLAGS := -DDWARF_SUPPORT $(LIBDW_CFLAGS) $(BASIC_CFLAGS)
608 BASIC_LDFLAGS := $(LIBDW_LDFLAGS) $(BASIC_LDFLAGS)
563 EXTLIBS += -lelf -ldw 609 EXTLIBS += -lelf -ldw
564 LIB_OBJS += $(OUTPUT)util/probe-finder.o 610 LIB_OBJS += $(OUTPUT)util/probe-finder.o
565 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o 611 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
@@ -577,7 +623,7 @@ endif
577 623
578ifndef NO_LIBAUDIT 624ifndef NO_LIBAUDIT
579 FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit 625 FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit
580 ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y) 626 ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
581 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); 627 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
582 else 628 else
583 BASIC_CFLAGS += -DLIBAUDIT_SUPPORT 629 BASIC_CFLAGS += -DLIBAUDIT_SUPPORT
@@ -588,23 +634,23 @@ endif
588 634
589ifndef NO_NEWT 635ifndef NO_NEWT
590 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt 636 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
591 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y) 637 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT),libnewt),y)
592 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); 638 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
593 else 639 else
594 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 640 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
595 BASIC_CFLAGS += -I/usr/include/slang 641 BASIC_CFLAGS += -I/usr/include/slang
596 BASIC_CFLAGS += -DNEWT_SUPPORT 642 BASIC_CFLAGS += -DNEWT_SUPPORT
597 EXTLIBS += -lnewt -lslang 643 EXTLIBS += -lnewt -lslang
598 LIB_OBJS += $(OUTPUT)ui/setup.o
599 LIB_OBJS += $(OUTPUT)ui/browser.o 644 LIB_OBJS += $(OUTPUT)ui/browser.o
600 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o 645 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
601 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o 646 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
602 LIB_OBJS += $(OUTPUT)ui/browsers/map.o 647 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
603 LIB_OBJS += $(OUTPUT)ui/progress.o 648 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
604 LIB_OBJS += $(OUTPUT)ui/util.o 649 LIB_OBJS += $(OUTPUT)ui/util.o
605 LIB_OBJS += $(OUTPUT)ui/tui/setup.o 650 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
606 LIB_OBJS += $(OUTPUT)ui/tui/util.o 651 LIB_OBJS += $(OUTPUT)ui/tui/util.o
607 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o 652 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
653 LIB_OBJS += $(OUTPUT)ui/tui/progress.o
608 LIB_H += ui/browser.h 654 LIB_H += ui/browser.h
609 LIB_H += ui/browsers/map.h 655 LIB_H += ui/browsers/map.h
610 LIB_H += ui/keysyms.h 656 LIB_H += ui/keysyms.h
@@ -617,10 +663,10 @@ endif
617 663
618ifndef NO_GTK2 664ifndef NO_GTK2
619 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 665 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
620 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y) 666 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y)
621 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); 667 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
622 else 668 else
623 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y) 669 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
624 BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR 670 BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
625 endif 671 endif
626 BASIC_CFLAGS += -DGTK2_SUPPORT 672 BASIC_CFLAGS += -DGTK2_SUPPORT
@@ -630,9 +676,9 @@ ifndef NO_GTK2
630 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o 676 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
631 LIB_OBJS += $(OUTPUT)ui/gtk/util.o 677 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
632 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o 678 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
679 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
633 # Make sure that it'd be included only once. 680 # Make sure that it'd be included only once.
634 ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),) 681 ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),)
635 LIB_OBJS += $(OUTPUT)ui/setup.o
636 LIB_OBJS += $(OUTPUT)ui/util.o 682 LIB_OBJS += $(OUTPUT)ui/util.o
637 endif 683 endif
638 endif 684 endif
@@ -647,7 +693,7 @@ else
647 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 693 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
648 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) 694 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
649 695
650 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y) 696 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
651 BASIC_CFLAGS += -DNO_LIBPERL 697 BASIC_CFLAGS += -DNO_LIBPERL
652 else 698 else
653 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS) 699 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
@@ -701,11 +747,11 @@ else
701 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 747 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
702 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 748 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
703 749
704 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) 750 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
705 $(call disable-python,Python.h (for Python 2.x)) 751 $(call disable-python,Python.h (for Python 2.x))
706 else 752 else
707 753
708 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED)),y) 754 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
709 $(warning Python 3 is not yet supported; please set) 755 $(warning Python 3 is not yet supported; please set)
710 $(warning PYTHON and/or PYTHON_CONFIG appropriately.) 756 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
711 $(warning If you also have Python 2 installed, then) 757 $(warning If you also have Python 2 installed, then)
@@ -739,22 +785,22 @@ else
739 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 785 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
740 else 786 else
741 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd 787 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
742 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD)) 788 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
743 ifeq ($(has_bfd),y) 789 ifeq ($(has_bfd),y)
744 EXTLIBS += -lbfd 790 EXTLIBS += -lbfd
745 else 791 else
746 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty 792 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
747 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY)) 793 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
748 ifeq ($(has_bfd_iberty),y) 794 ifeq ($(has_bfd_iberty),y)
749 EXTLIBS += -lbfd -liberty 795 EXTLIBS += -lbfd -liberty
750 else 796 else
751 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz 797 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
752 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z)) 798 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
753 ifeq ($(has_bfd_iberty_z),y) 799 ifeq ($(has_bfd_iberty_z),y)
754 EXTLIBS += -lbfd -liberty -lz 800 EXTLIBS += -lbfd -liberty -lz
755 else 801 else
756 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty 802 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
757 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE)) 803 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
758 ifeq ($(has_cplus_demangle),y) 804 ifeq ($(has_cplus_demangle),y)
759 EXTLIBS += -liberty 805 EXTLIBS += -liberty
760 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 806 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
@@ -776,13 +822,19 @@ ifeq ($(NO_PERF_REGS),0)
776endif 822endif
777 823
778ifndef NO_STRLCPY 824ifndef NO_STRLCPY
779 ifeq ($(call try-cc,$(SOURCE_STRLCPY),),y) 825 ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
780 BASIC_CFLAGS += -DHAVE_STRLCPY 826 BASIC_CFLAGS += -DHAVE_STRLCPY
781 endif 827 endif
782endif 828endif
783 829
830ifndef NO_ON_EXIT
831 ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
832 BASIC_CFLAGS += -DHAVE_ON_EXIT
833 endif
834endif
835
784ifndef NO_BACKTRACE 836ifndef NO_BACKTRACE
785 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),),y) 837 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
786 BASIC_CFLAGS += -DBACKTRACE_SUPPORT 838 BASIC_CFLAGS += -DBACKTRACE_SUPPORT
787 endif 839 endif
788endif 840endif
@@ -891,10 +943,14 @@ $(OUTPUT)%.s: %.S
891$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS 943$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
892 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 944 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
893 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ 945 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
894 '-DBINDIR="$(bindir_relative_SQ)"' \
895 '-DPREFIX="$(prefix_SQ)"' \ 946 '-DPREFIX="$(prefix_SQ)"' \
896 $< 947 $<
897 948
949$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
950 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
951 '-DBINDIR="$(bindir_SQ)"' \
952 $<
953
898$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 954$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
899 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 955 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
900 956
@@ -910,6 +966,9 @@ $(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
910$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS 966$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
911 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 967 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
912 968
969$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
970 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
971
913$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 972$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
914 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 973 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
915 974
@@ -981,20 +1040,15 @@ help:
981 @echo 'Perf maintainer targets:' 1040 @echo 'Perf maintainer targets:'
982 @echo ' clean - clean all binary objects and build output' 1041 @echo ' clean - clean all binary objects and build output'
983 1042
984doc:
985 $(MAKE) -C Documentation all
986
987man:
988 $(MAKE) -C Documentation man
989 1043
990html: 1044DOC_TARGETS := doc man html info pdf
991 $(MAKE) -C Documentation html
992 1045
993info: 1046INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man
994 $(MAKE) -C Documentation info 1047INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
995 1048
996pdf: 1049# 'make doc' should call 'make -C Documentation all'
997 $(MAKE) -C Documentation pdf 1050$(DOC_TARGETS):
1051 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
998 1052
999TAGS: 1053TAGS:
1000 $(RM) TAGS 1054 $(RM) TAGS
@@ -1045,7 +1099,7 @@ perfexec_instdir = $(prefix)/$(perfexecdir)
1045endif 1099endif
1046perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 1100perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1047 1101
1048install: all 1102install: all try-install-man
1049 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 1103 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1050 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' 1104 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1051 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1105 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
@@ -1061,33 +1115,17 @@ install: all
1061 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 1115 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1062 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d' 1116 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
1063 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' 1117 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
1118 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
1119 $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
1120 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1121 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1064 1122
1065install-python_ext: 1123install-python_ext:
1066 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' 1124 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
1067 1125
1068install-doc: 1126# 'make install-doc' should call 'make -C Documentation install'
1069 $(MAKE) -C Documentation install 1127$(INSTALL_DOC_TARGETS):
1070 1128 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=)
1071install-man:
1072 $(MAKE) -C Documentation install-man
1073
1074install-html:
1075 $(MAKE) -C Documentation install-html
1076
1077install-info:
1078 $(MAKE) -C Documentation install-info
1079
1080install-pdf:
1081 $(MAKE) -C Documentation install-pdf
1082
1083quick-install-doc:
1084 $(MAKE) -C Documentation quick-install
1085
1086quick-install-man:
1087 $(MAKE) -C Documentation quick-install-man
1088
1089quick-install-html:
1090 $(MAKE) -C Documentation quick-install-html
1091 1129
1092### Cleaning rules 1130### Cleaning rules
1093 1131
@@ -1095,7 +1133,7 @@ clean: $(LIBTRACEEVENT)-clean
1095 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) 1133 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
1096 $(RM) $(ALL_PROGRAMS) perf 1134 $(RM) $(ALL_PROGRAMS) perf
1097 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 1135 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1098 $(MAKE) -C Documentation/ clean 1136 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
1099 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS 1137 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
1100 $(RM) $(OUTPUT)util/*-bison* 1138 $(RM) $(OUTPUT)util/*-bison*
1101 $(RM) $(OUTPUT)util/*-flex* 1139 $(RM) $(OUTPUT)util/*-flex*
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
new file mode 100644
index 000000000000..3e975cb6232e
--- /dev/null
+++ b/tools/perf/arch/common.c
@@ -0,0 +1,211 @@
1#include <stdio.h>
2#include <sys/utsname.h>
3#include "common.h"
4#include "../util/debug.h"
5
6const char *const arm_triplets[] = {
7 "arm-eabi-",
8 "arm-linux-androideabi-",
9 "arm-unknown-linux-",
10 "arm-unknown-linux-gnu-",
11 "arm-unknown-linux-gnueabi-",
12 NULL
13};
14
15const char *const powerpc_triplets[] = {
16 "powerpc-unknown-linux-gnu-",
17 "powerpc64-unknown-linux-gnu-",
18 NULL
19};
20
21const char *const s390_triplets[] = {
22 "s390-ibm-linux-",
23 NULL
24};
25
26const char *const sh_triplets[] = {
27 "sh-unknown-linux-gnu-",
28 "sh64-unknown-linux-gnu-",
29 NULL
30};
31
32const char *const sparc_triplets[] = {
33 "sparc-unknown-linux-gnu-",
34 "sparc64-unknown-linux-gnu-",
35 NULL
36};
37
38const char *const x86_triplets[] = {
39 "x86_64-pc-linux-gnu-",
40 "x86_64-unknown-linux-gnu-",
41 "i686-pc-linux-gnu-",
42 "i586-pc-linux-gnu-",
43 "i486-pc-linux-gnu-",
44 "i386-pc-linux-gnu-",
45 "i686-linux-android-",
46 "i686-android-linux-",
47 NULL
48};
49
50const char *const mips_triplets[] = {
51 "mips-unknown-linux-gnu-",
52 "mipsel-linux-android-",
53 NULL
54};
55
56static bool lookup_path(char *name)
57{
58 bool found = false;
59 char *path, *tmp;
60 char buf[PATH_MAX];
61 char *env = getenv("PATH");
62
63 if (!env)
64 return false;
65
66 env = strdup(env);
67 if (!env)
68 return false;
69
70 path = strtok_r(env, ":", &tmp);
71 while (path) {
72 scnprintf(buf, sizeof(buf), "%s/%s", path, name);
73 if (access(buf, F_OK) == 0) {
74 found = true;
75 break;
76 }
77 path = strtok_r(NULL, ":", &tmp);
78 }
79 free(env);
80 return found;
81}
82
83static int lookup_triplets(const char *const *triplets, const char *name)
84{
85 int i;
86 char buf[PATH_MAX];
87
88 for (i = 0; triplets[i] != NULL; i++) {
89 scnprintf(buf, sizeof(buf), "%s%s", triplets[i], name);
90 if (lookup_path(buf))
91 return i;
92 }
93 return -1;
94}
95
96/*
97 * Return architecture name in a normalized form.
98 * The conversion logic comes from the Makefile.
99 */
100static const char *normalize_arch(char *arch)
101{
102 if (!strcmp(arch, "x86_64"))
103 return "x86";
104 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6')
105 return "x86";
106 if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5))
107 return "sparc";
108 if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110"))
109 return "arm";
110 if (!strncmp(arch, "s390", 4))
111 return "s390";
112 if (!strncmp(arch, "parisc", 6))
113 return "parisc";
114 if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3))
115 return "powerpc";
116 if (!strncmp(arch, "mips", 4))
117 return "mips";
118 if (!strncmp(arch, "sh", 2) && isdigit(arch[2]))
119 return "sh";
120
121 return arch;
122}
123
124static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
125 const char *name,
126 const char **path)
127{
128 int idx;
129 const char *arch, *cross_env;
130 struct utsname uts;
131 const char *const *path_list;
132 char *buf = NULL;
133
134 arch = normalize_arch(env->arch);
135
136 if (uname(&uts) < 0)
137 goto out;
138
139 /*
140 * We don't need to try to find objdump path for native system.
141 * Just use default binutils path (e.g.: "objdump").
142 */
143 if (!strcmp(normalize_arch(uts.machine), arch))
144 goto out;
145
146 cross_env = getenv("CROSS_COMPILE");
147 if (cross_env) {
148 if (asprintf(&buf, "%s%s", cross_env, name) < 0)
149 goto out_error;
150 if (buf[0] == '/') {
151 if (access(buf, F_OK) == 0)
152 goto out;
153 goto out_error;
154 }
155 if (lookup_path(buf))
156 goto out;
157 free(buf);
158 }
159
160 if (!strcmp(arch, "arm"))
161 path_list = arm_triplets;
162 else if (!strcmp(arch, "powerpc"))
163 path_list = powerpc_triplets;
164 else if (!strcmp(arch, "sh"))
165 path_list = sh_triplets;
166 else if (!strcmp(arch, "s390"))
167 path_list = s390_triplets;
168 else if (!strcmp(arch, "sparc"))
169 path_list = sparc_triplets;
170 else if (!strcmp(arch, "x86"))
171 path_list = x86_triplets;
172 else if (!strcmp(arch, "mips"))
173 path_list = mips_triplets;
174 else {
175 ui__error("binutils for %s not supported.\n", arch);
176 goto out_error;
177 }
178
179 idx = lookup_triplets(path_list, name);
180 if (idx < 0) {
181 ui__error("Please install %s for %s.\n"
182 "You can add it to PATH, set CROSS_COMPILE or "
183 "override the default using --%s.\n",
184 name, arch, name);
185 goto out_error;
186 }
187
188 if (asprintf(&buf, "%s%s", path_list[idx], name) < 0)
189 goto out_error;
190
191out:
192 *path = buf;
193 return 0;
194out_error:
195 free(buf);
196 *path = NULL;
197 return -1;
198}
199
200int perf_session_env__lookup_objdump(struct perf_session_env *env)
201{
202 /*
203 * For live mode, env->arch will be NULL and we can use
204 * the native objdump tool.
205 */
206 if (env->arch == NULL)
207 return 0;
208
209 return perf_session_env__lookup_binutils_path(env, "objdump",
210 &objdump_path);
211}
diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h
new file mode 100644
index 000000000000..ede246eda9be
--- /dev/null
+++ b/tools/perf/arch/common.h
@@ -0,0 +1,10 @@
1#ifndef ARCH_PERF_COMMON_H
2#define ARCH_PERF_COMMON_H
3
4#include "../util/session.h"
5
6extern const char *objdump_path;
7
8int perf_session_env__lookup_objdump(struct perf_session_env *env);
9
10#endif /* ARCH_PERF_COMMON_H */
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 9ea38540b873..dc870cf31b79 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -28,12 +28,12 @@
28#include "util/hist.h" 28#include "util/hist.h"
29#include "util/session.h" 29#include "util/session.h"
30#include "util/tool.h" 30#include "util/tool.h"
31#include "arch/common.h"
31 32
32#include <linux/bitmap.h> 33#include <linux/bitmap.h>
33 34
34struct perf_annotate { 35struct perf_annotate {
35 struct perf_tool tool; 36 struct perf_tool tool;
36 char const *input_name;
37 bool force, use_tui, use_stdio; 37 bool force, use_tui, use_stdio;
38 bool full_paths; 38 bool full_paths;
39 bool print_line; 39 bool print_line;
@@ -139,7 +139,7 @@ find_next:
139 } 139 }
140 140
141 if (use_browser > 0) { 141 if (use_browser > 0) {
142 key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0); 142 key = hist_entry__tui_annotate(he, evidx, NULL);
143 switch (key) { 143 switch (key) {
144 case K_RIGHT: 144 case K_RIGHT:
145 next = rb_next(nd); 145 next = rb_next(nd);
@@ -174,7 +174,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
174 struct perf_evsel *pos; 174 struct perf_evsel *pos;
175 u64 total_nr_samples; 175 u64 total_nr_samples;
176 176
177 session = perf_session__new(ann->input_name, O_RDONLY, 177 session = perf_session__new(input_name, O_RDONLY,
178 ann->force, false, &ann->tool); 178 ann->force, false, &ann->tool);
179 if (session == NULL) 179 if (session == NULL)
180 return -ENOMEM; 180 return -ENOMEM;
@@ -186,6 +186,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
186 goto out_delete; 186 goto out_delete;
187 } 187 }
188 188
189 if (!objdump_path) {
190 ret = perf_session_env__lookup_objdump(&session->header.env);
191 if (ret)
192 goto out_delete;
193 }
194
189 ret = perf_session__process_events(session, &ann->tool); 195 ret = perf_session__process_events(session, &ann->tool);
190 if (ret) 196 if (ret)
191 goto out_delete; 197 goto out_delete;
@@ -246,13 +252,14 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
246 .sample = process_sample_event, 252 .sample = process_sample_event,
247 .mmap = perf_event__process_mmap, 253 .mmap = perf_event__process_mmap,
248 .comm = perf_event__process_comm, 254 .comm = perf_event__process_comm,
249 .fork = perf_event__process_task, 255 .exit = perf_event__process_exit,
256 .fork = perf_event__process_fork,
250 .ordered_samples = true, 257 .ordered_samples = true,
251 .ordering_requires_timestamps = true, 258 .ordering_requires_timestamps = true,
252 }, 259 },
253 }; 260 };
254 const struct option options[] = { 261 const struct option options[] = {
255 OPT_STRING('i', "input", &annotate.input_name, "file", 262 OPT_STRING('i', "input", &input_name, "file",
256 "input file name"), 263 "input file name"),
257 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 264 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
258 "only consider symbols in these dsos"), 265 "only consider symbols in these dsos"),
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index d37e077f4b14..fae8b250b2ca 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -13,6 +13,7 @@
13#include "util/header.h" 13#include "util/header.h"
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/strlist.h" 15#include "util/strlist.h"
16#include "util/build-id.h"
16#include "util/symbol.h" 17#include "util/symbol.h"
17 18
18static int build_id_cache__add_file(const char *filename, const char *debugdir) 19static int build_id_cache__add_file(const char *filename, const char *debugdir)
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index a0e94fffa03e..a82d99fec83e 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -44,8 +44,7 @@ static int filename__fprintf_build_id(const char *name, FILE *fp)
44 return fprintf(fp, "%s\n", sbuild_id); 44 return fprintf(fp, "%s\n", sbuild_id);
45} 45}
46 46
47static int perf_session__list_build_ids(const char *input_name, 47static int perf_session__list_build_ids(bool force, bool with_hits)
48 bool force, bool with_hits)
49{ 48{
50 struct perf_session *session; 49 struct perf_session *session;
51 50
@@ -81,7 +80,6 @@ int cmd_buildid_list(int argc, const char **argv,
81 bool show_kernel = false; 80 bool show_kernel = false;
82 bool with_hits = false; 81 bool with_hits = false;
83 bool force = false; 82 bool force = false;
84 const char *input_name = NULL;
85 const struct option options[] = { 83 const struct option options[] = {
86 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"), 84 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
87 OPT_STRING('i', "input", &input_name, "file", "input file name"), 85 OPT_STRING('i', "input", &input_name, "file", "input file name"),
@@ -101,5 +99,5 @@ int cmd_buildid_list(int argc, const char **argv,
101 if (show_kernel) 99 if (show_kernel)
102 return sysfs__fprintf_build_id(stdout); 100 return sysfs__fprintf_build_id(stdout);
103 101
104 return perf_session__list_build_ids(input_name, force, with_hits); 102 return perf_session__list_build_ids(force, with_hits);
105} 103}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index a0b531c14b97..93b852f8a5d5 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -24,6 +24,228 @@ static char const *input_old = "perf.data.old",
24static char diff__default_sort_order[] = "dso,symbol"; 24static char diff__default_sort_order[] = "dso,symbol";
25static bool force; 25static bool force;
26static bool show_displacement; 26static bool show_displacement;
27static bool show_period;
28static bool show_formula;
29static bool show_baseline_only;
30static bool sort_compute;
31
32static s64 compute_wdiff_w1;
33static s64 compute_wdiff_w2;
34
35enum {
36 COMPUTE_DELTA,
37 COMPUTE_RATIO,
38 COMPUTE_WEIGHTED_DIFF,
39 COMPUTE_MAX,
40};
41
42const char *compute_names[COMPUTE_MAX] = {
43 [COMPUTE_DELTA] = "delta",
44 [COMPUTE_RATIO] = "ratio",
45 [COMPUTE_WEIGHTED_DIFF] = "wdiff",
46};
47
48static int compute;
49
50static int setup_compute_opt_wdiff(char *opt)
51{
52 char *w1_str = opt;
53 char *w2_str;
54
55 int ret = -EINVAL;
56
57 if (!opt)
58 goto out;
59
60 w2_str = strchr(opt, ',');
61 if (!w2_str)
62 goto out;
63
64 *w2_str++ = 0x0;
65 if (!*w2_str)
66 goto out;
67
68 compute_wdiff_w1 = strtol(w1_str, NULL, 10);
69 compute_wdiff_w2 = strtol(w2_str, NULL, 10);
70
71 if (!compute_wdiff_w1 || !compute_wdiff_w2)
72 goto out;
73
74 pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
75 compute_wdiff_w1, compute_wdiff_w2);
76
77 ret = 0;
78
79 out:
80 if (ret)
81 pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
82
83 return ret;
84}
85
86static int setup_compute_opt(char *opt)
87{
88 if (compute == COMPUTE_WEIGHTED_DIFF)
89 return setup_compute_opt_wdiff(opt);
90
91 if (opt) {
92 pr_err("Failed: extra option specified '%s'", opt);
93 return -EINVAL;
94 }
95
96 return 0;
97}
98
99static int setup_compute(const struct option *opt, const char *str,
100 int unset __maybe_unused)
101{
102 int *cp = (int *) opt->value;
103 char *cstr = (char *) str;
104 char buf[50];
105 unsigned i;
106 char *option;
107
108 if (!str) {
109 *cp = COMPUTE_DELTA;
110 return 0;
111 }
112
113 if (*str == '+') {
114 sort_compute = true;
115 cstr = (char *) ++str;
116 if (!*str)
117 return 0;
118 }
119
120 option = strchr(str, ':');
121 if (option) {
122 unsigned len = option++ - str;
123
124 /*
125 * The str data are not writeable, so we need
126 * to use another buffer.
127 */
128
129 /* No option value is longer. */
130 if (len >= sizeof(buf))
131 return -EINVAL;
132
133 strncpy(buf, str, len);
134 buf[len] = 0x0;
135 cstr = buf;
136 }
137
138 for (i = 0; i < COMPUTE_MAX; i++)
139 if (!strcmp(cstr, compute_names[i])) {
140 *cp = i;
141 return setup_compute_opt(option);
142 }
143
144 pr_err("Failed: '%s' is not computation method "
145 "(use 'delta','ratio' or 'wdiff')\n", str);
146 return -EINVAL;
147}
148
149static double get_period_percent(struct hist_entry *he, u64 period)
150{
151 u64 total = he->hists->stats.total_period;
152 return (period * 100.0) / total;
153}
154
155double perf_diff__compute_delta(struct hist_entry *he)
156{
157 struct hist_entry *pair = hist_entry__next_pair(he);
158 double new_percent = get_period_percent(he, he->stat.period);
159 double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0;
160
161 he->diff.period_ratio_delta = new_percent - old_percent;
162 he->diff.computed = true;
163 return he->diff.period_ratio_delta;
164}
165
166double perf_diff__compute_ratio(struct hist_entry *he)
167{
168 struct hist_entry *pair = hist_entry__next_pair(he);
169 double new_period = he->stat.period;
170 double old_period = pair ? pair->stat.period : 0;
171
172 he->diff.computed = true;
173 he->diff.period_ratio = pair ? (new_period / old_period) : 0;
174 return he->diff.period_ratio;
175}
176
177s64 perf_diff__compute_wdiff(struct hist_entry *he)
178{
179 struct hist_entry *pair = hist_entry__next_pair(he);
180 u64 new_period = he->stat.period;
181 u64 old_period = pair ? pair->stat.period : 0;
182
183 he->diff.computed = true;
184
185 if (!pair)
186 he->diff.wdiff = 0;
187 else
188 he->diff.wdiff = new_period * compute_wdiff_w2 -
189 old_period * compute_wdiff_w1;
190
191 return he->diff.wdiff;
192}
193
194static int formula_delta(struct hist_entry *he, char *buf, size_t size)
195{
196 struct hist_entry *pair = hist_entry__next_pair(he);
197
198 if (!pair)
199 return -1;
200
201 return scnprintf(buf, size,
202 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
203 "(%" PRIu64 " * 100 / %" PRIu64 ")",
204 he->stat.period, he->hists->stats.total_period,
205 pair->stat.period, pair->hists->stats.total_period);
206}
207
208static int formula_ratio(struct hist_entry *he, char *buf, size_t size)
209{
210 struct hist_entry *pair = hist_entry__next_pair(he);
211 double new_period = he->stat.period;
212 double old_period = pair ? pair->stat.period : 0;
213
214 if (!pair)
215 return -1;
216
217 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
218}
219
220static int formula_wdiff(struct hist_entry *he, char *buf, size_t size)
221{
222 struct hist_entry *pair = hist_entry__next_pair(he);
223 u64 new_period = he->stat.period;
224 u64 old_period = pair ? pair->stat.period : 0;
225
226 if (!pair)
227 return -1;
228
229 return scnprintf(buf, size,
230 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
231 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
232}
233
234int perf_diff__formula(char *buf, size_t size, struct hist_entry *he)
235{
236 switch (compute) {
237 case COMPUTE_DELTA:
238 return formula_delta(he, buf, size);
239 case COMPUTE_RATIO:
240 return formula_ratio(he, buf, size);
241 case COMPUTE_WEIGHTED_DIFF:
242 return formula_wdiff(he, buf, size);
243 default:
244 BUG_ON(1);
245 }
246
247 return -1;
248}
27 249
28static int hists__add_entry(struct hists *self, 250static int hists__add_entry(struct hists *self,
29 struct addr_location *al, u64 period) 251 struct addr_location *al, u64 period)
@@ -47,7 +269,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
47 return -1; 269 return -1;
48 } 270 }
49 271
50 if (al.filtered || al.sym == NULL) 272 if (al.filtered)
51 return 0; 273 return 0;
52 274
53 if (hists__add_entry(&evsel->hists, &al, sample->period)) { 275 if (hists__add_entry(&evsel->hists, &al, sample->period)) {
@@ -63,8 +285,8 @@ static struct perf_tool tool = {
63 .sample = diff__process_sample_event, 285 .sample = diff__process_sample_event,
64 .mmap = perf_event__process_mmap, 286 .mmap = perf_event__process_mmap,
65 .comm = perf_event__process_comm, 287 .comm = perf_event__process_comm,
66 .exit = perf_event__process_task, 288 .exit = perf_event__process_exit,
67 .fork = perf_event__process_task, 289 .fork = perf_event__process_fork,
68 .lost = perf_event__process_lost, 290 .lost = perf_event__process_lost,
69 .ordered_samples = true, 291 .ordered_samples = true,
70 .ordering_requires_timestamps = true, 292 .ordering_requires_timestamps = true,
@@ -112,36 +334,6 @@ static void hists__name_resort(struct hists *self, bool sort)
112 self->entries = tmp; 334 self->entries = tmp;
113} 335}
114 336
115static struct hist_entry *hists__find_entry(struct hists *self,
116 struct hist_entry *he)
117{
118 struct rb_node *n = self->entries.rb_node;
119
120 while (n) {
121 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
122 int64_t cmp = hist_entry__cmp(he, iter);
123
124 if (cmp < 0)
125 n = n->rb_left;
126 else if (cmp > 0)
127 n = n->rb_right;
128 else
129 return iter;
130 }
131
132 return NULL;
133}
134
135static void hists__match(struct hists *older, struct hists *newer)
136{
137 struct rb_node *nd;
138
139 for (nd = rb_first(&newer->entries); nd; nd = rb_next(nd)) {
140 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
141 pos->pair = hists__find_entry(older, pos);
142 }
143}
144
145static struct perf_evsel *evsel_match(struct perf_evsel *evsel, 337static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
146 struct perf_evlist *evlist) 338 struct perf_evlist *evlist)
147{ 339{
@@ -172,6 +364,144 @@ static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name)
172 } 364 }
173} 365}
174 366
367static void hists__baseline_only(struct hists *hists)
368{
369 struct rb_node *next = rb_first(&hists->entries);
370
371 while (next != NULL) {
372 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
373
374 next = rb_next(&he->rb_node);
375 if (!hist_entry__next_pair(he)) {
376 rb_erase(&he->rb_node, &hists->entries);
377 hist_entry__free(he);
378 }
379 }
380}
381
382static void hists__precompute(struct hists *hists)
383{
384 struct rb_node *next = rb_first(&hists->entries);
385
386 while (next != NULL) {
387 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
388
389 next = rb_next(&he->rb_node);
390
391 switch (compute) {
392 case COMPUTE_DELTA:
393 perf_diff__compute_delta(he);
394 break;
395 case COMPUTE_RATIO:
396 perf_diff__compute_ratio(he);
397 break;
398 case COMPUTE_WEIGHTED_DIFF:
399 perf_diff__compute_wdiff(he);
400 break;
401 default:
402 BUG_ON(1);
403 }
404 }
405}
406
407static int64_t cmp_doubles(double l, double r)
408{
409 if (l > r)
410 return -1;
411 else if (l < r)
412 return 1;
413 else
414 return 0;
415}
416
417static int64_t
418hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
419 int c)
420{
421 switch (c) {
422 case COMPUTE_DELTA:
423 {
424 double l = left->diff.period_ratio_delta;
425 double r = right->diff.period_ratio_delta;
426
427 return cmp_doubles(l, r);
428 }
429 case COMPUTE_RATIO:
430 {
431 double l = left->diff.period_ratio;
432 double r = right->diff.period_ratio;
433
434 return cmp_doubles(l, r);
435 }
436 case COMPUTE_WEIGHTED_DIFF:
437 {
438 s64 l = left->diff.wdiff;
439 s64 r = right->diff.wdiff;
440
441 return r - l;
442 }
443 default:
444 BUG_ON(1);
445 }
446
447 return 0;
448}
449
450static void insert_hist_entry_by_compute(struct rb_root *root,
451 struct hist_entry *he,
452 int c)
453{
454 struct rb_node **p = &root->rb_node;
455 struct rb_node *parent = NULL;
456 struct hist_entry *iter;
457
458 while (*p != NULL) {
459 parent = *p;
460 iter = rb_entry(parent, struct hist_entry, rb_node);
461 if (hist_entry__cmp_compute(he, iter, c) < 0)
462 p = &(*p)->rb_left;
463 else
464 p = &(*p)->rb_right;
465 }
466
467 rb_link_node(&he->rb_node, parent, p);
468 rb_insert_color(&he->rb_node, root);
469}
470
471static void hists__compute_resort(struct hists *hists)
472{
473 struct rb_root tmp = RB_ROOT;
474 struct rb_node *next = rb_first(&hists->entries);
475
476 while (next != NULL) {
477 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
478
479 next = rb_next(&he->rb_node);
480
481 rb_erase(&he->rb_node, &hists->entries);
482 insert_hist_entry_by_compute(&tmp, he, compute);
483 }
484
485 hists->entries = tmp;
486}
487
488static void hists__process(struct hists *old, struct hists *new)
489{
490 hists__match(new, old);
491
492 if (show_baseline_only)
493 hists__baseline_only(new);
494 else
495 hists__link(new, old);
496
497 if (sort_compute) {
498 hists__precompute(new);
499 hists__compute_resort(new);
500 }
501
502 hists__fprintf(new, true, 0, 0, stdout);
503}
504
175static int __cmd_diff(void) 505static int __cmd_diff(void)
176{ 506{
177 int ret, i; 507 int ret, i;
@@ -213,8 +543,7 @@ static int __cmd_diff(void)
213 543
214 first = false; 544 first = false;
215 545
216 hists__match(&evsel_old->hists, &evsel->hists); 546 hists__process(&evsel_old->hists, &evsel->hists);
217 hists__fprintf(&evsel->hists, true, 0, 0, stdout);
218 } 547 }
219 548
220out_delete: 549out_delete:
@@ -235,6 +564,16 @@ static const struct option options[] = {
235 "be more verbose (show symbol address, etc)"), 564 "be more verbose (show symbol address, etc)"),
236 OPT_BOOLEAN('M', "displacement", &show_displacement, 565 OPT_BOOLEAN('M', "displacement", &show_displacement,
237 "Show position displacement relative to baseline"), 566 "Show position displacement relative to baseline"),
567 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
568 "Show only items with match in baseline"),
569 OPT_CALLBACK('c', "compute", &compute,
570 "delta,ratio,wdiff:w1,w2 (default delta)",
571 "Entries differential computation selection",
572 setup_compute),
573 OPT_BOOLEAN('p', "period", &show_period,
574 "Show period values."),
575 OPT_BOOLEAN('F', "formula", &show_formula,
576 "Show formula."),
238 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 577 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
239 "dump raw trace in ASCII"), 578 "dump raw trace in ASCII"),
240 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 579 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
@@ -263,12 +602,36 @@ static void ui_init(void)
263 /* No overhead column. */ 602 /* No overhead column. */
264 perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); 603 perf_hpp__column_enable(PERF_HPP__OVERHEAD, false);
265 604
266 /* Display baseline/delta/displacement columns. */ 605 /*
606 * Display baseline/delta/ratio/displacement/
607 * formula/periods columns.
608 */
267 perf_hpp__column_enable(PERF_HPP__BASELINE, true); 609 perf_hpp__column_enable(PERF_HPP__BASELINE, true);
268 perf_hpp__column_enable(PERF_HPP__DELTA, true); 610
611 switch (compute) {
612 case COMPUTE_DELTA:
613 perf_hpp__column_enable(PERF_HPP__DELTA, true);
614 break;
615 case COMPUTE_RATIO:
616 perf_hpp__column_enable(PERF_HPP__RATIO, true);
617 break;
618 case COMPUTE_WEIGHTED_DIFF:
619 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true);
620 break;
621 default:
622 BUG_ON(1);
623 };
269 624
270 if (show_displacement) 625 if (show_displacement)
271 perf_hpp__column_enable(PERF_HPP__DISPL, true); 626 perf_hpp__column_enable(PERF_HPP__DISPL, true);
627
628 if (show_formula)
629 perf_hpp__column_enable(PERF_HPP__FORMULA, true);
630
631 if (show_period) {
632 perf_hpp__column_enable(PERF_HPP__PERIOD, true);
633 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true);
634 }
272} 635}
273 636
274int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) 637int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 997afb82691b..c20f1dcfb7e2 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -48,12 +48,12 @@ static int __if_print(bool *first, const char *field, u64 value)
48 48
49#define if_print(field) __if_print(&first, #field, pos->attr.field) 49#define if_print(field) __if_print(&first, #field, pos->attr.field)
50 50
51static int __cmd_evlist(const char *input_name, struct perf_attr_details *details) 51static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
52{ 52{
53 struct perf_session *session; 53 struct perf_session *session;
54 struct perf_evsel *pos; 54 struct perf_evsel *pos;
55 55
56 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL); 56 session = perf_session__new(file_name, O_RDONLY, 0, false, NULL);
57 if (session == NULL) 57 if (session == NULL)
58 return -ENOMEM; 58 return -ENOMEM;
59 59
@@ -111,7 +111,6 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail
111int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) 111int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
112{ 112{
113 struct perf_attr_details details = { .verbose = false, }; 113 struct perf_attr_details details = { .verbose = false, };
114 const char *input_name = NULL;
115 const struct option options[] = { 114 const struct option options[] = {
116 OPT_STRING('i', "input", &input_name, "file", "Input file name"), 115 OPT_STRING('i', "input", &input_name, "file", "Input file name"),
117 OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), 116 OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"),
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 4688bea95c12..84ad6abe4258 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -8,33 +8,53 @@
8#include "builtin.h" 8#include "builtin.h"
9 9
10#include "perf.h" 10#include "perf.h"
11#include "util/color.h"
12#include "util/evlist.h"
13#include "util/evsel.h"
11#include "util/session.h" 14#include "util/session.h"
12#include "util/tool.h" 15#include "util/tool.h"
13#include "util/debug.h" 16#include "util/debug.h"
17#include "util/build-id.h"
14 18
15#include "util/parse-options.h" 19#include "util/parse-options.h"
16 20
21#include <linux/list.h>
22
17struct perf_inject { 23struct perf_inject {
18 struct perf_tool tool; 24 struct perf_tool tool;
19 bool build_ids; 25 bool build_ids;
26 bool sched_stat;
27 const char *input_name;
28 int pipe_output,
29 output;
30 u64 bytes_written;
31 struct list_head samples;
32};
33
34struct event_entry {
35 struct list_head node;
36 u32 tid;
37 union perf_event event[0];
20}; 38};
21 39
22static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused, 40static int perf_event__repipe_synth(struct perf_tool *tool,
23 union perf_event *event, 41 union perf_event *event,
24 struct machine *machine __maybe_unused) 42 struct machine *machine __maybe_unused)
25{ 43{
44 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
26 uint32_t size; 45 uint32_t size;
27 void *buf = event; 46 void *buf = event;
28 47
29 size = event->header.size; 48 size = event->header.size;
30 49
31 while (size) { 50 while (size) {
32 int ret = write(STDOUT_FILENO, buf, size); 51 int ret = write(inject->output, buf, size);
33 if (ret < 0) 52 if (ret < 0)
34 return -errno; 53 return -errno;
35 54
36 size -= ret; 55 size -= ret;
37 buf += ret; 56 buf += ret;
57 inject->bytes_written += ret;
38 } 58 }
39 59
40 return 0; 60 return 0;
@@ -80,12 +100,25 @@ static int perf_event__repipe(struct perf_tool *tool,
80 return perf_event__repipe_synth(tool, event, machine); 100 return perf_event__repipe_synth(tool, event, machine);
81} 101}
82 102
103typedef int (*inject_handler)(struct perf_tool *tool,
104 union perf_event *event,
105 struct perf_sample *sample,
106 struct perf_evsel *evsel,
107 struct machine *machine);
108
83static int perf_event__repipe_sample(struct perf_tool *tool, 109static int perf_event__repipe_sample(struct perf_tool *tool,
84 union perf_event *event, 110 union perf_event *event,
85 struct perf_sample *sample __maybe_unused, 111 struct perf_sample *sample,
86 struct perf_evsel *evsel __maybe_unused, 112 struct perf_evsel *evsel,
87 struct machine *machine) 113 struct machine *machine)
88{ 114{
115 if (evsel->handler.func) {
116 inject_handler f = evsel->handler.func;
117 return f(tool, event, sample, evsel, machine);
118 }
119
120 build_id__mark_dso_hit(tool, event, sample, evsel, machine);
121
89 return perf_event__repipe_synth(tool, event, machine); 122 return perf_event__repipe_synth(tool, event, machine);
90} 123}
91 124
@@ -102,14 +135,14 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
102 return err; 135 return err;
103} 136}
104 137
105static int perf_event__repipe_task(struct perf_tool *tool, 138static int perf_event__repipe_fork(struct perf_tool *tool,
106 union perf_event *event, 139 union perf_event *event,
107 struct perf_sample *sample, 140 struct perf_sample *sample,
108 struct machine *machine) 141 struct machine *machine)
109{ 142{
110 int err; 143 int err;
111 144
112 err = perf_event__process_task(tool, event, sample, machine); 145 err = perf_event__process_fork(tool, event, sample, machine);
113 perf_event__repipe(tool, event, sample, machine); 146 perf_event__repipe(tool, event, sample, machine);
114 147
115 return err; 148 return err;
@@ -210,6 +243,80 @@ repipe:
210 return 0; 243 return 0;
211} 244}
212 245
246static int perf_inject__sched_process_exit(struct perf_tool *tool,
247 union perf_event *event __maybe_unused,
248 struct perf_sample *sample,
249 struct perf_evsel *evsel __maybe_unused,
250 struct machine *machine __maybe_unused)
251{
252 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
253 struct event_entry *ent;
254
255 list_for_each_entry(ent, &inject->samples, node) {
256 if (sample->tid == ent->tid) {
257 list_del_init(&ent->node);
258 free(ent);
259 break;
260 }
261 }
262
263 return 0;
264}
265
266static int perf_inject__sched_switch(struct perf_tool *tool,
267 union perf_event *event,
268 struct perf_sample *sample,
269 struct perf_evsel *evsel,
270 struct machine *machine)
271{
272 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
273 struct event_entry *ent;
274
275 perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
276
277 ent = malloc(event->header.size + sizeof(struct event_entry));
278 if (ent == NULL) {
279 color_fprintf(stderr, PERF_COLOR_RED,
280 "Not enough memory to process sched switch event!");
281 return -1;
282 }
283
284 ent->tid = sample->tid;
285 memcpy(&ent->event, event, event->header.size);
286 list_add(&ent->node, &inject->samples);
287 return 0;
288}
289
290static int perf_inject__sched_stat(struct perf_tool *tool,
291 union perf_event *event __maybe_unused,
292 struct perf_sample *sample,
293 struct perf_evsel *evsel,
294 struct machine *machine)
295{
296 struct event_entry *ent;
297 union perf_event *event_sw;
298 struct perf_sample sample_sw;
299 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
300 u32 pid = perf_evsel__intval(evsel, sample, "pid");
301
302 list_for_each_entry(ent, &inject->samples, node) {
303 if (pid == ent->tid)
304 goto found;
305 }
306
307 return 0;
308found:
309 event_sw = &ent->event[0];
310 perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
311
312 sample_sw.period = sample->period;
313 sample_sw.time = sample->time;
314 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
315 &sample_sw, false);
316 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
317 return perf_event__repipe(tool, event_sw, &sample_sw, machine);
318}
319
213extern volatile int session_done; 320extern volatile int session_done;
214 321
215static void sig_handler(int sig __maybe_unused) 322static void sig_handler(int sig __maybe_unused)
@@ -217,6 +324,21 @@ static void sig_handler(int sig __maybe_unused)
217 session_done = 1; 324 session_done = 1;
218} 325}
219 326
327static int perf_evsel__check_stype(struct perf_evsel *evsel,
328 u64 sample_type, const char *sample_msg)
329{
330 struct perf_event_attr *attr = &evsel->attr;
331 const char *name = perf_evsel__name(evsel);
332
333 if (!(attr->sample_type & sample_type)) {
334 pr_err("Samples for %s event do not have %s attribute set.",
335 name, sample_msg);
336 return -EINVAL;
337 }
338
339 return 0;
340}
341
220static int __cmd_inject(struct perf_inject *inject) 342static int __cmd_inject(struct perf_inject *inject)
221{ 343{
222 struct perf_session *session; 344 struct perf_session *session;
@@ -224,19 +346,48 @@ static int __cmd_inject(struct perf_inject *inject)
224 346
225 signal(SIGINT, sig_handler); 347 signal(SIGINT, sig_handler);
226 348
227 if (inject->build_ids) { 349 if (inject->build_ids || inject->sched_stat) {
228 inject->tool.sample = perf_event__inject_buildid;
229 inject->tool.mmap = perf_event__repipe_mmap; 350 inject->tool.mmap = perf_event__repipe_mmap;
230 inject->tool.fork = perf_event__repipe_task; 351 inject->tool.fork = perf_event__repipe_fork;
231 inject->tool.tracing_data = perf_event__repipe_tracing_data; 352 inject->tool.tracing_data = perf_event__repipe_tracing_data;
232 } 353 }
233 354
234 session = perf_session__new("-", O_RDONLY, false, true, &inject->tool); 355 session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool);
235 if (session == NULL) 356 if (session == NULL)
236 return -ENOMEM; 357 return -ENOMEM;
237 358
359 if (inject->build_ids) {
360 inject->tool.sample = perf_event__inject_buildid;
361 } else if (inject->sched_stat) {
362 struct perf_evsel *evsel;
363
364 inject->tool.ordered_samples = true;
365
366 list_for_each_entry(evsel, &session->evlist->entries, node) {
367 const char *name = perf_evsel__name(evsel);
368
369 if (!strcmp(name, "sched:sched_switch")) {
370 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
371 return -EINVAL;
372
373 evsel->handler.func = perf_inject__sched_switch;
374 } else if (!strcmp(name, "sched:sched_process_exit"))
375 evsel->handler.func = perf_inject__sched_process_exit;
376 else if (!strncmp(name, "sched:sched_stat_", 17))
377 evsel->handler.func = perf_inject__sched_stat;
378 }
379 }
380
381 if (!inject->pipe_output)
382 lseek(inject->output, session->header.data_offset, SEEK_SET);
383
238 ret = perf_session__process_events(session, &inject->tool); 384 ret = perf_session__process_events(session, &inject->tool);
239 385
386 if (!inject->pipe_output) {
387 session->header.data_size = inject->bytes_written;
388 perf_session__write_header(session, session->evlist, inject->output, true);
389 }
390
240 perf_session__delete(session); 391 perf_session__delete(session);
241 392
242 return ret; 393 return ret;
@@ -260,10 +411,20 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
260 .tracing_data = perf_event__repipe_tracing_data_synth, 411 .tracing_data = perf_event__repipe_tracing_data_synth,
261 .build_id = perf_event__repipe_op2_synth, 412 .build_id = perf_event__repipe_op2_synth,
262 }, 413 },
414 .input_name = "-",
415 .samples = LIST_HEAD_INIT(inject.samples),
263 }; 416 };
417 const char *output_name = "-";
264 const struct option options[] = { 418 const struct option options[] = {
265 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 419 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
266 "Inject build-ids into the output stream"), 420 "Inject build-ids into the output stream"),
421 OPT_STRING('i', "input", &inject.input_name, "file",
422 "input file name"),
423 OPT_STRING('o', "output", &output_name, "file",
424 "output file name"),
425 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
426 "Merge sched-stat and sched-switch for getting events "
427 "where and how long tasks slept"),
267 OPT_INCR('v', "verbose", &verbose, 428 OPT_INCR('v', "verbose", &verbose,
268 "be more verbose (show build ids, etc)"), 429 "be more verbose (show build ids, etc)"),
269 OPT_END() 430 OPT_END()
@@ -281,6 +442,18 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
281 if (argc) 442 if (argc)
282 usage_with_options(inject_usage, options); 443 usage_with_options(inject_usage, options);
283 444
445 if (!strcmp(output_name, "-")) {
446 inject.pipe_output = 1;
447 inject.output = STDOUT_FILENO;
448 } else {
449 inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC,
450 S_IRUSR | S_IWUSR);
451 if (inject.output < 0) {
452 perror("failed to create output file");
453 return -1;
454 }
455 }
456
284 if (symbol__init() < 0) 457 if (symbol__init() < 0)
285 return -1; 458 return -1;
286 459
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 14bf82f63659..0b4b796167be 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -477,7 +477,7 @@ static void sort_result(void)
477 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); 477 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
478} 478}
479 479
480static int __cmd_kmem(const char *input_name) 480static int __cmd_kmem(void)
481{ 481{
482 int err = -EINVAL; 482 int err = -EINVAL;
483 struct perf_session *session; 483 struct perf_session *session;
@@ -743,7 +743,6 @@ static int __cmd_record(int argc, const char **argv)
743int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) 743int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
744{ 744{
745 const char * const default_sort_order = "frag,hit,bytes"; 745 const char * const default_sort_order = "frag,hit,bytes";
746 const char *input_name = NULL;
747 const struct option kmem_options[] = { 746 const struct option kmem_options[] = {
748 OPT_STRING('i', "input", &input_name, "file", "input file name"), 747 OPT_STRING('i', "input", &input_name, "file", "input file name"),
749 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, 748 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
@@ -779,7 +778,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
779 if (list_empty(&alloc_sort)) 778 if (list_empty(&alloc_sort))
780 setup_sorting(&alloc_sort, default_sort_order); 779 setup_sorting(&alloc_sort, default_sort_order);
781 780
782 return __cmd_kmem(input_name); 781 return __cmd_kmem();
783 } else 782 } else
784 usage_with_options(kmem_usage, kmem_options); 783 usage_with_options(kmem_usage, kmem_options);
785 784
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 283b4397e397..ca3f80ebc100 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -314,9 +314,9 @@ struct vcpu_event_record {
314 314
315static void init_kvm_event_record(struct perf_kvm_stat *kvm) 315static void init_kvm_event_record(struct perf_kvm_stat *kvm)
316{ 316{
317 int i; 317 unsigned int i;
318 318
319 for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) 319 for (i = 0; i < EVENTS_CACHE_SIZE; i++)
320 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]); 320 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
321} 321}
322 322
@@ -370,9 +370,10 @@ static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,
370 BUG_ON(key->key == INVALID_KEY); 370 BUG_ON(key->key == INVALID_KEY);
371 371
372 head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)]; 372 head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)];
373 list_for_each_entry(event, head, hash_entry) 373 list_for_each_entry(event, head, hash_entry) {
374 if (event->key.key == key->key && event->key.info == key->info) 374 if (event->key.key == key->key && event->key.info == key->info)
375 return event; 375 return event;
376 }
376 377
377 event = kvm_alloc_init_event(key); 378 event = kvm_alloc_init_event(key);
378 if (!event) 379 if (!event)
@@ -417,7 +418,10 @@ static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)
417static bool update_kvm_event(struct kvm_event *event, int vcpu_id, 418static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
418 u64 time_diff) 419 u64 time_diff)
419{ 420{
420 kvm_update_event_stats(&event->total, time_diff); 421 if (vcpu_id == -1) {
422 kvm_update_event_stats(&event->total, time_diff);
423 return true;
424 }
421 425
422 if (!kvm_event_expand(event, vcpu_id)) 426 if (!kvm_event_expand(event, vcpu_id))
423 return false; 427 return false;
@@ -433,6 +437,12 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
433{ 437{
434 struct kvm_event *event; 438 struct kvm_event *event;
435 u64 time_begin, time_diff; 439 u64 time_begin, time_diff;
440 int vcpu;
441
442 if (kvm->trace_vcpu == -1)
443 vcpu = -1;
444 else
445 vcpu = vcpu_record->vcpu_id;
436 446
437 event = vcpu_record->last_event; 447 event = vcpu_record->last_event;
438 time_begin = vcpu_record->start_time; 448 time_begin = vcpu_record->start_time;
@@ -462,7 +472,7 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
462 BUG_ON(timestamp < time_begin); 472 BUG_ON(timestamp < time_begin);
463 473
464 time_diff = timestamp - time_begin; 474 time_diff = timestamp - time_begin;
465 return update_kvm_event(event, vcpu_record->vcpu_id, time_diff); 475 return update_kvm_event(event, vcpu, time_diff);
466} 476}
467 477
468static 478static
@@ -499,6 +509,11 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
499 if (!vcpu_record) 509 if (!vcpu_record)
500 return true; 510 return true;
501 511
512 /* only process events for vcpus user cares about */
513 if ((kvm->trace_vcpu != -1) &&
514 (kvm->trace_vcpu != vcpu_record->vcpu_id))
515 return true;
516
502 if (kvm->events_ops->is_begin_event(evsel, sample, &key)) 517 if (kvm->events_ops->is_begin_event(evsel, sample, &key))
503 return handle_begin_event(kvm, vcpu_record, &key, sample->time); 518 return handle_begin_event(kvm, vcpu_record, &key, sample->time);
504 519
@@ -598,13 +613,15 @@ static void sort_result(struct perf_kvm_stat *kvm)
598 int vcpu = kvm->trace_vcpu; 613 int vcpu = kvm->trace_vcpu;
599 struct kvm_event *event; 614 struct kvm_event *event;
600 615
601 for (i = 0; i < EVENTS_CACHE_SIZE; i++) 616 for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
602 list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) 617 list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) {
603 if (event_is_valid(event, vcpu)) { 618 if (event_is_valid(event, vcpu)) {
604 update_total_count(kvm, event); 619 update_total_count(kvm, event);
605 insert_to_result(&kvm->result, event, 620 insert_to_result(&kvm->result, event,
606 kvm->compare, vcpu); 621 kvm->compare, vcpu);
607 } 622 }
623 }
624 }
608} 625}
609 626
610/* returns left most element of result, and erase it */ 627/* returns left most element of result, and erase it */
@@ -661,8 +678,8 @@ static void print_result(struct perf_kvm_stat *kvm)
661 pr_info("\n"); 678 pr_info("\n");
662 } 679 }
663 680
664 pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", 681 pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",
665 (unsigned long long)kvm->total_count, kvm->total_time / 1e3); 682 kvm->total_count, kvm->total_time / 1e3);
666} 683}
667 684
668static int process_sample_event(struct perf_tool *tool, 685static int process_sample_event(struct perf_tool *tool,
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 6f5f328157aa..425830069749 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -335,8 +335,6 @@ alloc_failed:
335 return NULL; 335 return NULL;
336} 336}
337 337
338static const char *input_name;
339
340struct trace_lock_handler { 338struct trace_lock_handler {
341 int (*acquire_event)(struct perf_evsel *evsel, 339 int (*acquire_event)(struct perf_evsel *evsel,
342 struct perf_sample *sample); 340 struct perf_sample *sample);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e9231659754d..f3151d3c70ce 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -31,6 +31,38 @@
31#include <sched.h> 31#include <sched.h>
32#include <sys/mman.h> 32#include <sys/mman.h>
33 33
34#ifndef HAVE_ON_EXIT
35#ifndef ATEXIT_MAX
36#define ATEXIT_MAX 32
37#endif
38static int __on_exit_count = 0;
39typedef void (*on_exit_func_t) (int, void *);
40static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
41static void *__on_exit_args[ATEXIT_MAX];
42static int __exitcode = 0;
43static void __handle_on_exit_funcs(void);
44static int on_exit(on_exit_func_t function, void *arg);
45#define exit(x) (exit)(__exitcode = (x))
46
47static int on_exit(on_exit_func_t function, void *arg)
48{
49 if (__on_exit_count == ATEXIT_MAX)
50 return -ENOMEM;
51 else if (__on_exit_count == 0)
52 atexit(__handle_on_exit_funcs);
53 __on_exit_funcs[__on_exit_count] = function;
54 __on_exit_args[__on_exit_count++] = arg;
55 return 0;
56}
57
58static void __handle_on_exit_funcs(void)
59{
60 int i;
61 for (i = 0; i < __on_exit_count; i++)
62 __on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
63}
64#endif
65
34enum write_mode_t { 66enum write_mode_t {
35 WRITE_FORCE, 67 WRITE_FORCE,
36 WRITE_APPEND 68 WRITE_APPEND
@@ -198,11 +230,15 @@ static int perf_record__open(struct perf_record *rec)
198 struct perf_record_opts *opts = &rec->opts; 230 struct perf_record_opts *opts = &rec->opts;
199 int rc = 0; 231 int rc = 0;
200 232
201 perf_evlist__config_attrs(evlist, opts); 233 /*
202 234 * Set the evsel leader links before we configure attributes,
235 * since some might depend on this info.
236 */
203 if (opts->group) 237 if (opts->group)
204 perf_evlist__set_leader(evlist); 238 perf_evlist__set_leader(evlist);
205 239
240 perf_evlist__config_attrs(evlist, opts);
241
206 list_for_each_entry(pos, &evlist->entries, node) { 242 list_for_each_entry(pos, &evlist->entries, node) {
207 struct perf_event_attr *attr = &pos->attr; 243 struct perf_event_attr *attr = &pos->attr;
208 /* 244 /*
@@ -285,6 +321,11 @@ try_again:
285 perf_evsel__name(pos)); 321 perf_evsel__name(pos));
286 rc = -err; 322 rc = -err;
287 goto out; 323 goto out;
324 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
325 ui__error("\'precise\' request may not be supported. "
326 "Try removing 'p' modifier\n");
327 rc = -err;
328 goto out;
288 } 329 }
289 330
290 printf("\n"); 331 printf("\n");
@@ -326,7 +367,8 @@ try_again:
326 "or try again with a smaller value of -m/--mmap_pages.\n" 367 "or try again with a smaller value of -m/--mmap_pages.\n"
327 "(current value: %d)\n", opts->mmap_pages); 368 "(current value: %d)\n", opts->mmap_pages);
328 rc = -errno; 369 rc = -errno;
329 } else if (!is_power_of_2(opts->mmap_pages)) { 370 } else if (!is_power_of_2(opts->mmap_pages) &&
371 (opts->mmap_pages != UINT_MAX)) {
330 pr_err("--mmap_pages/-m value must be a power of two."); 372 pr_err("--mmap_pages/-m value must be a power of two.");
331 rc = -EINVAL; 373 rc = -EINVAL;
332 } else { 374 } else {
@@ -460,6 +502,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
460 struct perf_evlist *evsel_list = rec->evlist; 502 struct perf_evlist *evsel_list = rec->evlist;
461 const char *output_name = rec->output_name; 503 const char *output_name = rec->output_name;
462 struct perf_session *session; 504 struct perf_session *session;
505 bool disabled = false;
463 506
464 rec->progname = argv[0]; 507 rec->progname = argv[0];
465 508
@@ -659,7 +702,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
659 } 702 }
660 } 703 }
661 704
662 perf_evlist__enable(evsel_list); 705 /*
706 * When perf is starting the traced process, all the events
707 * (apart from group members) have enable_on_exec=1 set,
708 * so don't spoil it by prematurely enabling them.
709 */
710 if (!perf_target__none(&opts->target))
711 perf_evlist__enable(evsel_list);
663 712
664 /* 713 /*
665 * Let the child rip 714 * Let the child rip
@@ -682,8 +731,15 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
682 waking++; 731 waking++;
683 } 732 }
684 733
685 if (done) 734 /*
735 * When perf is starting the traced process, at the end events
736 * die with the process and we wait for that. Thus no need to
737 * disable events in this case.
738 */
739 if (done && !disabled && !perf_target__none(&opts->target)) {
686 perf_evlist__disable(evsel_list); 740 perf_evlist__disable(evsel_list);
741 disabled = true;
742 }
687 } 743 }
688 744
689 if (quiet || signr == SIGUSR1) 745 if (quiet || signr == SIGUSR1)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index a61725d89d3e..fc251005dd3d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -33,13 +33,13 @@
33#include "util/thread.h" 33#include "util/thread.h"
34#include "util/sort.h" 34#include "util/sort.h"
35#include "util/hist.h" 35#include "util/hist.h"
36#include "arch/common.h"
36 37
37#include <linux/bitmap.h> 38#include <linux/bitmap.h>
38 39
39struct perf_report { 40struct perf_report {
40 struct perf_tool tool; 41 struct perf_tool tool;
41 struct perf_session *session; 42 struct perf_session *session;
42 char const *input_name;
43 bool force, use_tui, use_gtk, use_stdio; 43 bool force, use_tui, use_gtk, use_stdio;
44 bool hide_unresolved; 44 bool hide_unresolved;
45 bool dont_use_callchains; 45 bool dont_use_callchains;
@@ -428,10 +428,11 @@ static int __cmd_report(struct perf_report *rep)
428 if (use_browser > 0) { 428 if (use_browser > 0) {
429 if (use_browser == 1) { 429 if (use_browser == 1) {
430 perf_evlist__tui_browse_hists(session->evlist, help, 430 perf_evlist__tui_browse_hists(session->evlist, help,
431 NULL, NULL, 0); 431 NULL,
432 &session->header.env);
432 } else if (use_browser == 2) { 433 } else if (use_browser == 2) {
433 perf_evlist__gtk_browse_hists(session->evlist, help, 434 perf_evlist__gtk_browse_hists(session->evlist, help,
434 NULL, NULL, 0); 435 NULL);
435 } 436 }
436 } else 437 } else
437 perf_evlist__tty_browse_hists(session->evlist, rep, help); 438 perf_evlist__tty_browse_hists(session->evlist, rep, help);
@@ -556,8 +557,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
556 .sample = process_sample_event, 557 .sample = process_sample_event,
557 .mmap = perf_event__process_mmap, 558 .mmap = perf_event__process_mmap,
558 .comm = perf_event__process_comm, 559 .comm = perf_event__process_comm,
559 .exit = perf_event__process_task, 560 .exit = perf_event__process_exit,
560 .fork = perf_event__process_task, 561 .fork = perf_event__process_fork,
561 .lost = perf_event__process_lost, 562 .lost = perf_event__process_lost,
562 .read = process_read_event, 563 .read = process_read_event,
563 .attr = perf_event__process_attr, 564 .attr = perf_event__process_attr,
@@ -570,7 +571,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
570 .pretty_printing_style = "normal", 571 .pretty_printing_style = "normal",
571 }; 572 };
572 const struct option options[] = { 573 const struct option options[] = {
573 OPT_STRING('i', "input", &report.input_name, "file", 574 OPT_STRING('i', "input", &input_name, "file",
574 "input file name"), 575 "input file name"),
575 OPT_INCR('v', "verbose", &verbose, 576 OPT_INCR('v', "verbose", &verbose,
576 "be more verbose (show symbol address, etc)"), 577 "be more verbose (show symbol address, etc)"),
@@ -656,13 +657,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
656 if (report.inverted_callchain) 657 if (report.inverted_callchain)
657 callchain_param.order = ORDER_CALLER; 658 callchain_param.order = ORDER_CALLER;
658 659
659 if (!report.input_name || !strlen(report.input_name)) { 660 if (!input_name || !strlen(input_name)) {
660 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) 661 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
661 report.input_name = "-"; 662 input_name = "-";
662 else 663 else
663 report.input_name = "perf.data"; 664 input_name = "perf.data";
664 } 665 }
665 session = perf_session__new(report.input_name, O_RDONLY, 666 session = perf_session__new(input_name, O_RDONLY,
666 report.force, false, &report.tool); 667 report.force, false, &report.tool);
667 if (session == NULL) 668 if (session == NULL)
668 return -ENOMEM; 669 return -ENOMEM;
@@ -687,7 +688,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
687 688
688 } 689 }
689 690
690 if (strcmp(report.input_name, "-") != 0) 691 if (strcmp(input_name, "-") != 0)
691 setup_browser(true); 692 setup_browser(true);
692 else { 693 else {
693 use_browser = 0; 694 use_browser = 0;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 3488ead3b60c..cc28b85dabd5 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -120,7 +120,6 @@ struct trace_sched_handler {
120 120
121struct perf_sched { 121struct perf_sched {
122 struct perf_tool tool; 122 struct perf_tool tool;
123 const char *input_name;
124 const char *sort_order; 123 const char *sort_order;
125 unsigned long nr_tasks; 124 unsigned long nr_tasks;
126 struct task_desc *pid_to_task[MAX_PID]; 125 struct task_desc *pid_to_task[MAX_PID];
@@ -1460,7 +1459,7 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1460 }; 1459 };
1461 struct perf_session *session; 1460 struct perf_session *session;
1462 1461
1463 session = perf_session__new(sched->input_name, O_RDONLY, 0, false, &sched->tool); 1462 session = perf_session__new(input_name, O_RDONLY, 0, false, &sched->tool);
1464 if (session == NULL) { 1463 if (session == NULL) {
1465 pr_debug("No Memory for session\n"); 1464 pr_debug("No Memory for session\n");
1466 return -1; 1465 return -1;
@@ -1672,7 +1671,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1672 .sample = perf_sched__process_tracepoint_sample, 1671 .sample = perf_sched__process_tracepoint_sample,
1673 .comm = perf_event__process_comm, 1672 .comm = perf_event__process_comm,
1674 .lost = perf_event__process_lost, 1673 .lost = perf_event__process_lost,
1675 .fork = perf_event__process_task, 1674 .exit = perf_event__process_exit,
1675 .fork = perf_event__process_fork,
1676 .ordered_samples = true, 1676 .ordered_samples = true,
1677 }, 1677 },
1678 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), 1678 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
@@ -1707,7 +1707,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1707 OPT_END() 1707 OPT_END()
1708 }; 1708 };
1709 const struct option sched_options[] = { 1709 const struct option sched_options[] = {
1710 OPT_STRING('i', "input", &sched.input_name, "file", 1710 OPT_STRING('i', "input", &input_name, "file",
1711 "input file name"), 1711 "input file name"),
1712 OPT_INCR('v', "verbose", &verbose, 1712 OPT_INCR('v', "verbose", &verbose,
1713 "be more verbose (show symbol address, etc)"), 1713 "be more verbose (show symbol address, etc)"),
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index fb9625083a2e..b363e7b292b2 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -520,8 +520,8 @@ static struct perf_tool perf_script = {
520 .sample = process_sample_event, 520 .sample = process_sample_event,
521 .mmap = perf_event__process_mmap, 521 .mmap = perf_event__process_mmap,
522 .comm = perf_event__process_comm, 522 .comm = perf_event__process_comm,
523 .exit = perf_event__process_task, 523 .exit = perf_event__process_exit,
524 .fork = perf_event__process_task, 524 .fork = perf_event__process_fork,
525 .attr = perf_event__process_attr, 525 .attr = perf_event__process_attr,
526 .event_type = perf_event__process_event_type, 526 .event_type = perf_event__process_event_type,
527 .tracing_data = perf_event__process_tracing_data, 527 .tracing_data = perf_event__process_tracing_data,
@@ -1030,6 +1030,68 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1030} 1030}
1031 1031
1032/* 1032/*
1033 * Some scripts specify the required events in their "xxx-record" file,
1034 * this function will check if the events in perf.data match those
1035 * mentioned in the "xxx-record".
1036 *
1037 * Fixme: All existing "xxx-record" are all in good formats "-e event ",
1038 * which is covered well now. And new parsing code should be added to
1039 * cover the future complexing formats like event groups etc.
1040 */
1041static int check_ev_match(char *dir_name, char *scriptname,
1042 struct perf_session *session)
1043{
1044 char filename[MAXPATHLEN], evname[128];
1045 char line[BUFSIZ], *p;
1046 struct perf_evsel *pos;
1047 int match, len;
1048 FILE *fp;
1049
1050 sprintf(filename, "%s/bin/%s-record", dir_name, scriptname);
1051
1052 fp = fopen(filename, "r");
1053 if (!fp)
1054 return -1;
1055
1056 while (fgets(line, sizeof(line), fp)) {
1057 p = ltrim(line);
1058 if (*p == '#')
1059 continue;
1060
1061 while (strlen(p)) {
1062 p = strstr(p, "-e");
1063 if (!p)
1064 break;
1065
1066 p += 2;
1067 p = ltrim(p);
1068 len = strcspn(p, " \t");
1069 if (!len)
1070 break;
1071
1072 snprintf(evname, len + 1, "%s", p);
1073
1074 match = 0;
1075 list_for_each_entry(pos,
1076 &session->evlist->entries, node) {
1077 if (!strcmp(perf_evsel__name(pos), evname)) {
1078 match = 1;
1079 break;
1080 }
1081 }
1082
1083 if (!match) {
1084 fclose(fp);
1085 return -1;
1086 }
1087 }
1088 }
1089
1090 fclose(fp);
1091 return 0;
1092}
1093
1094/*
1033 * Return -1 if none is found, otherwise the actual scripts number. 1095 * Return -1 if none is found, otherwise the actual scripts number.
1034 * 1096 *
1035 * Currently the only user of this function is the script browser, which 1097 * Currently the only user of this function is the script browser, which
@@ -1039,17 +1101,23 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1039int find_scripts(char **scripts_array, char **scripts_path_array) 1101int find_scripts(char **scripts_array, char **scripts_path_array)
1040{ 1102{
1041 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 1103 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
1042 char scripts_path[MAXPATHLEN]; 1104 char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
1043 DIR *scripts_dir, *lang_dir; 1105 DIR *scripts_dir, *lang_dir;
1044 char lang_path[MAXPATHLEN]; 1106 struct perf_session *session;
1045 char *temp; 1107 char *temp;
1046 int i = 0; 1108 int i = 0;
1047 1109
1110 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
1111 if (!session)
1112 return -1;
1113
1048 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 1114 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
1049 1115
1050 scripts_dir = opendir(scripts_path); 1116 scripts_dir = opendir(scripts_path);
1051 if (!scripts_dir) 1117 if (!scripts_dir) {
1118 perf_session__delete(session);
1052 return -1; 1119 return -1;
1120 }
1053 1121
1054 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { 1122 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
1055 snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path, 1123 snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path,
@@ -1077,10 +1145,18 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
1077 snprintf(scripts_array[i], 1145 snprintf(scripts_array[i],
1078 (temp - script_dirent.d_name) + 1, 1146 (temp - script_dirent.d_name) + 1,
1079 "%s", script_dirent.d_name); 1147 "%s", script_dirent.d_name);
1148
1149 if (check_ev_match(lang_path,
1150 scripts_array[i], session))
1151 continue;
1152
1080 i++; 1153 i++;
1081 } 1154 }
1155 closedir(lang_dir);
1082 } 1156 }
1083 1157
1158 closedir(scripts_dir);
1159 perf_session__delete(session);
1084 return i; 1160 return i;
1085} 1161}
1086 1162
@@ -1175,7 +1251,6 @@ static int have_cmd(int argc, const char **argv)
1175int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) 1251int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1176{ 1252{
1177 bool show_full_info = false; 1253 bool show_full_info = false;
1178 const char *input_name = NULL;
1179 char *rec_script_path = NULL; 1254 char *rec_script_path = NULL;
1180 char *rep_script_path = NULL; 1255 char *rep_script_path = NULL;
1181 struct perf_session *session; 1256 struct perf_session *session;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 93b9011fa3e2..c247faca7127 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -57,6 +57,7 @@
57#include "util/thread.h" 57#include "util/thread.h"
58#include "util/thread_map.h" 58#include "util/thread_map.h"
59 59
60#include <stdlib.h>
60#include <sys/prctl.h> 61#include <sys/prctl.h>
61#include <locale.h> 62#include <locale.h>
62 63
@@ -83,6 +84,9 @@ static const char *csv_sep = NULL;
83static bool csv_output = false; 84static bool csv_output = false;
84static bool group = false; 85static bool group = false;
85static FILE *output = NULL; 86static FILE *output = NULL;
87static const char *pre_cmd = NULL;
88static const char *post_cmd = NULL;
89static bool sync_run = false;
86 90
87static volatile int done = 0; 91static volatile int done = 0;
88 92
@@ -125,8 +129,7 @@ static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
125static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 129static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
126static struct stats walltime_nsecs_stats; 130static struct stats walltime_nsecs_stats;
127 131
128static int create_perf_stat_counter(struct perf_evsel *evsel, 132static int create_perf_stat_counter(struct perf_evsel *evsel)
129 struct perf_evsel *first)
130{ 133{
131 struct perf_event_attr *attr = &evsel->attr; 134 struct perf_event_attr *attr = &evsel->attr;
132 bool exclude_guest_missing = false; 135 bool exclude_guest_missing = false;
@@ -149,7 +152,8 @@ retry:
149 return 0; 152 return 0;
150 } 153 }
151 154
152 if (!perf_target__has_task(&target) && (!group || evsel == first)) { 155 if (!perf_target__has_task(&target) &&
156 !perf_evsel__is_group_member(evsel)) {
153 attr->disabled = 1; 157 attr->disabled = 1;
154 attr->enable_on_exec = 1; 158 attr->enable_on_exec = 1;
155 } 159 }
@@ -265,10 +269,10 @@ static int read_counter(struct perf_evsel *counter)
265 return 0; 269 return 0;
266} 270}
267 271
268static int run_perf_stat(int argc __maybe_unused, const char **argv) 272static int __run_perf_stat(int argc __maybe_unused, const char **argv)
269{ 273{
270 unsigned long long t0, t1; 274 unsigned long long t0, t1;
271 struct perf_evsel *counter, *first; 275 struct perf_evsel *counter;
272 int status = 0; 276 int status = 0;
273 int child_ready_pipe[2], go_pipe[2]; 277 int child_ready_pipe[2], go_pipe[2];
274 const bool forks = (argc > 0); 278 const bool forks = (argc > 0);
@@ -328,10 +332,8 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
328 if (group) 332 if (group)
329 perf_evlist__set_leader(evsel_list); 333 perf_evlist__set_leader(evsel_list);
330 334
331 first = perf_evlist__first(evsel_list);
332
333 list_for_each_entry(counter, &evsel_list->entries, node) { 335 list_for_each_entry(counter, &evsel_list->entries, node) {
334 if (create_perf_stat_counter(counter, first) < 0) { 336 if (create_perf_stat_counter(counter) < 0) {
335 /* 337 /*
336 * PPC returns ENXIO for HW counters until 2.6.37 338 * PPC returns ENXIO for HW counters until 2.6.37
337 * (behavior changed with commit b0a873e). 339 * (behavior changed with commit b0a873e).
@@ -405,6 +407,32 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
405 return WEXITSTATUS(status); 407 return WEXITSTATUS(status);
406} 408}
407 409
410static int run_perf_stat(int argc __maybe_unused, const char **argv)
411{
412 int ret;
413
414 if (pre_cmd) {
415 ret = system(pre_cmd);
416 if (ret)
417 return ret;
418 }
419
420 if (sync_run)
421 sync();
422
423 ret = __run_perf_stat(argc, argv);
424 if (ret)
425 return ret;
426
427 if (post_cmd) {
428 ret = system(post_cmd);
429 if (ret)
430 return ret;
431 }
432
433 return ret;
434}
435
408static void print_noise_pct(double total, double avg) 436static void print_noise_pct(double total, double avg)
409{ 437{
410 double pct = rel_stddev_stats(total, avg); 438 double pct = rel_stddev_stats(total, avg);
@@ -1069,8 +1097,7 @@ static int add_default_attributes(void)
1069 1097
1070int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) 1098int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1071{ 1099{
1072 bool append_file = false, 1100 bool append_file = false;
1073 sync_run = false;
1074 int output_fd = 0; 1101 int output_fd = 0;
1075 const char *output_name = NULL; 1102 const char *output_name = NULL;
1076 const struct option options[] = { 1103 const struct option options[] = {
@@ -1114,6 +1141,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1114 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), 1141 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
1115 OPT_INTEGER(0, "log-fd", &output_fd, 1142 OPT_INTEGER(0, "log-fd", &output_fd,
1116 "log output to fd, instead of stderr"), 1143 "log output to fd, instead of stderr"),
1144 OPT_STRING(0, "pre", &pre_cmd, "command",
1145 "command to run prior to the measured command"),
1146 OPT_STRING(0, "post", &post_cmd, "command",
1147 "command to run after to the measured command"),
1117 OPT_END() 1148 OPT_END()
1118 }; 1149 };
1119 const char * const stat_usage[] = { 1150 const char * const stat_usage[] = {
@@ -1238,9 +1269,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1238 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 1269 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
1239 run_idx + 1); 1270 run_idx + 1);
1240 1271
1241 if (sync_run)
1242 sync();
1243
1244 status = run_perf_stat(argc, argv); 1272 status = run_perf_stat(argc, argv);
1245 } 1273 }
1246 1274
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
deleted file mode 100644
index 5acd6e8e658b..000000000000
--- a/tools/perf/builtin-test.c
+++ /dev/null
@@ -1,1547 +0,0 @@
1/*
2 * builtin-test.c
3 *
4 * Builtin regression testing command: ever growing number of sanity tests
5 */
6#include "builtin.h"
7
8#include "util/cache.h"
9#include "util/debug.h"
10#include "util/debugfs.h"
11#include "util/evlist.h"
12#include "util/parse-options.h"
13#include "util/parse-events.h"
14#include "util/symbol.h"
15#include "util/thread_map.h"
16#include "util/pmu.h"
17#include "event-parse.h"
18#include <linux/hw_breakpoint.h>
19
20#include <sys/mman.h>
21
22static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
23 struct symbol *sym)
24{
25 bool *visited = symbol__priv(sym);
26 *visited = true;
27 return 0;
28}
29
30static int test__vmlinux_matches_kallsyms(void)
31{
32 int err = -1;
33 struct rb_node *nd;
34 struct symbol *sym;
35 struct map *kallsyms_map, *vmlinux_map;
36 struct machine kallsyms, vmlinux;
37 enum map_type type = MAP__FUNCTION;
38 long page_size = sysconf(_SC_PAGE_SIZE);
39 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
40
41 /*
42 * Step 1:
43 *
44 * Init the machines that will hold kernel, modules obtained from
45 * both vmlinux + .ko files and from /proc/kallsyms split by modules.
46 */
47 machine__init(&kallsyms, "", HOST_KERNEL_ID);
48 machine__init(&vmlinux, "", HOST_KERNEL_ID);
49
50 /*
51 * Step 2:
52 *
53 * Create the kernel maps for kallsyms and the DSO where we will then
54 * load /proc/kallsyms. Also create the modules maps from /proc/modules
55 * and find the .ko files that match them in /lib/modules/`uname -r`/.
56 */
57 if (machine__create_kernel_maps(&kallsyms) < 0) {
58 pr_debug("machine__create_kernel_maps ");
59 return -1;
60 }
61
62 /*
63 * Step 3:
64 *
65 * Load and split /proc/kallsyms into multiple maps, one per module.
66 */
67 if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) {
68 pr_debug("dso__load_kallsyms ");
69 goto out;
70 }
71
72 /*
73 * Step 4:
74 *
75 * kallsyms will be internally on demand sorted by name so that we can
76 * find the reference relocation * symbol, i.e. the symbol we will use
77 * to see if the running kernel was relocated by checking if it has the
78 * same value in the vmlinux file we load.
79 */
80 kallsyms_map = machine__kernel_map(&kallsyms, type);
81
82 sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL);
83 if (sym == NULL) {
84 pr_debug("dso__find_symbol_by_name ");
85 goto out;
86 }
87
88 ref_reloc_sym.addr = sym->start;
89
90 /*
91 * Step 5:
92 *
93 * Now repeat step 2, this time for the vmlinux file we'll auto-locate.
94 */
95 if (machine__create_kernel_maps(&vmlinux) < 0) {
96 pr_debug("machine__create_kernel_maps ");
97 goto out;
98 }
99
100 vmlinux_map = machine__kernel_map(&vmlinux, type);
101 map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym;
102
103 /*
104 * Step 6:
105 *
106 * Locate a vmlinux file in the vmlinux path that has a buildid that
107 * matches the one of the running kernel.
108 *
109 * While doing that look if we find the ref reloc symbol, if we find it
110 * we'll have its ref_reloc_symbol.unrelocated_addr and then
111 * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines
112 * to fixup the symbols.
113 */
114 if (machine__load_vmlinux_path(&vmlinux, type,
115 vmlinux_matches_kallsyms_filter) <= 0) {
116 pr_debug("machine__load_vmlinux_path ");
117 goto out;
118 }
119
120 err = 0;
121 /*
122 * Step 7:
123 *
124 * Now look at the symbols in the vmlinux DSO and check if we find all of them
125 * in the kallsyms dso. For the ones that are in both, check its names and
126 * end addresses too.
127 */
128 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
129 struct symbol *pair, *first_pair;
130 bool backwards = true;
131
132 sym = rb_entry(nd, struct symbol, rb_node);
133
134 if (sym->start == sym->end)
135 continue;
136
137 first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
138 pair = first_pair;
139
140 if (pair && pair->start == sym->start) {
141next_pair:
142 if (strcmp(sym->name, pair->name) == 0) {
143 /*
144 * kallsyms don't have the symbol end, so we
145 * set that by using the next symbol start - 1,
146 * in some cases we get this up to a page
147 * wrong, trace_kmalloc when I was developing
148 * this code was one such example, 2106 bytes
149 * off the real size. More than that and we
150 * _really_ have a problem.
151 */
152 s64 skew = sym->end - pair->end;
153 if (llabs(skew) < page_size)
154 continue;
155
156 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
157 sym->start, sym->name, sym->end, pair->end);
158 } else {
159 struct rb_node *nnd;
160detour:
161 nnd = backwards ? rb_prev(&pair->rb_node) :
162 rb_next(&pair->rb_node);
163 if (nnd) {
164 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
165
166 if (next->start == sym->start) {
167 pair = next;
168 goto next_pair;
169 }
170 }
171
172 if (backwards) {
173 backwards = false;
174 pair = first_pair;
175 goto detour;
176 }
177
178 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
179 sym->start, sym->name, pair->name);
180 }
181 } else
182 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
183
184 err = -1;
185 }
186
187 if (!verbose)
188 goto out;
189
190 pr_info("Maps only in vmlinux:\n");
191
192 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
193 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
194 /*
195 * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
196 * the kernel will have the path for the vmlinux file being used,
197 * so use the short name, less descriptive but the same ("[kernel]" in
198 * both cases.
199 */
200 pair = map_groups__find_by_name(&kallsyms.kmaps, type,
201 (pos->dso->kernel ?
202 pos->dso->short_name :
203 pos->dso->name));
204 if (pair)
205 pair->priv = 1;
206 else
207 map__fprintf(pos, stderr);
208 }
209
210 pr_info("Maps in vmlinux with a different name in kallsyms:\n");
211
212 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
213 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
214
215 pair = map_groups__find(&kallsyms.kmaps, type, pos->start);
216 if (pair == NULL || pair->priv)
217 continue;
218
219 if (pair->start == pos->start) {
220 pair->priv = 1;
221 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
222 pos->start, pos->end, pos->pgoff, pos->dso->name);
223 if (pos->pgoff != pair->pgoff || pos->end != pair->end)
224 pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
225 pair->start, pair->end, pair->pgoff);
226 pr_info(" %s\n", pair->dso->name);
227 pair->priv = 1;
228 }
229 }
230
231 pr_info("Maps only in kallsyms:\n");
232
233 for (nd = rb_first(&kallsyms.kmaps.maps[type]);
234 nd; nd = rb_next(nd)) {
235 struct map *pos = rb_entry(nd, struct map, rb_node);
236
237 if (!pos->priv)
238 map__fprintf(pos, stderr);
239 }
240out:
241 return err;
242}
243
244#include "util/cpumap.h"
245#include "util/evsel.h"
246#include <sys/types.h>
247
248static int trace_event__id(const char *evname)
249{
250 char *filename;
251 int err = -1, fd;
252
253 if (asprintf(&filename,
254 "%s/syscalls/%s/id",
255 tracing_events_path, evname) < 0)
256 return -1;
257
258 fd = open(filename, O_RDONLY);
259 if (fd >= 0) {
260 char id[16];
261 if (read(fd, id, sizeof(id)) > 0)
262 err = atoi(id);
263 close(fd);
264 }
265
266 free(filename);
267 return err;
268}
269
270static int test__open_syscall_event(void)
271{
272 int err = -1, fd;
273 struct thread_map *threads;
274 struct perf_evsel *evsel;
275 struct perf_event_attr attr;
276 unsigned int nr_open_calls = 111, i;
277 int id = trace_event__id("sys_enter_open");
278
279 if (id < 0) {
280 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
281 return -1;
282 }
283
284 threads = thread_map__new(-1, getpid(), UINT_MAX);
285 if (threads == NULL) {
286 pr_debug("thread_map__new\n");
287 return -1;
288 }
289
290 memset(&attr, 0, sizeof(attr));
291 attr.type = PERF_TYPE_TRACEPOINT;
292 attr.config = id;
293 evsel = perf_evsel__new(&attr, 0);
294 if (evsel == NULL) {
295 pr_debug("perf_evsel__new\n");
296 goto out_thread_map_delete;
297 }
298
299 if (perf_evsel__open_per_thread(evsel, threads) < 0) {
300 pr_debug("failed to open counter: %s, "
301 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
302 strerror(errno));
303 goto out_evsel_delete;
304 }
305
306 for (i = 0; i < nr_open_calls; ++i) {
307 fd = open("/etc/passwd", O_RDONLY);
308 close(fd);
309 }
310
311 if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
312 pr_debug("perf_evsel__read_on_cpu\n");
313 goto out_close_fd;
314 }
315
316 if (evsel->counts->cpu[0].val != nr_open_calls) {
317 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
318 nr_open_calls, evsel->counts->cpu[0].val);
319 goto out_close_fd;
320 }
321
322 err = 0;
323out_close_fd:
324 perf_evsel__close_fd(evsel, 1, threads->nr);
325out_evsel_delete:
326 perf_evsel__delete(evsel);
327out_thread_map_delete:
328 thread_map__delete(threads);
329 return err;
330}
331
332#include <sched.h>
333
334static int test__open_syscall_event_on_all_cpus(void)
335{
336 int err = -1, fd, cpu;
337 struct thread_map *threads;
338 struct cpu_map *cpus;
339 struct perf_evsel *evsel;
340 struct perf_event_attr attr;
341 unsigned int nr_open_calls = 111, i;
342 cpu_set_t cpu_set;
343 int id = trace_event__id("sys_enter_open");
344
345 if (id < 0) {
346 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
347 return -1;
348 }
349
350 threads = thread_map__new(-1, getpid(), UINT_MAX);
351 if (threads == NULL) {
352 pr_debug("thread_map__new\n");
353 return -1;
354 }
355
356 cpus = cpu_map__new(NULL);
357 if (cpus == NULL) {
358 pr_debug("cpu_map__new\n");
359 goto out_thread_map_delete;
360 }
361
362
363 CPU_ZERO(&cpu_set);
364
365 memset(&attr, 0, sizeof(attr));
366 attr.type = PERF_TYPE_TRACEPOINT;
367 attr.config = id;
368 evsel = perf_evsel__new(&attr, 0);
369 if (evsel == NULL) {
370 pr_debug("perf_evsel__new\n");
371 goto out_thread_map_delete;
372 }
373
374 if (perf_evsel__open(evsel, cpus, threads) < 0) {
375 pr_debug("failed to open counter: %s, "
376 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
377 strerror(errno));
378 goto out_evsel_delete;
379 }
380
381 for (cpu = 0; cpu < cpus->nr; ++cpu) {
382 unsigned int ncalls = nr_open_calls + cpu;
383 /*
384 * XXX eventually lift this restriction in a way that
385 * keeps perf building on older glibc installations
386 * without CPU_ALLOC. 1024 cpus in 2010 still seems
387 * a reasonable upper limit tho :-)
388 */
389 if (cpus->map[cpu] >= CPU_SETSIZE) {
390 pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
391 continue;
392 }
393
394 CPU_SET(cpus->map[cpu], &cpu_set);
395 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
396 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
397 cpus->map[cpu],
398 strerror(errno));
399 goto out_close_fd;
400 }
401 for (i = 0; i < ncalls; ++i) {
402 fd = open("/etc/passwd", O_RDONLY);
403 close(fd);
404 }
405 CPU_CLR(cpus->map[cpu], &cpu_set);
406 }
407
408 /*
409 * Here we need to explicitely preallocate the counts, as if
410 * we use the auto allocation it will allocate just for 1 cpu,
411 * as we start by cpu 0.
412 */
413 if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
414 pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
415 goto out_close_fd;
416 }
417
418 err = 0;
419
420 for (cpu = 0; cpu < cpus->nr; ++cpu) {
421 unsigned int expected;
422
423 if (cpus->map[cpu] >= CPU_SETSIZE)
424 continue;
425
426 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
427 pr_debug("perf_evsel__read_on_cpu\n");
428 err = -1;
429 break;
430 }
431
432 expected = nr_open_calls + cpu;
433 if (evsel->counts->cpu[cpu].val != expected) {
434 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
435 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
436 err = -1;
437 }
438 }
439
440out_close_fd:
441 perf_evsel__close_fd(evsel, 1, threads->nr);
442out_evsel_delete:
443 perf_evsel__delete(evsel);
444out_thread_map_delete:
445 thread_map__delete(threads);
446 return err;
447}
448
449/*
450 * This test will generate random numbers of calls to some getpid syscalls,
451 * then establish an mmap for a group of events that are created to monitor
452 * the syscalls.
453 *
454 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
455 * sample.id field to map back to its respective perf_evsel instance.
456 *
457 * Then it checks if the number of syscalls reported as perf events by
458 * the kernel corresponds to the number of syscalls made.
459 */
460static int test__basic_mmap(void)
461{
462 int err = -1;
463 union perf_event *event;
464 struct thread_map *threads;
465 struct cpu_map *cpus;
466 struct perf_evlist *evlist;
467 struct perf_event_attr attr = {
468 .type = PERF_TYPE_TRACEPOINT,
469 .read_format = PERF_FORMAT_ID,
470 .sample_type = PERF_SAMPLE_ID,
471 .watermark = 0,
472 };
473 cpu_set_t cpu_set;
474 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
475 "getpgid", };
476 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
477 (void*)getpgid };
478#define nsyscalls ARRAY_SIZE(syscall_names)
479 int ids[nsyscalls];
480 unsigned int nr_events[nsyscalls],
481 expected_nr_events[nsyscalls], i, j;
482 struct perf_evsel *evsels[nsyscalls], *evsel;
483
484 for (i = 0; i < nsyscalls; ++i) {
485 char name[64];
486
487 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
488 ids[i] = trace_event__id(name);
489 if (ids[i] < 0) {
490 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
491 return -1;
492 }
493 nr_events[i] = 0;
494 expected_nr_events[i] = random() % 257;
495 }
496
497 threads = thread_map__new(-1, getpid(), UINT_MAX);
498 if (threads == NULL) {
499 pr_debug("thread_map__new\n");
500 return -1;
501 }
502
503 cpus = cpu_map__new(NULL);
504 if (cpus == NULL) {
505 pr_debug("cpu_map__new\n");
506 goto out_free_threads;
507 }
508
509 CPU_ZERO(&cpu_set);
510 CPU_SET(cpus->map[0], &cpu_set);
511 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
512 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
513 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
514 cpus->map[0], strerror(errno));
515 goto out_free_cpus;
516 }
517
518 evlist = perf_evlist__new(cpus, threads);
519 if (evlist == NULL) {
520 pr_debug("perf_evlist__new\n");
521 goto out_free_cpus;
522 }
523
524 /* anonymous union fields, can't be initialized above */
525 attr.wakeup_events = 1;
526 attr.sample_period = 1;
527
528 for (i = 0; i < nsyscalls; ++i) {
529 attr.config = ids[i];
530 evsels[i] = perf_evsel__new(&attr, i);
531 if (evsels[i] == NULL) {
532 pr_debug("perf_evsel__new\n");
533 goto out_free_evlist;
534 }
535
536 perf_evlist__add(evlist, evsels[i]);
537
538 if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
539 pr_debug("failed to open counter: %s, "
540 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
541 strerror(errno));
542 goto out_close_fd;
543 }
544 }
545
546 if (perf_evlist__mmap(evlist, 128, true) < 0) {
547 pr_debug("failed to mmap events: %d (%s)\n", errno,
548 strerror(errno));
549 goto out_close_fd;
550 }
551
552 for (i = 0; i < nsyscalls; ++i)
553 for (j = 0; j < expected_nr_events[i]; ++j) {
554 int foo = syscalls[i]();
555 ++foo;
556 }
557
558 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
559 struct perf_sample sample;
560
561 if (event->header.type != PERF_RECORD_SAMPLE) {
562 pr_debug("unexpected %s event\n",
563 perf_event__name(event->header.type));
564 goto out_munmap;
565 }
566
567 err = perf_evlist__parse_sample(evlist, event, &sample);
568 if (err) {
569 pr_err("Can't parse sample, err = %d\n", err);
570 goto out_munmap;
571 }
572
573 evsel = perf_evlist__id2evsel(evlist, sample.id);
574 if (evsel == NULL) {
575 pr_debug("event with id %" PRIu64
576 " doesn't map to an evsel\n", sample.id);
577 goto out_munmap;
578 }
579 nr_events[evsel->idx]++;
580 }
581
582 list_for_each_entry(evsel, &evlist->entries, node) {
583 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
584 pr_debug("expected %d %s events, got %d\n",
585 expected_nr_events[evsel->idx],
586 perf_evsel__name(evsel), nr_events[evsel->idx]);
587 goto out_munmap;
588 }
589 }
590
591 err = 0;
592out_munmap:
593 perf_evlist__munmap(evlist);
594out_close_fd:
595 for (i = 0; i < nsyscalls; ++i)
596 perf_evsel__close_fd(evsels[i], 1, threads->nr);
597out_free_evlist:
598 perf_evlist__delete(evlist);
599out_free_cpus:
600 cpu_map__delete(cpus);
601out_free_threads:
602 thread_map__delete(threads);
603 return err;
604#undef nsyscalls
605}
606
607static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
608 size_t *sizep)
609{
610 cpu_set_t *mask;
611 size_t size;
612 int i, cpu = -1, nrcpus = 1024;
613realloc:
614 mask = CPU_ALLOC(nrcpus);
615 size = CPU_ALLOC_SIZE(nrcpus);
616 CPU_ZERO_S(size, mask);
617
618 if (sched_getaffinity(pid, size, mask) == -1) {
619 CPU_FREE(mask);
620 if (errno == EINVAL && nrcpus < (1024 << 8)) {
621 nrcpus = nrcpus << 2;
622 goto realloc;
623 }
624 perror("sched_getaffinity");
625 return -1;
626 }
627
628 for (i = 0; i < nrcpus; i++) {
629 if (CPU_ISSET_S(i, size, mask)) {
630 if (cpu == -1) {
631 cpu = i;
632 *maskp = mask;
633 *sizep = size;
634 } else
635 CPU_CLR_S(i, size, mask);
636 }
637 }
638
639 if (cpu == -1)
640 CPU_FREE(mask);
641
642 return cpu;
643}
644
645static int test__PERF_RECORD(void)
646{
647 struct perf_record_opts opts = {
648 .target = {
649 .uid = UINT_MAX,
650 .uses_mmap = true,
651 },
652 .no_delay = true,
653 .freq = 10,
654 .mmap_pages = 256,
655 };
656 cpu_set_t *cpu_mask = NULL;
657 size_t cpu_mask_size = 0;
658 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
659 struct perf_evsel *evsel;
660 struct perf_sample sample;
661 const char *cmd = "sleep";
662 const char *argv[] = { cmd, "1", NULL, };
663 char *bname;
664 u64 prev_time = 0;
665 bool found_cmd_mmap = false,
666 found_libc_mmap = false,
667 found_vdso_mmap = false,
668 found_ld_mmap = false;
669 int err = -1, errs = 0, i, wakeups = 0;
670 u32 cpu;
671 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
672
673 if (evlist == NULL || argv == NULL) {
674 pr_debug("Not enough memory to create evlist\n");
675 goto out;
676 }
677
678 /*
679 * We need at least one evsel in the evlist, use the default
680 * one: "cycles".
681 */
682 err = perf_evlist__add_default(evlist);
683 if (err < 0) {
684 pr_debug("Not enough memory to create evsel\n");
685 goto out_delete_evlist;
686 }
687
688 /*
689 * Create maps of threads and cpus to monitor. In this case
690 * we start with all threads and cpus (-1, -1) but then in
691 * perf_evlist__prepare_workload we'll fill in the only thread
692 * we're monitoring, the one forked there.
693 */
694 err = perf_evlist__create_maps(evlist, &opts.target);
695 if (err < 0) {
696 pr_debug("Not enough memory to create thread/cpu maps\n");
697 goto out_delete_evlist;
698 }
699
700 /*
701 * Prepare the workload in argv[] to run, it'll fork it, and then wait
702 * for perf_evlist__start_workload() to exec it. This is done this way
703 * so that we have time to open the evlist (calling sys_perf_event_open
704 * on all the fds) and then mmap them.
705 */
706 err = perf_evlist__prepare_workload(evlist, &opts, argv);
707 if (err < 0) {
708 pr_debug("Couldn't run the workload!\n");
709 goto out_delete_evlist;
710 }
711
712 /*
713 * Config the evsels, setting attr->comm on the first one, etc.
714 */
715 evsel = perf_evlist__first(evlist);
716 evsel->attr.sample_type |= PERF_SAMPLE_CPU;
717 evsel->attr.sample_type |= PERF_SAMPLE_TID;
718 evsel->attr.sample_type |= PERF_SAMPLE_TIME;
719 perf_evlist__config_attrs(evlist, &opts);
720
721 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask,
722 &cpu_mask_size);
723 if (err < 0) {
724 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
725 goto out_delete_evlist;
726 }
727
728 cpu = err;
729
730 /*
731 * So that we can check perf_sample.cpu on all the samples.
732 */
733 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) {
734 pr_debug("sched_setaffinity: %s\n", strerror(errno));
735 goto out_free_cpu_mask;
736 }
737
738 /*
739 * Call sys_perf_event_open on all the fds on all the evsels,
740 * grouping them if asked to.
741 */
742 err = perf_evlist__open(evlist);
743 if (err < 0) {
744 pr_debug("perf_evlist__open: %s\n", strerror(errno));
745 goto out_delete_evlist;
746 }
747
748 /*
749 * mmap the first fd on a given CPU and ask for events for the other
750 * fds in the same CPU to be injected in the same mmap ring buffer
751 * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)).
752 */
753 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
754 if (err < 0) {
755 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
756 goto out_delete_evlist;
757 }
758
759 /*
760 * Now that all is properly set up, enable the events, they will
761 * count just on workload.pid, which will start...
762 */
763 perf_evlist__enable(evlist);
764
765 /*
766 * Now!
767 */
768 perf_evlist__start_workload(evlist);
769
770 while (1) {
771 int before = total_events;
772
773 for (i = 0; i < evlist->nr_mmaps; i++) {
774 union perf_event *event;
775
776 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
777 const u32 type = event->header.type;
778 const char *name = perf_event__name(type);
779
780 ++total_events;
781 if (type < PERF_RECORD_MAX)
782 nr_events[type]++;
783
784 err = perf_evlist__parse_sample(evlist, event, &sample);
785 if (err < 0) {
786 if (verbose)
787 perf_event__fprintf(event, stderr);
788 pr_debug("Couldn't parse sample\n");
789 goto out_err;
790 }
791
792 if (verbose) {
793 pr_info("%" PRIu64" %d ", sample.time, sample.cpu);
794 perf_event__fprintf(event, stderr);
795 }
796
797 if (prev_time > sample.time) {
798 pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n",
799 name, prev_time, sample.time);
800 ++errs;
801 }
802
803 prev_time = sample.time;
804
805 if (sample.cpu != cpu) {
806 pr_debug("%s with unexpected cpu, expected %d, got %d\n",
807 name, cpu, sample.cpu);
808 ++errs;
809 }
810
811 if ((pid_t)sample.pid != evlist->workload.pid) {
812 pr_debug("%s with unexpected pid, expected %d, got %d\n",
813 name, evlist->workload.pid, sample.pid);
814 ++errs;
815 }
816
817 if ((pid_t)sample.tid != evlist->workload.pid) {
818 pr_debug("%s with unexpected tid, expected %d, got %d\n",
819 name, evlist->workload.pid, sample.tid);
820 ++errs;
821 }
822
823 if ((type == PERF_RECORD_COMM ||
824 type == PERF_RECORD_MMAP ||
825 type == PERF_RECORD_FORK ||
826 type == PERF_RECORD_EXIT) &&
827 (pid_t)event->comm.pid != evlist->workload.pid) {
828 pr_debug("%s with unexpected pid/tid\n", name);
829 ++errs;
830 }
831
832 if ((type == PERF_RECORD_COMM ||
833 type == PERF_RECORD_MMAP) &&
834 event->comm.pid != event->comm.tid) {
835 pr_debug("%s with different pid/tid!\n", name);
836 ++errs;
837 }
838
839 switch (type) {
840 case PERF_RECORD_COMM:
841 if (strcmp(event->comm.comm, cmd)) {
842 pr_debug("%s with unexpected comm!\n", name);
843 ++errs;
844 }
845 break;
846 case PERF_RECORD_EXIT:
847 goto found_exit;
848 case PERF_RECORD_MMAP:
849 bname = strrchr(event->mmap.filename, '/');
850 if (bname != NULL) {
851 if (!found_cmd_mmap)
852 found_cmd_mmap = !strcmp(bname + 1, cmd);
853 if (!found_libc_mmap)
854 found_libc_mmap = !strncmp(bname + 1, "libc", 4);
855 if (!found_ld_mmap)
856 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
857 } else if (!found_vdso_mmap)
858 found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
859 break;
860
861 case PERF_RECORD_SAMPLE:
862 /* Just ignore samples for now */
863 break;
864 default:
865 pr_debug("Unexpected perf_event->header.type %d!\n",
866 type);
867 ++errs;
868 }
869 }
870 }
871
872 /*
873 * We don't use poll here because at least at 3.1 times the
874 * PERF_RECORD_{!SAMPLE} events don't honour
875 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
876 */
877 if (total_events == before && false)
878 poll(evlist->pollfd, evlist->nr_fds, -1);
879
880 sleep(1);
881 if (++wakeups > 5) {
882 pr_debug("No PERF_RECORD_EXIT event!\n");
883 break;
884 }
885 }
886
887found_exit:
888 if (nr_events[PERF_RECORD_COMM] > 1) {
889 pr_debug("Excessive number of PERF_RECORD_COMM events!\n");
890 ++errs;
891 }
892
893 if (nr_events[PERF_RECORD_COMM] == 0) {
894 pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd);
895 ++errs;
896 }
897
898 if (!found_cmd_mmap) {
899 pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd);
900 ++errs;
901 }
902
903 if (!found_libc_mmap) {
904 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc");
905 ++errs;
906 }
907
908 if (!found_ld_mmap) {
909 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld");
910 ++errs;
911 }
912
913 if (!found_vdso_mmap) {
914 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
915 ++errs;
916 }
917out_err:
918 perf_evlist__munmap(evlist);
919out_free_cpu_mask:
920 CPU_FREE(cpu_mask);
921out_delete_evlist:
922 perf_evlist__delete(evlist);
923out:
924 return (err < 0 || errs > 0) ? -1 : 0;
925}
926
927
928#if defined(__x86_64__) || defined(__i386__)
929
930#define barrier() asm volatile("" ::: "memory")
931
932static u64 rdpmc(unsigned int counter)
933{
934 unsigned int low, high;
935
936 asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
937
938 return low | ((u64)high) << 32;
939}
940
941static u64 rdtsc(void)
942{
943 unsigned int low, high;
944
945 asm volatile("rdtsc" : "=a" (low), "=d" (high));
946
947 return low | ((u64)high) << 32;
948}
949
950static u64 mmap_read_self(void *addr)
951{
952 struct perf_event_mmap_page *pc = addr;
953 u32 seq, idx, time_mult = 0, time_shift = 0;
954 u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
955
956 do {
957 seq = pc->lock;
958 barrier();
959
960 enabled = pc->time_enabled;
961 running = pc->time_running;
962
963 if (enabled != running) {
964 cyc = rdtsc();
965 time_mult = pc->time_mult;
966 time_shift = pc->time_shift;
967 time_offset = pc->time_offset;
968 }
969
970 idx = pc->index;
971 count = pc->offset;
972 if (idx)
973 count += rdpmc(idx - 1);
974
975 barrier();
976 } while (pc->lock != seq);
977
978 if (enabled != running) {
979 u64 quot, rem;
980
981 quot = (cyc >> time_shift);
982 rem = cyc & ((1 << time_shift) - 1);
983 delta = time_offset + quot * time_mult +
984 ((rem * time_mult) >> time_shift);
985
986 enabled += delta;
987 if (idx)
988 running += delta;
989
990 quot = count / running;
991 rem = count % running;
992 count = quot * enabled + (rem * enabled) / running;
993 }
994
995 return count;
996}
997
998/*
999 * If the RDPMC instruction faults then signal this back to the test parent task:
1000 */
1001static void segfault_handler(int sig __maybe_unused,
1002 siginfo_t *info __maybe_unused,
1003 void *uc __maybe_unused)
1004{
1005 exit(-1);
1006}
1007
1008static int __test__rdpmc(void)
1009{
1010 long page_size = sysconf(_SC_PAGE_SIZE);
1011 volatile int tmp = 0;
1012 u64 i, loops = 1000;
1013 int n;
1014 int fd;
1015 void *addr;
1016 struct perf_event_attr attr = {
1017 .type = PERF_TYPE_HARDWARE,
1018 .config = PERF_COUNT_HW_INSTRUCTIONS,
1019 .exclude_kernel = 1,
1020 };
1021 u64 delta_sum = 0;
1022 struct sigaction sa;
1023
1024 sigfillset(&sa.sa_mask);
1025 sa.sa_sigaction = segfault_handler;
1026 sigaction(SIGSEGV, &sa, NULL);
1027
1028 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
1029 if (fd < 0) {
1030 pr_err("Error: sys_perf_event_open() syscall returned "
1031 "with %d (%s)\n", fd, strerror(errno));
1032 return -1;
1033 }
1034
1035 addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
1036 if (addr == (void *)(-1)) {
1037 pr_err("Error: mmap() syscall returned with (%s)\n",
1038 strerror(errno));
1039 goto out_close;
1040 }
1041
1042 for (n = 0; n < 6; n++) {
1043 u64 stamp, now, delta;
1044
1045 stamp = mmap_read_self(addr);
1046
1047 for (i = 0; i < loops; i++)
1048 tmp++;
1049
1050 now = mmap_read_self(addr);
1051 loops *= 10;
1052
1053 delta = now - stamp;
1054 pr_debug("%14d: %14Lu\n", n, (long long)delta);
1055
1056 delta_sum += delta;
1057 }
1058
1059 munmap(addr, page_size);
1060 pr_debug(" ");
1061out_close:
1062 close(fd);
1063
1064 if (!delta_sum)
1065 return -1;
1066
1067 return 0;
1068}
1069
1070static int test__rdpmc(void)
1071{
1072 int status = 0;
1073 int wret = 0;
1074 int ret;
1075 int pid;
1076
1077 pid = fork();
1078 if (pid < 0)
1079 return -1;
1080
1081 if (!pid) {
1082 ret = __test__rdpmc();
1083
1084 exit(ret);
1085 }
1086
1087 wret = waitpid(pid, &status, 0);
1088 if (wret < 0 || status)
1089 return -1;
1090
1091 return 0;
1092}
1093
1094#endif
1095
1096static int test__perf_pmu(void)
1097{
1098 return perf_pmu__test();
1099}
1100
1101static int perf_evsel__roundtrip_cache_name_test(void)
1102{
1103 char name[128];
1104 int type, op, err = 0, ret = 0, i, idx;
1105 struct perf_evsel *evsel;
1106 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
1107
1108 if (evlist == NULL)
1109 return -ENOMEM;
1110
1111 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
1112 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
1113 /* skip invalid cache type */
1114 if (!perf_evsel__is_cache_op_valid(type, op))
1115 continue;
1116
1117 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
1118 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
1119 name, sizeof(name));
1120 err = parse_events(evlist, name, 0);
1121 if (err)
1122 ret = err;
1123 }
1124 }
1125 }
1126
1127 idx = 0;
1128 evsel = perf_evlist__first(evlist);
1129
1130 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
1131 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
1132 /* skip invalid cache type */
1133 if (!perf_evsel__is_cache_op_valid(type, op))
1134 continue;
1135
1136 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
1137 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
1138 name, sizeof(name));
1139 if (evsel->idx != idx)
1140 continue;
1141
1142 ++idx;
1143
1144 if (strcmp(perf_evsel__name(evsel), name)) {
1145 pr_debug("%s != %s\n", perf_evsel__name(evsel), name);
1146 ret = -1;
1147 }
1148
1149 evsel = perf_evsel__next(evsel);
1150 }
1151 }
1152 }
1153
1154 perf_evlist__delete(evlist);
1155 return ret;
1156}
1157
1158static int __perf_evsel__name_array_test(const char *names[], int nr_names)
1159{
1160 int i, err;
1161 struct perf_evsel *evsel;
1162 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
1163
1164 if (evlist == NULL)
1165 return -ENOMEM;
1166
1167 for (i = 0; i < nr_names; ++i) {
1168 err = parse_events(evlist, names[i], 0);
1169 if (err) {
1170 pr_debug("failed to parse event '%s', err %d\n",
1171 names[i], err);
1172 goto out_delete_evlist;
1173 }
1174 }
1175
1176 err = 0;
1177 list_for_each_entry(evsel, &evlist->entries, node) {
1178 if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) {
1179 --err;
1180 pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]);
1181 }
1182 }
1183
1184out_delete_evlist:
1185 perf_evlist__delete(evlist);
1186 return err;
1187}
1188
1189#define perf_evsel__name_array_test(names) \
1190 __perf_evsel__name_array_test(names, ARRAY_SIZE(names))
1191
1192static int perf_evsel__roundtrip_name_test(void)
1193{
1194 int err = 0, ret = 0;
1195
1196 err = perf_evsel__name_array_test(perf_evsel__hw_names);
1197 if (err)
1198 ret = err;
1199
1200 err = perf_evsel__name_array_test(perf_evsel__sw_names);
1201 if (err)
1202 ret = err;
1203
1204 err = perf_evsel__roundtrip_cache_name_test();
1205 if (err)
1206 ret = err;
1207
1208 return ret;
1209}
1210
1211static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
1212 int size, bool should_be_signed)
1213{
1214 struct format_field *field = perf_evsel__field(evsel, name);
1215 int is_signed;
1216 int ret = 0;
1217
1218 if (field == NULL) {
1219 pr_debug("%s: \"%s\" field not found!\n", evsel->name, name);
1220 return -1;
1221 }
1222
1223 is_signed = !!(field->flags | FIELD_IS_SIGNED);
1224 if (should_be_signed && !is_signed) {
1225 pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n",
1226 evsel->name, name, is_signed, should_be_signed);
1227 ret = -1;
1228 }
1229
1230 if (field->size != size) {
1231 pr_debug("%s: \"%s\" size (%d) should be %d!\n",
1232 evsel->name, name, field->size, size);
1233 ret = -1;
1234 }
1235
1236 return ret;
1237}
1238
1239static int perf_evsel__tp_sched_test(void)
1240{
1241 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch", 0);
1242 int ret = 0;
1243
1244 if (evsel == NULL) {
1245 pr_debug("perf_evsel__new\n");
1246 return -1;
1247 }
1248
1249 if (perf_evsel__test_field(evsel, "prev_comm", 16, true))
1250 ret = -1;
1251
1252 if (perf_evsel__test_field(evsel, "prev_pid", 4, true))
1253 ret = -1;
1254
1255 if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
1256 ret = -1;
1257
1258 if (perf_evsel__test_field(evsel, "prev_state", 8, true))
1259 ret = -1;
1260
1261 if (perf_evsel__test_field(evsel, "next_comm", 16, true))
1262 ret = -1;
1263
1264 if (perf_evsel__test_field(evsel, "next_pid", 4, true))
1265 ret = -1;
1266
1267 if (perf_evsel__test_field(evsel, "next_prio", 4, true))
1268 ret = -1;
1269
1270 perf_evsel__delete(evsel);
1271
1272 evsel = perf_evsel__newtp("sched", "sched_wakeup", 0);
1273
1274 if (perf_evsel__test_field(evsel, "comm", 16, true))
1275 ret = -1;
1276
1277 if (perf_evsel__test_field(evsel, "pid", 4, true))
1278 ret = -1;
1279
1280 if (perf_evsel__test_field(evsel, "prio", 4, true))
1281 ret = -1;
1282
1283 if (perf_evsel__test_field(evsel, "success", 4, true))
1284 ret = -1;
1285
1286 if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
1287 ret = -1;
1288
1289 return ret;
1290}
1291
1292static int test__syscall_open_tp_fields(void)
1293{
1294 struct perf_record_opts opts = {
1295 .target = {
1296 .uid = UINT_MAX,
1297 .uses_mmap = true,
1298 },
1299 .no_delay = true,
1300 .freq = 1,
1301 .mmap_pages = 256,
1302 .raw_samples = true,
1303 };
1304 const char *filename = "/etc/passwd";
1305 int flags = O_RDONLY | O_DIRECTORY;
1306 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
1307 struct perf_evsel *evsel;
1308 int err = -1, i, nr_events = 0, nr_polls = 0;
1309
1310 if (evlist == NULL) {
1311 pr_debug("%s: perf_evlist__new\n", __func__);
1312 goto out;
1313 }
1314
1315 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
1316 if (evsel == NULL) {
1317 pr_debug("%s: perf_evsel__newtp\n", __func__);
1318 goto out_delete_evlist;
1319 }
1320
1321 perf_evlist__add(evlist, evsel);
1322
1323 err = perf_evlist__create_maps(evlist, &opts.target);
1324 if (err < 0) {
1325 pr_debug("%s: perf_evlist__create_maps\n", __func__);
1326 goto out_delete_evlist;
1327 }
1328
1329 perf_evsel__config(evsel, &opts, evsel);
1330
1331 evlist->threads->map[0] = getpid();
1332
1333 err = perf_evlist__open(evlist);
1334 if (err < 0) {
1335 pr_debug("perf_evlist__open: %s\n", strerror(errno));
1336 goto out_delete_evlist;
1337 }
1338
1339 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1340 if (err < 0) {
1341 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
1342 goto out_delete_evlist;
1343 }
1344
1345 perf_evlist__enable(evlist);
1346
1347 /*
1348 * Generate the event:
1349 */
1350 open(filename, flags);
1351
1352 while (1) {
1353 int before = nr_events;
1354
1355 for (i = 0; i < evlist->nr_mmaps; i++) {
1356 union perf_event *event;
1357
1358 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1359 const u32 type = event->header.type;
1360 int tp_flags;
1361 struct perf_sample sample;
1362
1363 ++nr_events;
1364
1365 if (type != PERF_RECORD_SAMPLE)
1366 continue;
1367
1368 err = perf_evsel__parse_sample(evsel, event, &sample);
1369 if (err) {
1370 pr_err("Can't parse sample, err = %d\n", err);
1371 goto out_munmap;
1372 }
1373
1374 tp_flags = perf_evsel__intval(evsel, &sample, "flags");
1375
1376 if (flags != tp_flags) {
1377 pr_debug("%s: Expected flags=%#x, got %#x\n",
1378 __func__, flags, tp_flags);
1379 goto out_munmap;
1380 }
1381
1382 goto out_ok;
1383 }
1384 }
1385
1386 if (nr_events == before)
1387 poll(evlist->pollfd, evlist->nr_fds, 10);
1388
1389 if (++nr_polls > 5) {
1390 pr_debug("%s: no events!\n", __func__);
1391 goto out_munmap;
1392 }
1393 }
1394out_ok:
1395 err = 0;
1396out_munmap:
1397 perf_evlist__munmap(evlist);
1398out_delete_evlist:
1399 perf_evlist__delete(evlist);
1400out:
1401 return err;
1402}
1403
1404static struct test {
1405 const char *desc;
1406 int (*func)(void);
1407} tests[] = {
1408 {
1409 .desc = "vmlinux symtab matches kallsyms",
1410 .func = test__vmlinux_matches_kallsyms,
1411 },
1412 {
1413 .desc = "detect open syscall event",
1414 .func = test__open_syscall_event,
1415 },
1416 {
1417 .desc = "detect open syscall event on all cpus",
1418 .func = test__open_syscall_event_on_all_cpus,
1419 },
1420 {
1421 .desc = "read samples using the mmap interface",
1422 .func = test__basic_mmap,
1423 },
1424 {
1425 .desc = "parse events tests",
1426 .func = parse_events__test,
1427 },
1428#if defined(__x86_64__) || defined(__i386__)
1429 {
1430 .desc = "x86 rdpmc test",
1431 .func = test__rdpmc,
1432 },
1433#endif
1434 {
1435 .desc = "Validate PERF_RECORD_* events & perf_sample fields",
1436 .func = test__PERF_RECORD,
1437 },
1438 {
1439 .desc = "Test perf pmu format parsing",
1440 .func = test__perf_pmu,
1441 },
1442 {
1443 .desc = "Test dso data interface",
1444 .func = dso__test_data,
1445 },
1446 {
1447 .desc = "roundtrip evsel->name check",
1448 .func = perf_evsel__roundtrip_name_test,
1449 },
1450 {
1451 .desc = "Check parsing of sched tracepoints fields",
1452 .func = perf_evsel__tp_sched_test,
1453 },
1454 {
1455 .desc = "Generate and check syscalls:sys_enter_open event fields",
1456 .func = test__syscall_open_tp_fields,
1457 },
1458 {
1459 .func = NULL,
1460 },
1461};
1462
1463static bool perf_test__matches(int curr, int argc, const char *argv[])
1464{
1465 int i;
1466
1467 if (argc == 0)
1468 return true;
1469
1470 for (i = 0; i < argc; ++i) {
1471 char *end;
1472 long nr = strtoul(argv[i], &end, 10);
1473
1474 if (*end == '\0') {
1475 if (nr == curr + 1)
1476 return true;
1477 continue;
1478 }
1479
1480 if (strstr(tests[curr].desc, argv[i]))
1481 return true;
1482 }
1483
1484 return false;
1485}
1486
1487static int __cmd_test(int argc, const char *argv[])
1488{
1489 int i = 0;
1490
1491 while (tests[i].func) {
1492 int curr = i++, err;
1493
1494 if (!perf_test__matches(curr, argc, argv))
1495 continue;
1496
1497 pr_info("%2d: %s:", i, tests[curr].desc);
1498 pr_debug("\n--- start ---\n");
1499 err = tests[curr].func();
1500 pr_debug("---- end ----\n%s:", tests[curr].desc);
1501 pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
1502 }
1503
1504 return 0;
1505}
1506
1507static int perf_test__list(int argc, const char **argv)
1508{
1509 int i = 0;
1510
1511 while (tests[i].func) {
1512 int curr = i++;
1513
1514 if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
1515 continue;
1516
1517 pr_info("%2d: %s\n", i, tests[curr].desc);
1518 }
1519
1520 return 0;
1521}
1522
1523int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
1524{
1525 const char * const test_usage[] = {
1526 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
1527 NULL,
1528 };
1529 const struct option test_options[] = {
1530 OPT_INCR('v', "verbose", &verbose,
1531 "be more verbose (show symbol address, etc)"),
1532 OPT_END()
1533 };
1534
1535 argc = parse_options(argc, argv, test_options, test_usage, 0);
1536 if (argc >= 1 && !strcmp(argv[0], "list"))
1537 return perf_test__list(argc, argv);
1538
1539 symbol_conf.priv_size = sizeof(int);
1540 symbol_conf.sort_by_name = true;
1541 symbol_conf.try_vmlinux_path = true;
1542
1543 if (symbol__init() < 0)
1544 return -1;
1545
1546 return __cmd_test(argc, argv);
1547}
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index f251b613b2f3..ab4cf232b852 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -965,7 +965,7 @@ static void write_svg_file(const char *filename)
965 svg_close(); 965 svg_close();
966} 966}
967 967
968static int __cmd_timechart(const char *input_name, const char *output_name) 968static int __cmd_timechart(const char *output_name)
969{ 969{
970 struct perf_tool perf_timechart = { 970 struct perf_tool perf_timechart = {
971 .comm = process_comm_event, 971 .comm = process_comm_event,
@@ -1061,7 +1061,6 @@ parse_process(const struct option *opt __maybe_unused, const char *arg,
1061int cmd_timechart(int argc, const char **argv, 1061int cmd_timechart(int argc, const char **argv,
1062 const char *prefix __maybe_unused) 1062 const char *prefix __maybe_unused)
1063{ 1063{
1064 const char *input_name;
1065 const char *output_name = "output.svg"; 1064 const char *output_name = "output.svg";
1066 const struct option options[] = { 1065 const struct option options[] = {
1067 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1066 OPT_STRING('i', "input", &input_name, "file", "input file name"),
@@ -1092,5 +1091,5 @@ int cmd_timechart(int argc, const char **argv,
1092 1091
1093 setup_pager(); 1092 setup_pager();
1094 1093
1095 return __cmd_timechart(input_name, output_name); 1094 return __cmd_timechart(output_name);
1096} 1095}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ff6db8086805..c9ff3950cd4b 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -26,6 +26,7 @@
26#include "util/color.h" 26#include "util/color.h"
27#include "util/evlist.h" 27#include "util/evlist.h"
28#include "util/evsel.h" 28#include "util/evsel.h"
29#include "util/machine.h"
29#include "util/session.h" 30#include "util/session.h"
30#include "util/symbol.h" 31#include "util/symbol.h"
31#include "util/thread.h" 32#include "util/thread.h"
@@ -581,6 +582,11 @@ static void *display_thread_tui(void *arg)
581 struct perf_evsel *pos; 582 struct perf_evsel *pos;
582 struct perf_top *top = arg; 583 struct perf_top *top = arg;
583 const char *help = "For a higher level overview, try: perf top --sort comm,dso"; 584 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
585 struct hist_browser_timer hbt = {
586 .timer = perf_top__sort_new_samples,
587 .arg = top,
588 .refresh = top->delay_secs,
589 };
584 590
585 perf_top__sort_new_samples(top); 591 perf_top__sort_new_samples(top);
586 592
@@ -592,9 +598,8 @@ static void *display_thread_tui(void *arg)
592 list_for_each_entry(pos, &top->evlist->entries, node) 598 list_for_each_entry(pos, &top->evlist->entries, node)
593 pos->hists.uid_filter_str = top->target.uid_str; 599 pos->hists.uid_filter_str = top->target.uid_str;
594 600
595 perf_evlist__tui_browse_hists(top->evlist, help, 601 perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
596 perf_top__sort_new_samples, 602 &top->session->header.env);
597 top, top->delay_secs);
598 603
599 exit_browser(0); 604 exit_browser(0);
600 exit(0); 605 exit(0);
@@ -871,7 +876,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
871 &sample, machine); 876 &sample, machine);
872 } else if (event->header.type < PERF_RECORD_MAX) { 877 } else if (event->header.type < PERF_RECORD_MAX) {
873 hists__inc_nr_events(&evsel->hists, event->header.type); 878 hists__inc_nr_events(&evsel->hists, event->header.type);
874 perf_event__process(&top->tool, event, &sample, machine); 879 machine__process_event(machine, event);
875 } else 880 } else
876 ++session->hists.stats.nr_unknown_events; 881 ++session->hists.stats.nr_unknown_events;
877 } 882 }
@@ -976,6 +981,10 @@ try_again:
976 ui__error("Too many events are opened.\n" 981 ui__error("Too many events are opened.\n"
977 "Try again after reducing the number of events\n"); 982 "Try again after reducing the number of events\n");
978 goto out_err; 983 goto out_err;
984 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
985 ui__error("\'precise\' request may not be supported. "
986 "Try removing 'p' modifier\n");
987 goto out_err;
979 } 988 }
980 989
981 ui__error("The sys_perf_event_open() syscall " 990 ui__error("The sys_perf_event_open() syscall "
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 7aaee39f6774..7932ffa29889 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1,5 +1,8 @@
1#include "builtin.h" 1#include "builtin.h"
2#include "util/color.h"
2#include "util/evlist.h" 3#include "util/evlist.h"
4#include "util/machine.h"
5#include "util/thread.h"
3#include "util/parse-options.h" 6#include "util/parse-options.h"
4#include "util/thread_map.h" 7#include "util/thread_map.h"
5#include "event-parse.h" 8#include "event-parse.h"
@@ -13,15 +16,18 @@ static struct syscall_fmt {
13 bool errmsg; 16 bool errmsg;
14 bool timeout; 17 bool timeout;
15} syscall_fmts[] = { 18} syscall_fmts[] = {
19 { .name = "access", .errmsg = true, },
16 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, 20 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
17 { .name = "fstat", .errmsg = true, .alias = "newfstat", }, 21 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
18 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, 22 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
19 { .name = "futex", .errmsg = true, }, 23 { .name = "futex", .errmsg = true, },
24 { .name = "open", .errmsg = true, },
20 { .name = "poll", .errmsg = true, .timeout = true, }, 25 { .name = "poll", .errmsg = true, .timeout = true, },
21 { .name = "ppoll", .errmsg = true, .timeout = true, }, 26 { .name = "ppoll", .errmsg = true, .timeout = true, },
22 { .name = "read", .errmsg = true, }, 27 { .name = "read", .errmsg = true, },
23 { .name = "recvfrom", .errmsg = true, }, 28 { .name = "recvfrom", .errmsg = true, },
24 { .name = "select", .errmsg = true, .timeout = true, }, 29 { .name = "select", .errmsg = true, .timeout = true, },
30 { .name = "socket", .errmsg = true, },
25 { .name = "stat", .errmsg = true, .alias = "newstat", }, 31 { .name = "stat", .errmsg = true, .alias = "newstat", },
26}; 32};
27 33
@@ -43,6 +49,57 @@ struct syscall {
43 struct syscall_fmt *fmt; 49 struct syscall_fmt *fmt;
44}; 50};
45 51
52static size_t fprintf_duration(unsigned long t, FILE *fp)
53{
54 double duration = (double)t / NSEC_PER_MSEC;
55 size_t printed = fprintf(fp, "(");
56
57 if (duration >= 1.0)
58 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
59 else if (duration >= 0.01)
60 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
61 else
62 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
63 return printed + fprintf(stdout, "): ");
64}
65
66struct thread_trace {
67 u64 entry_time;
68 u64 exit_time;
69 bool entry_pending;
70 unsigned long nr_events;
71 char *entry_str;
72 double runtime_ms;
73};
74
75static struct thread_trace *thread_trace__new(void)
76{
77 return zalloc(sizeof(struct thread_trace));
78}
79
80static struct thread_trace *thread__trace(struct thread *thread)
81{
82 struct thread_trace *ttrace;
83
84 if (thread == NULL)
85 goto fail;
86
87 if (thread->priv == NULL)
88 thread->priv = thread_trace__new();
89
90 if (thread->priv == NULL)
91 goto fail;
92
93 ttrace = thread->priv;
94 ++ttrace->nr_events;
95
96 return ttrace;
97fail:
98 color_fprintf(stdout, PERF_COLOR_RED,
99 "WARNING: not enough memory, dropping samples!\n");
100 return NULL;
101}
102
46struct trace { 103struct trace {
47 int audit_machine; 104 int audit_machine;
48 struct { 105 struct {
@@ -50,8 +107,96 @@ struct trace {
50 struct syscall *table; 107 struct syscall *table;
51 } syscalls; 108 } syscalls;
52 struct perf_record_opts opts; 109 struct perf_record_opts opts;
110 struct machine host;
111 u64 base_time;
112 unsigned long nr_events;
113 bool sched;
114 bool multiple_threads;
115 double duration_filter;
116 double runtime_ms;
53}; 117};
54 118
119static bool trace__filter_duration(struct trace *trace, double t)
120{
121 return t < (trace->duration_filter * NSEC_PER_MSEC);
122}
123
124static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
125{
126 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
127
128 return fprintf(fp, "%10.3f ", ts);
129}
130
131static bool done = false;
132
133static void sig_handler(int sig __maybe_unused)
134{
135 done = true;
136}
137
138static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
139 u64 duration, u64 tstamp, FILE *fp)
140{
141 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
142 printed += fprintf_duration(duration, fp);
143
144 if (trace->multiple_threads)
145 printed += fprintf(fp, "%d ", thread->pid);
146
147 return printed;
148}
149
150static int trace__process_event(struct machine *machine, union perf_event *event)
151{
152 int ret = 0;
153
154 switch (event->header.type) {
155 case PERF_RECORD_LOST:
156 color_fprintf(stdout, PERF_COLOR_RED,
157 "LOST %" PRIu64 " events!\n", event->lost.lost);
158 ret = machine__process_lost_event(machine, event);
159 default:
160 ret = machine__process_event(machine, event);
161 break;
162 }
163
164 return ret;
165}
166
167static int trace__tool_process(struct perf_tool *tool __maybe_unused,
168 union perf_event *event,
169 struct perf_sample *sample __maybe_unused,
170 struct machine *machine)
171{
172 return trace__process_event(machine, event);
173}
174
175static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
176{
177 int err = symbol__init();
178
179 if (err)
180 return err;
181
182 machine__init(&trace->host, "", HOST_KERNEL_ID);
183 machine__create_kernel_maps(&trace->host);
184
185 if (perf_target__has_task(&trace->opts.target)) {
186 err = perf_event__synthesize_thread_map(NULL, evlist->threads,
187 trace__tool_process,
188 &trace->host);
189 } else {
190 err = perf_event__synthesize_threads(NULL, trace__tool_process,
191 &trace->host);
192 }
193
194 if (err)
195 symbol__exit();
196
197 return err;
198}
199
55static int trace__read_syscall_info(struct trace *trace, int id) 200static int trace__read_syscall_info(struct trace *trace, int id)
56{ 201{
57 char tp_name[128]; 202 char tp_name[128];
@@ -93,7 +238,8 @@ static int trace__read_syscall_info(struct trace *trace, int id)
93 return sc->tp_format != NULL ? 0 : -1; 238 return sc->tp_format != NULL ? 0 : -1;
94} 239}
95 240
96static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FILE *fp) 241static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
242 unsigned long *args)
97{ 243{
98 int i = 0; 244 int i = 0;
99 size_t printed = 0; 245 size_t printed = 0;
@@ -102,12 +248,15 @@ static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FIL
102 struct format_field *field; 248 struct format_field *field;
103 249
104 for (field = sc->tp_format->format.fields->next; field; field = field->next) { 250 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
105 printed += fprintf(fp, "%s%s: %ld", printed ? ", " : "", 251 printed += scnprintf(bf + printed, size - printed,
106 field->name, args[i++]); 252 "%s%s: %ld", printed ? ", " : "",
253 field->name, args[i++]);
107 } 254 }
108 } else { 255 } else {
109 while (i < 6) { 256 while (i < 6) {
110 printed += fprintf(fp, "%sarg%d: %ld", printed ? ", " : "", i, args[i]); 257 printed += scnprintf(bf + printed, size - printed,
258 "%sarg%d: %ld",
259 printed ? ", " : "", i, args[i]);
111 ++i; 260 ++i;
112 } 261 }
113 } 262 }
@@ -139,17 +288,24 @@ static struct syscall *trace__syscall_info(struct trace *trace,
139 return &trace->syscalls.table[id]; 288 return &trace->syscalls.table[id];
140 289
141out_cant_read: 290out_cant_read:
142 printf("Problems reading syscall %d information\n", id); 291 printf("Problems reading syscall %d", id);
292 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
293 printf("(%s)", trace->syscalls.table[id].name);
294 puts(" information");
143 return NULL; 295 return NULL;
144} 296}
145 297
146static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 298static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
147 struct perf_sample *sample) 299 struct perf_sample *sample)
148{ 300{
301 char *msg;
149 void *args; 302 void *args;
303 size_t printed = 0;
304 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
150 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 305 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
306 struct thread_trace *ttrace = thread__trace(thread);
151 307
152 if (sc == NULL) 308 if (ttrace == NULL || sc == NULL)
153 return -1; 309 return -1;
154 310
155 args = perf_evsel__rawptr(evsel, sample, "args"); 311 args = perf_evsel__rawptr(evsel, sample, "args");
@@ -158,8 +314,27 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
158 return -1; 314 return -1;
159 } 315 }
160 316
161 printf("%s(", sc->name); 317 ttrace = thread->priv;
162 syscall__fprintf_args(sc, args, stdout); 318
319 if (ttrace->entry_str == NULL) {
320 ttrace->entry_str = malloc(1024);
321 if (!ttrace->entry_str)
322 return -1;
323 }
324
325 ttrace->entry_time = sample->time;
326 msg = ttrace->entry_str;
327 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
328
329 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
330
331 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
332 if (!trace->duration_filter) {
333 trace__fprintf_entry_head(trace, thread, 1, sample->time, stdout);
334 printf("%-70s\n", ttrace->entry_str);
335 }
336 } else
337 ttrace->entry_pending = true;
163 338
164 return 0; 339 return 0;
165} 340}
@@ -168,13 +343,37 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
168 struct perf_sample *sample) 343 struct perf_sample *sample)
169{ 344{
170 int ret; 345 int ret;
346 u64 duration = 0;
347 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
348 struct thread_trace *ttrace = thread__trace(thread);
171 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 349 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
172 350
173 if (sc == NULL) 351 if (ttrace == NULL || sc == NULL)
174 return -1; 352 return -1;
175 353
176 ret = perf_evsel__intval(evsel, sample, "ret"); 354 ret = perf_evsel__intval(evsel, sample, "ret");
177 355
356 ttrace = thread->priv;
357
358 ttrace->exit_time = sample->time;
359
360 if (ttrace->entry_time) {
361 duration = sample->time - ttrace->entry_time;
362 if (trace__filter_duration(trace, duration))
363 goto out;
364 } else if (trace->duration_filter)
365 goto out;
366
367 trace__fprintf_entry_head(trace, thread, duration, sample->time, stdout);
368
369 if (ttrace->entry_pending) {
370 printf("%-70s", ttrace->entry_str);
371 } else {
372 printf(" ... [");
373 color_fprintf(stdout, PERF_COLOR_YELLOW, "continued");
374 printf("]: %s()", sc->name);
375 }
376
178 if (ret < 0 && sc->fmt && sc->fmt->errmsg) { 377 if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
179 char bf[256]; 378 char bf[256];
180 const char *emsg = strerror_r(-ret, bf, sizeof(bf)), 379 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
@@ -187,14 +386,44 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
187 printf(") = %d", ret); 386 printf(") = %d", ret);
188 387
189 putchar('\n'); 388 putchar('\n');
389out:
390 ttrace->entry_pending = false;
391
392 return 0;
393}
394
395static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
396 struct perf_sample *sample)
397{
398 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
399 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
400 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
401 struct thread_trace *ttrace = thread__trace(thread);
402
403 if (ttrace == NULL)
404 goto out_dump;
405
406 ttrace->runtime_ms += runtime_ms;
407 trace->runtime_ms += runtime_ms;
408 return 0;
409
410out_dump:
411 printf("%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
412 evsel->name,
413 perf_evsel__strval(evsel, sample, "comm"),
414 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
415 runtime,
416 perf_evsel__intval(evsel, sample, "vruntime"));
190 return 0; 417 return 0;
191} 418}
192 419
193static int trace__run(struct trace *trace) 420static int trace__run(struct trace *trace, int argc, const char **argv)
194{ 421{
195 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 422 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
196 struct perf_evsel *evsel; 423 struct perf_evsel *evsel;
197 int err = -1, i, nr_events = 0, before; 424 int err = -1, i;
425 unsigned long before;
426 const bool forks = argc > 0;
198 427
199 if (evlist == NULL) { 428 if (evlist == NULL) {
200 printf("Not enough memory to run!\n"); 429 printf("Not enough memory to run!\n");
@@ -207,14 +436,38 @@ static int trace__run(struct trace *trace)
207 goto out_delete_evlist; 436 goto out_delete_evlist;
208 } 437 }
209 438
439 if (trace->sched &&
440 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
441 trace__sched_stat_runtime)) {
442 printf("Couldn't read the sched_stat_runtime tracepoint information!\n");
443 goto out_delete_evlist;
444 }
445
210 err = perf_evlist__create_maps(evlist, &trace->opts.target); 446 err = perf_evlist__create_maps(evlist, &trace->opts.target);
211 if (err < 0) { 447 if (err < 0) {
212 printf("Problems parsing the target to trace, check your options!\n"); 448 printf("Problems parsing the target to trace, check your options!\n");
213 goto out_delete_evlist; 449 goto out_delete_evlist;
214 } 450 }
215 451
452 err = trace__symbols_init(trace, evlist);
453 if (err < 0) {
454 printf("Problems initializing symbol libraries!\n");
455 goto out_delete_evlist;
456 }
457
216 perf_evlist__config_attrs(evlist, &trace->opts); 458 perf_evlist__config_attrs(evlist, &trace->opts);
217 459
460 signal(SIGCHLD, sig_handler);
461 signal(SIGINT, sig_handler);
462
463 if (forks) {
464 err = perf_evlist__prepare_workload(evlist, &trace->opts, argv);
465 if (err < 0) {
466 printf("Couldn't run the workload!\n");
467 goto out_delete_evlist;
468 }
469 }
470
218 err = perf_evlist__open(evlist); 471 err = perf_evlist__open(evlist);
219 if (err < 0) { 472 if (err < 0) {
220 printf("Couldn't create the events: %s\n", strerror(errno)); 473 printf("Couldn't create the events: %s\n", strerror(errno));
@@ -228,8 +481,13 @@ static int trace__run(struct trace *trace)
228 } 481 }
229 482
230 perf_evlist__enable(evlist); 483 perf_evlist__enable(evlist);
484
485 if (forks)
486 perf_evlist__start_workload(evlist);
487
488 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
231again: 489again:
232 before = nr_events; 490 before = trace->nr_events;
233 491
234 for (i = 0; i < evlist->nr_mmaps; i++) { 492 for (i = 0; i < evlist->nr_mmaps; i++) {
235 union perf_event *event; 493 union perf_event *event;
@@ -239,19 +497,7 @@ again:
239 tracepoint_handler handler; 497 tracepoint_handler handler;
240 struct perf_sample sample; 498 struct perf_sample sample;
241 499
242 ++nr_events; 500 ++trace->nr_events;
243
244 switch (type) {
245 case PERF_RECORD_SAMPLE:
246 break;
247 case PERF_RECORD_LOST:
248 printf("LOST %" PRIu64 " events!\n", event->lost.lost);
249 continue;
250 default:
251 printf("Unexpected %s event, skipping...\n",
252 perf_event__name(type));
253 continue;
254 }
255 501
256 err = perf_evlist__parse_sample(evlist, event, &sample); 502 err = perf_evlist__parse_sample(evlist, event, &sample);
257 if (err) { 503 if (err) {
@@ -259,14 +505,26 @@ again:
259 continue; 505 continue;
260 } 506 }
261 507
508 if (trace->base_time == 0)
509 trace->base_time = sample.time;
510
511 if (type != PERF_RECORD_SAMPLE) {
512 trace__process_event(&trace->host, event);
513 continue;
514 }
515
262 evsel = perf_evlist__id2evsel(evlist, sample.id); 516 evsel = perf_evlist__id2evsel(evlist, sample.id);
263 if (evsel == NULL) { 517 if (evsel == NULL) {
264 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); 518 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
265 continue; 519 continue;
266 } 520 }
267 521
268 if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) 522 if (sample.raw_data == NULL) {
269 printf("%d ", sample.tid); 523 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
524 perf_evsel__name(evsel), sample.tid,
525 sample.cpu, sample.raw_size);
526 continue;
527 }
270 528
271 if (sample.raw_data == NULL) { 529 if (sample.raw_data == NULL) {
272 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 530 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
@@ -280,8 +538,15 @@ again:
280 } 538 }
281 } 539 }
282 540
283 if (nr_events == before) 541 if (trace->nr_events == before) {
542 if (done)
543 goto out_delete_evlist;
544
284 poll(evlist->pollfd, evlist->nr_fds, -1); 545 poll(evlist->pollfd, evlist->nr_fds, -1);
546 }
547
548 if (done)
549 perf_evlist__disable(evlist);
285 550
286 goto again; 551 goto again;
287 552
@@ -291,10 +556,65 @@ out:
291 return err; 556 return err;
292} 557}
293 558
559static size_t trace__fprintf_threads_header(FILE *fp)
560{
561 size_t printed;
562
563 printed = fprintf(fp, "\n _____________________________________________________________________\n");
564 printed += fprintf(fp," __) Summary of events (__\n\n");
565 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
566 printed += fprintf(fp," _____________________________________________________________________\n\n");
567
568 return printed;
569}
570
571static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
572{
573 size_t printed = trace__fprintf_threads_header(fp);
574 struct rb_node *nd;
575
576 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
577 struct thread *thread = rb_entry(nd, struct thread, rb_node);
578 struct thread_trace *ttrace = thread->priv;
579 const char *color;
580 double ratio;
581
582 if (ttrace == NULL)
583 continue;
584
585 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
586
587 color = PERF_COLOR_NORMAL;
588 if (ratio > 50.0)
589 color = PERF_COLOR_RED;
590 else if (ratio > 25.0)
591 color = PERF_COLOR_GREEN;
592 else if (ratio > 5.0)
593 color = PERF_COLOR_YELLOW;
594
595 printed += color_fprintf(fp, color, "%20s", thread->comm);
596 printed += fprintf(fp, " - %-5d :%11lu [", thread->pid, ttrace->nr_events);
597 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
598 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
599 }
600
601 return printed;
602}
603
604static int trace__set_duration(const struct option *opt, const char *str,
605 int unset __maybe_unused)
606{
607 struct trace *trace = opt->value;
608
609 trace->duration_filter = atof(str);
610 return 0;
611}
612
294int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 613int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
295{ 614{
296 const char * const trace_usage[] = { 615 const char * const trace_usage[] = {
297 "perf trace [<options>]", 616 "perf trace [<options>] [<command>]",
617 "perf trace [<options>] -- <command> [<options>]",
298 NULL 618 NULL
299 }; 619 };
300 struct trace trace = { 620 struct trace trace = {
@@ -328,21 +648,38 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
328 "number of mmap data pages"), 648 "number of mmap data pages"),
329 OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user", 649 OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user",
330 "user to profile"), 650 "user to profile"),
651 OPT_CALLBACK(0, "duration", &trace, "float",
652 "show only events with duration > N.M ms",
653 trace__set_duration),
654 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
331 OPT_END() 655 OPT_END()
332 }; 656 };
333 int err; 657 int err;
658 char bf[BUFSIZ];
334 659
335 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 660 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
336 if (argc) 661
337 usage_with_options(trace_usage, trace_options); 662 err = perf_target__validate(&trace.opts.target);
663 if (err) {
664 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
665 printf("%s", bf);
666 return err;
667 }
338 668
339 err = perf_target__parse_uid(&trace.opts.target); 669 err = perf_target__parse_uid(&trace.opts.target);
340 if (err) { 670 if (err) {
341 char bf[BUFSIZ];
342 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 671 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
343 printf("%s", bf); 672 printf("%s", bf);
344 return err; 673 return err;
345 } 674 }
346 675
347 return trace__run(&trace); 676 if (!argc && perf_target__none(&trace.opts.target))
677 trace.opts.target.system_wide = true;
678
679 err = trace__run(&trace, argc, argv);
680
681 if (trace.sched && !err)
682 trace__fprintf_thread_summary(&trace, stdout);
683
684 return err;
348} 685}
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index 4add41bb0c7e..f5ac77485a4f 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -43,6 +43,15 @@ int main(void)
43} 43}
44endef 44endef
45 45
46define SOURCE_BIONIC
47#include <android/api-level.h>
48
49int main(void)
50{
51 return __ANDROID_API__;
52}
53endef
54
46define SOURCE_ELF_MMAP 55define SOURCE_ELF_MMAP
47#include <libelf.h> 56#include <libelf.h>
48int main(void) 57int main(void)
@@ -112,7 +121,10 @@ define SOURCE_PYTHON_VERSION
112#if PY_VERSION_HEX >= 0x03000000 121#if PY_VERSION_HEX >= 0x03000000
113 #error 122 #error
114#endif 123#endif
115int main(void){} 124int main(void)
125{
126 return 0;
127}
116endef 128endef
117define SOURCE_PYTHON_EMBED 129define SOURCE_PYTHON_EMBED
118#include <Python.h> 130#include <Python.h>
@@ -203,4 +215,13 @@ int main(void)
203 return audit_open(); 215 return audit_open();
204} 216}
205endef 217endef
206endif \ No newline at end of file 218endif
219
220define SOURCE_ON_EXIT
221#include <stdio.h>
222
223int main(void)
224{
225 return on_exit(NULL, NULL);
226}
227endef
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index 8046182a19eb..e5413125e6bb 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -180,9 +180,15 @@ _gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) 180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181 181
182# try-cc 182# try-cc
183# Usage: option = $(call try-cc, source-to-build, cc-options) 183# Usage: option = $(call try-cc, source-to-build, cc-options, msg)
184ifndef V
185TRY_CC_OUTPUT= > /dev/null 2>&1
186endif
187TRY_CC_MSG=echo " CHK $(3)" 1>&2;
188
184try-cc = $(shell sh -c \ 189try-cc = $(shell sh -c \
185 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \ 190 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
191 $(TRY_CC_MSG) \
186 echo "$(1)" | \ 192 echo "$(1)" | \
187 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ 193 $(CC) -x c - $(2) -o "$$TMP" $(TRY_CC_OUTPUT) && echo y; \
188 rm -f "$$TMP"') 194 rm -f "$$TMP"')
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 6d50eb0b4251..0f661fbce6a8 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -24,6 +24,7 @@ const char perf_more_info_string[] =
24 24
25int use_browser = -1; 25int use_browser = -1;
26static int use_pager = -1; 26static int use_pager = -1;
27const char *input_name;
27 28
28struct cmd_struct { 29struct cmd_struct {
29 const char *cmd; 30 const char *cmd;
@@ -84,21 +85,26 @@ int check_pager_config(const char *cmd)
84 return c.val; 85 return c.val;
85} 86}
86 87
87static int tui_command_config(const char *var, const char *value, void *data) 88static int browser_command_config(const char *var, const char *value, void *data)
88{ 89{
89 struct pager_config *c = data; 90 struct pager_config *c = data;
90 if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd)) 91 if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd))
91 c->val = perf_config_bool(var, value); 92 c->val = perf_config_bool(var, value);
93 if (!prefixcmp(var, "gtk.") && !strcmp(var + 4, c->cmd))
94 c->val = perf_config_bool(var, value) ? 2 : 0;
92 return 0; 95 return 0;
93} 96}
94 97
95/* returns 0 for "no tui", 1 for "use tui", and -1 for "not specified" */ 98/*
96static int check_tui_config(const char *cmd) 99 * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk",
100 * and -1 for "not specified"
101 */
102static int check_browser_config(const char *cmd)
97{ 103{
98 struct pager_config c; 104 struct pager_config c;
99 c.cmd = cmd; 105 c.cmd = cmd;
100 c.val = -1; 106 c.val = -1;
101 perf_config(tui_command_config, &c); 107 perf_config(browser_command_config, &c);
102 return c.val; 108 return c.val;
103} 109}
104 110
@@ -301,7 +307,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
301 prefix = NULL; /* setup_perf_directory(); */ 307 prefix = NULL; /* setup_perf_directory(); */
302 308
303 if (use_browser == -1) 309 if (use_browser == -1)
304 use_browser = check_tui_config(p->cmd); 310 use_browser = check_browser_config(p->cmd);
305 311
306 if (use_pager == -1 && p->option & RUN_SETUP) 312 if (use_pager == -1 && p->option & RUN_SETUP)
307 use_pager = check_pager_config(p->cmd); 313 use_pager = check_pager_config(p->cmd);
@@ -440,6 +446,8 @@ int main(int argc, const char **argv)
440{ 446{
441 const char *cmd; 447 const char *cmd;
442 448
449 page_size = sysconf(_SC_PAGE_SIZE);
450
443 cmd = perf_extract_argv0_path(argv[0]); 451 cmd = perf_extract_argv0_path(argv[0]);
444 if (!cmd) 452 if (!cmd)
445 cmd = "perf-help"; 453 cmd = "perf-help";
@@ -481,6 +489,8 @@ int main(int argc, const char **argv)
481 } 489 }
482 cmd = argv[0]; 490 cmd = argv[0];
483 491
492 test_attr__init();
493
484 /* 494 /*
485 * We use PATH to find perf commands, but we prepend some higher 495 * We use PATH to find perf commands, but we prepend some higher
486 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH 496 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 238f923f2218..2c340e7da458 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -26,6 +26,7 @@ void get_term_dimensions(struct winsize *ws);
26#endif 26#endif
27 27
28#ifdef __powerpc__ 28#ifdef __powerpc__
29#include "../../arch/powerpc/include/uapi/asm/unistd.h"
29#define rmb() asm volatile ("sync" ::: "memory") 30#define rmb() asm volatile ("sync" ::: "memory")
30#define cpu_relax() asm volatile ("" ::: "memory"); 31#define cpu_relax() asm volatile ("" ::: "memory");
31#define CPUINFO_PROC "cpu" 32#define CPUINFO_PROC "cpu"
@@ -164,13 +165,25 @@ static inline unsigned long long rdclock(void)
164 (void) (&_min1 == &_min2); \ 165 (void) (&_min1 == &_min2); \
165 _min1 < _min2 ? _min1 : _min2; }) 166 _min1 < _min2 ? _min1 : _min2; })
166 167
168extern bool test_attr__enabled;
169void test_attr__init(void);
170void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
171 int fd, int group_fd, unsigned long flags);
172
167static inline int 173static inline int
168sys_perf_event_open(struct perf_event_attr *attr, 174sys_perf_event_open(struct perf_event_attr *attr,
169 pid_t pid, int cpu, int group_fd, 175 pid_t pid, int cpu, int group_fd,
170 unsigned long flags) 176 unsigned long flags)
171{ 177{
172 return syscall(__NR_perf_event_open, attr, pid, cpu, 178 int fd;
173 group_fd, flags); 179
180 fd = syscall(__NR_perf_event_open, attr, pid, cpu,
181 group_fd, flags);
182
183 if (unlikely(test_attr__enabled))
184 test_attr__open(attr, pid, cpu, fd, group_fd, flags);
185
186 return fd;
174} 187}
175 188
176#define MAX_COUNTERS 256 189#define MAX_COUNTERS 256
@@ -198,6 +211,7 @@ struct branch_stack {
198 struct branch_entry entries[0]; 211 struct branch_entry entries[0];
199}; 212};
200 213
214extern const char *input_name;
201extern bool perf_host, perf_guest; 215extern bool perf_host, perf_guest;
202extern const char perf_version_string[]; 216extern const char perf_version_string[];
203 217
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
new file mode 100644
index 000000000000..25638a986257
--- /dev/null
+++ b/tools/perf/tests/attr.c
@@ -0,0 +1,175 @@
1
2/*
3 * The struct perf_event_attr test support.
4 *
5 * This test is embedded inside into perf directly and is governed
6 * by the PERF_TEST_ATTR environment variable and hook inside
7 * sys_perf_event_open function.
8 *
9 * The general idea is to store 'struct perf_event_attr' details for
10 * each event created within single perf command. Each event details
11 * are stored into separate text file. Once perf command is finished
12 * these files can be checked for values we expect for command.
13 *
14 * Besides 'struct perf_event_attr' values we also store 'fd' and
15 * 'group_fd' values to allow checking for groups created.
16 *
17 * This all is triggered by setting PERF_TEST_ATTR environment variable.
18 * It must contain name of existing directory with access and write
19 * permissions. All the event text files are stored there.
20 */
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <inttypes.h>
25#include <linux/types.h>
26#include <linux/kernel.h>
27#include "../perf.h"
28#include "util.h"
29#include "exec_cmd.h"
30#include "tests.h"
31
32#define ENV "PERF_TEST_ATTR"
33
34extern int verbose;
35
36bool test_attr__enabled;
37
38static char *dir;
39
40void test_attr__init(void)
41{
42 dir = getenv(ENV);
43 test_attr__enabled = (dir != NULL);
44}
45
46#define BUFSIZE 1024
47
48#define __WRITE_ASS(str, fmt, data) \
49do { \
50 char buf[BUFSIZE]; \
51 size_t size; \
52 \
53 size = snprintf(buf, BUFSIZE, #str "=%"fmt "\n", data); \
54 if (1 != fwrite(buf, size, 1, file)) { \
55 perror("test attr - failed to write event file"); \
56 fclose(file); \
57 return -1; \
58 } \
59 \
60} while (0)
61
62#define WRITE_ASS(field, fmt) __WRITE_ASS(field, fmt, attr->field)
63
64static int store_event(struct perf_event_attr *attr, pid_t pid, int cpu,
65 int fd, int group_fd, unsigned long flags)
66{
67 FILE *file;
68 char path[PATH_MAX];
69
70 snprintf(path, PATH_MAX, "%s/event-%d-%llu-%d", dir,
71 attr->type, attr->config, fd);
72
73 file = fopen(path, "w+");
74 if (!file) {
75 perror("test attr - failed to open event file");
76 return -1;
77 }
78
79 if (fprintf(file, "[event-%d-%llu-%d]\n",
80 attr->type, attr->config, fd) < 0) {
81 perror("test attr - failed to write event file");
82 fclose(file);
83 return -1;
84 }
85
86 /* syscall arguments */
87 __WRITE_ASS(fd, "d", fd);
88 __WRITE_ASS(group_fd, "d", group_fd);
89 __WRITE_ASS(cpu, "d", cpu);
90 __WRITE_ASS(pid, "d", pid);
91 __WRITE_ASS(flags, "lu", flags);
92
93 /* struct perf_event_attr */
94 WRITE_ASS(type, PRIu32);
95 WRITE_ASS(size, PRIu32);
96 WRITE_ASS(config, "llu");
97 WRITE_ASS(sample_period, "llu");
98 WRITE_ASS(sample_type, "llu");
99 WRITE_ASS(read_format, "llu");
100 WRITE_ASS(disabled, "d");
101 WRITE_ASS(inherit, "d");
102 WRITE_ASS(pinned, "d");
103 WRITE_ASS(exclusive, "d");
104 WRITE_ASS(exclude_user, "d");
105 WRITE_ASS(exclude_kernel, "d");
106 WRITE_ASS(exclude_hv, "d");
107 WRITE_ASS(exclude_idle, "d");
108 WRITE_ASS(mmap, "d");
109 WRITE_ASS(comm, "d");
110 WRITE_ASS(freq, "d");
111 WRITE_ASS(inherit_stat, "d");
112 WRITE_ASS(enable_on_exec, "d");
113 WRITE_ASS(task, "d");
114 WRITE_ASS(watermark, "d");
115 WRITE_ASS(precise_ip, "d");
116 WRITE_ASS(mmap_data, "d");
117 WRITE_ASS(sample_id_all, "d");
118 WRITE_ASS(exclude_host, "d");
119 WRITE_ASS(exclude_guest, "d");
120 WRITE_ASS(exclude_callchain_kernel, "d");
121 WRITE_ASS(exclude_callchain_user, "d");
122 WRITE_ASS(wakeup_events, PRIu32);
123 WRITE_ASS(bp_type, PRIu32);
124 WRITE_ASS(config1, "llu");
125 WRITE_ASS(config2, "llu");
126 WRITE_ASS(branch_sample_type, "llu");
127 WRITE_ASS(sample_regs_user, "llu");
128 WRITE_ASS(sample_stack_user, PRIu32);
129
130 fclose(file);
131 return 0;
132}
133
134void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
135 int fd, int group_fd, unsigned long flags)
136{
137 int errno_saved = errno;
138
139 if (store_event(attr, pid, cpu, fd, group_fd, flags))
140 die("test attr FAILED");
141
142 errno = errno_saved;
143}
144
145static int run_dir(const char *d, const char *perf)
146{
147 char cmd[3*PATH_MAX];
148
149 snprintf(cmd, 3*PATH_MAX, "python %s/attr.py -d %s/attr/ -p %s %s",
150 d, d, perf, verbose ? "-v" : "");
151
152 return system(cmd);
153}
154
155int test__attr(void)
156{
157 struct stat st;
158 char path_perf[PATH_MAX];
159 char path_dir[PATH_MAX];
160
161 /* First try developement tree tests. */
162 if (!lstat("./tests", &st))
163 return run_dir("./tests", "./perf");
164
165 /* Then installed path. */
166 snprintf(path_dir, PATH_MAX, "%s/tests", perf_exec_path());
167 snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
168
169 if (!lstat(path_dir, &st) &&
170 !lstat(path_perf, &st))
171 return run_dir(path_dir, path_perf);
172
173 fprintf(stderr, " (ommitted)");
174 return 0;
175}
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py
new file mode 100644
index 000000000000..e702b82dcb86
--- /dev/null
+++ b/tools/perf/tests/attr.py
@@ -0,0 +1,322 @@
1#! /usr/bin/python
2
3import os
4import sys
5import glob
6import optparse
7import tempfile
8import logging
9import shutil
10import ConfigParser
11
12class Fail(Exception):
13 def __init__(self, test, msg):
14 self.msg = msg
15 self.test = test
16 def getMsg(self):
17 return '\'%s\' - %s' % (self.test.path, self.msg)
18
19class Unsup(Exception):
20 def __init__(self, test):
21 self.test = test
22 def getMsg(self):
23 return '\'%s\'' % self.test.path
24
25class Event(dict):
26 terms = [
27 'flags',
28 'type',
29 'size',
30 'config',
31 'sample_period',
32 'sample_type',
33 'read_format',
34 'disabled',
35 'inherit',
36 'pinned',
37 'exclusive',
38 'exclude_user',
39 'exclude_kernel',
40 'exclude_hv',
41 'exclude_idle',
42 'mmap',
43 'comm',
44 'freq',
45 'inherit_stat',
46 'enable_on_exec',
47 'task',
48 'watermark',
49 'precise_ip',
50 'mmap_data',
51 'sample_id_all',
52 'exclude_host',
53 'exclude_guest',
54 'exclude_callchain_kernel',
55 'exclude_callchain_user',
56 'wakeup_events',
57 'bp_type',
58 'config1',
59 'config2',
60 'branch_sample_type',
61 'sample_regs_user',
62 'sample_stack_user',
63 ]
64
65 def add(self, data):
66 for key, val in data:
67 log.debug(" %s = %s" % (key, val))
68 self[key] = val
69
70 def __init__(self, name, data, base):
71 log.info(" Event %s" % name);
72 self.name = name;
73 self.group = ''
74 self.add(base)
75 self.add(data)
76
77 def compare_data(self, a, b):
78 # Allow multiple values in assignment separated by '|'
79 a_list = a.split('|')
80 b_list = b.split('|')
81
82 for a_item in a_list:
83 for b_item in b_list:
84 if (a_item == b_item):
85 return True
86 elif (a_item == '*') or (b_item == '*'):
87 return True
88
89 return False
90
91 def equal(self, other):
92 for t in Event.terms:
93 log.debug(" [%s] %s %s" % (t, self[t], other[t]));
94 if not self.has_key(t) or not other.has_key(t):
95 return False
96 if not self.compare_data(self[t], other[t]):
97 return False
98 return True
99
100# Test file description needs to have following sections:
101# [config]
102# - just single instance in file
103# - needs to specify:
104# 'command' - perf command name
105# 'args' - special command arguments
106# 'ret' - expected command return value (0 by default)
107#
108# [eventX:base]
109# - one or multiple instances in file
110# - expected values assignments
111class Test(object):
112 def __init__(self, path, options):
113 parser = ConfigParser.SafeConfigParser()
114 parser.read(path)
115
116 log.warning("running '%s'" % path)
117
118 self.path = path
119 self.test_dir = options.test_dir
120 self.perf = options.perf
121 self.command = parser.get('config', 'command')
122 self.args = parser.get('config', 'args')
123
124 try:
125 self.ret = parser.get('config', 'ret')
126 except:
127 self.ret = 0
128
129 self.expect = {}
130 self.result = {}
131 log.info(" loading expected events");
132 self.load_events(path, self.expect)
133
134 def is_event(self, name):
135 if name.find("event") == -1:
136 return False
137 else:
138 return True
139
140 def load_events(self, path, events):
141 parser_event = ConfigParser.SafeConfigParser()
142 parser_event.read(path)
143
144 # The event record section header contains 'event' word,
145 # optionaly followed by ':' allowing to load 'parent
146 # event' first as a base
147 for section in filter(self.is_event, parser_event.sections()):
148
149 parser_items = parser_event.items(section);
150 base_items = {}
151
152 # Read parent event if there's any
153 if (':' in section):
154 base = section[section.index(':') + 1:]
155 parser_base = ConfigParser.SafeConfigParser()
156 parser_base.read(self.test_dir + '/' + base)
157 base_items = parser_base.items('event')
158
159 e = Event(section, parser_items, base_items)
160 events[section] = e
161
162 def run_cmd(self, tempdir):
163 cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir,
164 self.perf, self.command, tempdir, self.args)
165 ret = os.WEXITSTATUS(os.system(cmd))
166
167 log.info(" running '%s' ret %d " % (cmd, ret))
168
169 if ret != int(self.ret):
170 raise Unsup(self)
171
172 def compare(self, expect, result):
173 match = {}
174
175 log.info(" compare");
176
177 # For each expected event find all matching
178 # events in result. Fail if there's not any.
179 for exp_name, exp_event in expect.items():
180 exp_list = []
181 log.debug(" matching [%s]" % exp_name)
182 for res_name, res_event in result.items():
183 log.debug(" to [%s]" % res_name)
184 if (exp_event.equal(res_event)):
185 exp_list.append(res_name)
186 log.debug(" ->OK")
187 else:
188 log.debug(" ->FAIL");
189
190 log.info(" match: [%s] matches %s" % (exp_name, str(exp_list)))
191
192 # we did not any matching event - fail
193 if (not exp_list):
194 raise Fail(self, 'match failure');
195
196 match[exp_name] = exp_list
197
198 # For each defined group in the expected events
199 # check we match the same group in the result.
200 for exp_name, exp_event in expect.items():
201 group = exp_event.group
202
203 if (group == ''):
204 continue
205
206 for res_name in match[exp_name]:
207 res_group = result[res_name].group
208 if res_group not in match[group]:
209 raise Fail(self, 'group failure')
210
211 log.info(" group: [%s] matches group leader %s" %
212 (exp_name, str(match[group])))
213
214 log.info(" matched")
215
216 def resolve_groups(self, events):
217 for name, event in events.items():
218 group_fd = event['group_fd'];
219 if group_fd == '-1':
220 continue;
221
222 for iname, ievent in events.items():
223 if (ievent['fd'] == group_fd):
224 event.group = iname
225 log.debug('[%s] has group leader [%s]' % (name, iname))
226 break;
227
228 def run(self):
229 tempdir = tempfile.mkdtemp();
230
231 try:
232 # run the test script
233 self.run_cmd(tempdir);
234
235 # load events expectation for the test
236 log.info(" loading result events");
237 for f in glob.glob(tempdir + '/event*'):
238 self.load_events(f, self.result);
239
240 # resolve group_fd to event names
241 self.resolve_groups(self.expect);
242 self.resolve_groups(self.result);
243
244 # do the expectation - results matching - both ways
245 self.compare(self.expect, self.result)
246 self.compare(self.result, self.expect)
247
248 finally:
249 # cleanup
250 shutil.rmtree(tempdir)
251
252
253def run_tests(options):
254 for f in glob.glob(options.test_dir + '/' + options.test):
255 try:
256 Test(f, options).run()
257 except Unsup, obj:
258 log.warning("unsupp %s" % obj.getMsg())
259
260def setup_log(verbose):
261 global log
262 level = logging.CRITICAL
263
264 if verbose == 1:
265 level = logging.WARNING
266 if verbose == 2:
267 level = logging.INFO
268 if verbose >= 3:
269 level = logging.DEBUG
270
271 log = logging.getLogger('test')
272 log.setLevel(level)
273 ch = logging.StreamHandler()
274 ch.setLevel(level)
275 formatter = logging.Formatter('%(message)s')
276 ch.setFormatter(formatter)
277 log.addHandler(ch)
278
279USAGE = '''%s [OPTIONS]
280 -d dir # tests dir
281 -p path # perf binary
282 -t test # single test
283 -v # verbose level
284''' % sys.argv[0]
285
286def main():
287 parser = optparse.OptionParser(usage=USAGE)
288
289 parser.add_option("-t", "--test",
290 action="store", type="string", dest="test")
291 parser.add_option("-d", "--test-dir",
292 action="store", type="string", dest="test_dir")
293 parser.add_option("-p", "--perf",
294 action="store", type="string", dest="perf")
295 parser.add_option("-v", "--verbose",
296 action="count", dest="verbose")
297
298 options, args = parser.parse_args()
299 if args:
300 parser.error('FAILED wrong arguments %s' % ' '.join(args))
301 return -1
302
303 setup_log(options.verbose)
304
305 if not options.test_dir:
306 print 'FAILED no -d option specified'
307 sys.exit(-1)
308
309 if not options.test:
310 options.test = 'test*'
311
312 try:
313 run_tests(options)
314
315 except Fail, obj:
316 print "FAILED %s" % obj.getMsg();
317 sys.exit(-1)
318
319 sys.exit(0)
320
321if __name__ == '__main__':
322 main()
diff --git a/tools/perf/tests/attr/README b/tools/perf/tests/attr/README
new file mode 100644
index 000000000000..d102957cd59a
--- /dev/null
+++ b/tools/perf/tests/attr/README
@@ -0,0 +1,64 @@
1The struct perf_event_attr test (attr tests) support
2====================================================
3This testing support is embedded into perf directly and is governed
4by the PERF_TEST_ATTR environment variable and hook inside the
5sys_perf_event_open function.
6
7The general idea is to store 'struct perf_event_attr' details for
8each event created within single perf command. Each event details
9are stored into separate text file. Once perf command is finished
10these files are checked for values we expect for command.
11
12The attr tests consist of following parts:
13
14tests/attr.c
15------------
16This is the sys_perf_event_open hook implementation. The hook
17is triggered when the PERF_TEST_ATTR environment variable is
18defined. It must contain name of existing directory with access
19and write permissions.
20
21For each sys_perf_event_open call event details are stored in
22separate file. Besides 'struct perf_event_attr' values we also
23store 'fd' and 'group_fd' values to allow checking for groups.
24
25tests/attr.py
26-------------
27This is the python script that does all the hard work. It reads
28the test definition, executes it and checks results.
29
30tests/attr/
31-----------
32Directory containing all attr test definitions.
33Following tests are defined (with perf commands):
34
35 perf record kill (test-record-basic)
36 perf record -b kill (test-record-branch-any)
37 perf record -j any kill (test-record-branch-filter-any)
38 perf record -j any_call kill (test-record-branch-filter-any_call)
39 perf record -j any_ret kill (test-record-branch-filter-any_ret)
40 perf record -j hv kill (test-record-branch-filter-hv)
41 perf record -j ind_call kill (test-record-branch-filter-ind_call)
42 perf record -j k kill (test-record-branch-filter-k)
43 perf record -j u kill (test-record-branch-filter-u)
44 perf record -c 123 kill (test-record-count)
45 perf record -d kill (test-record-data)
46 perf record -F 100 kill (test-record-freq)
47 perf record -g -- kill (test-record-graph-default)
48 perf record -g dwarf -- kill (test-record-graph-dwarf)
49 perf record -g fp kill (test-record-graph-fp)
50 perf record --group -e cycles,instructions kill (test-record-group)
51 perf record -e '{cycles,instructions}' kill (test-record-group1)
52 perf record -D kill (test-record-no-delay)
53 perf record -i kill (test-record-no-inherit)
54 perf record -n kill (test-record-no-samples)
55 perf record -c 100 -P kill (test-record-period)
56 perf record -R kill (test-record-raw)
57 perf stat -e cycles kill (test-stat-basic)
58 perf stat kill (test-stat-default)
59 perf stat -d kill (test-stat-detailed-1)
60 perf stat -dd kill (test-stat-detailed-2)
61 perf stat -ddd kill (test-stat-detailed-3)
62 perf stat --group -e cycles,instructions kill (test-stat-group)
63 perf stat -e '{cycles,instructions}' kill (test-stat-group1)
64 perf stat -i -e cycles kill (test-stat-no-inherit)
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
new file mode 100644
index 000000000000..f1485d8e6a0b
--- /dev/null
+++ b/tools/perf/tests/attr/base-record
@@ -0,0 +1,39 @@
1[event]
2fd=1
3group_fd=-1
4flags=0
5type=0|1
6size=96
7config=0
8sample_period=4000
9sample_type=263
10read_format=7
11disabled=1
12inherit=1
13pinned=0
14exclusive=0
15exclude_user=0
16exclude_kernel=0
17exclude_hv=0
18exclude_idle=0
19mmap=1
20comm=1
21freq=1
22inherit_stat=0
23enable_on_exec=1
24task=0
25watermark=0
26precise_ip=0
27mmap_data=0
28sample_id_all=1
29exclude_host=0
30exclude_guest=1
31exclude_callchain_kernel=0
32exclude_callchain_user=0
33wakeup_events=0
34bp_type=0
35config1=0
36config2=0
37branch_sample_type=0
38sample_regs_user=0
39sample_stack_user=0
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat
new file mode 100644
index 000000000000..4bd79a82784f
--- /dev/null
+++ b/tools/perf/tests/attr/base-stat
@@ -0,0 +1,39 @@
1[event]
2fd=1
3group_fd=-1
4flags=0
5type=0
6size=96
7config=0
8sample_period=0
9sample_type=0
10read_format=3
11disabled=1
12inherit=1
13pinned=0
14exclusive=0
15exclude_user=0
16exclude_kernel=0
17exclude_hv=0
18exclude_idle=0
19mmap=0
20comm=0
21freq=0
22inherit_stat=0
23enable_on_exec=1
24task=0
25watermark=0
26precise_ip=0
27mmap_data=0
28sample_id_all=0
29exclude_host=0
30exclude_guest=1
31exclude_callchain_kernel=0
32exclude_callchain_user=0
33wakeup_events=0
34bp_type=0
35config1=0
36config2=0
37branch_sample_type=0
38sample_regs_user=0
39sample_stack_user=0
diff --git a/tools/perf/tests/attr/test-record-basic b/tools/perf/tests/attr/test-record-basic
new file mode 100644
index 000000000000..55c0428370ca
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-basic
@@ -0,0 +1,5 @@
1[config]
2command = record
3args = kill >/dev/null 2>&1
4
5[event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-any b/tools/perf/tests/attr/test-record-branch-any
new file mode 100644
index 000000000000..1421960ed4e9
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-any
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -b kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any b/tools/perf/tests/attr/test-record-branch-filter-any
new file mode 100644
index 000000000000..915c4df0e0c2
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-any
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j any kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_call b/tools/perf/tests/attr/test-record-branch-filter-any_call
new file mode 100644
index 000000000000..8708dbd4f373
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-any_call
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j any_call kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=16
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_ret b/tools/perf/tests/attr/test-record-branch-filter-any_ret
new file mode 100644
index 000000000000..0d3607a6dcbe
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-any_ret
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j any_ret kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=32
diff --git a/tools/perf/tests/attr/test-record-branch-filter-hv b/tools/perf/tests/attr/test-record-branch-filter-hv
new file mode 100644
index 000000000000..f25526740cec
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-hv
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j hv kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-ind_call b/tools/perf/tests/attr/test-record-branch-filter-ind_call
new file mode 100644
index 000000000000..e862dd179128
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-ind_call
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j ind_call kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=64
diff --git a/tools/perf/tests/attr/test-record-branch-filter-k b/tools/perf/tests/attr/test-record-branch-filter-k
new file mode 100644
index 000000000000..182971e898f5
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-k
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j k kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-u b/tools/perf/tests/attr/test-record-branch-filter-u
new file mode 100644
index 000000000000..83449ef9e687
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-u
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j u kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-count b/tools/perf/tests/attr/test-record-count
new file mode 100644
index 000000000000..2f841de56f6b
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-count
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -c 123 kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=123
7sample_type=7
8freq=0
diff --git a/tools/perf/tests/attr/test-record-data b/tools/perf/tests/attr/test-record-data
new file mode 100644
index 000000000000..6627c3e7534a
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-data
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -d kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=271
8mmap_data=1
diff --git a/tools/perf/tests/attr/test-record-freq b/tools/perf/tests/attr/test-record-freq
new file mode 100644
index 000000000000..600d0f8f2583
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-freq
@@ -0,0 +1,6 @@
1[config]
2command = record
3args = -F 100 kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=100
diff --git a/tools/perf/tests/attr/test-record-graph-default b/tools/perf/tests/attr/test-record-graph-default
new file mode 100644
index 000000000000..833d1849d767
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-graph-default
@@ -0,0 +1,6 @@
1[config]
2command = record
3args = -g -- kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=295
diff --git a/tools/perf/tests/attr/test-record-graph-dwarf b/tools/perf/tests/attr/test-record-graph-dwarf
new file mode 100644
index 000000000000..e93e082f5208
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-graph-dwarf
@@ -0,0 +1,10 @@
1[config]
2command = record
3args = -g dwarf -- kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=12583
7exclude_callchain_user=1
8sample_stack_user=8192
9# TODO different for each arch, no support for that now
10sample_regs_user=*
diff --git a/tools/perf/tests/attr/test-record-graph-fp b/tools/perf/tests/attr/test-record-graph-fp
new file mode 100644
index 000000000000..7cef3743f03f
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-graph-fp
@@ -0,0 +1,6 @@
1[config]
2command = record
3args = -g fp kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=295
diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group
new file mode 100644
index 000000000000..a6599e9a19d3
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-group
@@ -0,0 +1,18 @@
1[config]
2command = record
3args = --group -e cycles,instructions kill >/dev/null 2>&1
4
5[event-1:base-record]
6fd=1
7group_fd=-1
8sample_type=327
9
10[event-2:base-record]
11fd=2
12group_fd=1
13config=1
14sample_type=327
15mmap=0
16comm=0
17enable_on_exec=0
18disabled=0
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1
new file mode 100644
index 000000000000..5a8359da38af
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-group1
@@ -0,0 +1,19 @@
1[config]
2command = record
3args = -e '{cycles,instructions}' kill >/tmp/krava 2>&1
4
5[event-1:base-record]
6fd=1
7group_fd=-1
8sample_type=327
9
10[event-2:base-record]
11fd=2
12group_fd=1
13type=0
14config=1
15sample_type=327
16mmap=0
17comm=0
18enable_on_exec=0
19disabled=0
diff --git a/tools/perf/tests/attr/test-record-no-delay b/tools/perf/tests/attr/test-record-no-delay
new file mode 100644
index 000000000000..f253b78cdbf2
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-no-delay
@@ -0,0 +1,9 @@
1[config]
2command = record
3args = -D kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=263
8watermark=0
9wakeup_events=1
diff --git a/tools/perf/tests/attr/test-record-no-inherit b/tools/perf/tests/attr/test-record-no-inherit
new file mode 100644
index 000000000000..9079a25cd643
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-no-inherit
@@ -0,0 +1,7 @@
1[config]
2command = record
3args = -i kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=259
7inherit=0
diff --git a/tools/perf/tests/attr/test-record-no-samples b/tools/perf/tests/attr/test-record-no-samples
new file mode 100644
index 000000000000..d0141b2418b5
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-no-samples
@@ -0,0 +1,6 @@
1[config]
2command = record
3args = -n kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=0
diff --git a/tools/perf/tests/attr/test-record-period b/tools/perf/tests/attr/test-record-period
new file mode 100644
index 000000000000..8abc5314fc52
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-period
@@ -0,0 +1,7 @@
1[config]
2command = record
3args = -c 100 -P kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=100
7freq=0
diff --git a/tools/perf/tests/attr/test-record-raw b/tools/perf/tests/attr/test-record-raw
new file mode 100644
index 000000000000..4a8ef25b5f49
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-raw
@@ -0,0 +1,7 @@
1[config]
2command = record
3args = -R kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=1415
diff --git a/tools/perf/tests/attr/test-stat-basic b/tools/perf/tests/attr/test-stat-basic
new file mode 100644
index 000000000000..74e17881f2ba
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-basic
@@ -0,0 +1,6 @@
1[config]
2command = stat
3args = -e cycles kill >/dev/null 2>&1
4ret = 1
5
6[event:base-stat]
diff --git a/tools/perf/tests/attr/test-stat-default b/tools/perf/tests/attr/test-stat-default
new file mode 100644
index 000000000000..19270f54c96e
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-default
@@ -0,0 +1,64 @@
1[config]
2command = stat
3args = kill >/dev/null 2>&1
4ret = 1
5
6# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
7[event1:base-stat]
8fd=1
9type=1
10config=1
11
12# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
13[event2:base-stat]
14fd=2
15type=1
16config=3
17
18# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
19[event3:base-stat]
20fd=3
21type=1
22config=4
23
24# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
25[event4:base-stat]
26fd=4
27type=1
28config=2
29
30# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
31[event5:base-stat]
32fd=5
33type=0
34config=0
35
36# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
37[event6:base-stat]
38fd=6
39type=0
40config=7
41
42# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
43[event7:base-stat]
44fd=7
45type=0
46config=8
47
48# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
49[event8:base-stat]
50fd=8
51type=0
52config=1
53
54# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
55[event9:base-stat]
56fd=9
57type=0
58config=4
59
60# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
61[event10:base-stat]
62fd=10
63type=0
64config=5
diff --git a/tools/perf/tests/attr/test-stat-detailed-1 b/tools/perf/tests/attr/test-stat-detailed-1
new file mode 100644
index 000000000000..51426b87153b
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-detailed-1
@@ -0,0 +1,101 @@
1[config]
2command = stat
3args = -d kill >/dev/null 2>&1
4ret = 1
5
6
7# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
8[event1:base-stat]
9fd=1
10type=1
11config=1
12
13# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
14[event2:base-stat]
15fd=2
16type=1
17config=3
18
19# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
20[event3:base-stat]
21fd=3
22type=1
23config=4
24
25# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
26[event4:base-stat]
27fd=4
28type=1
29config=2
30
31# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
32[event5:base-stat]
33fd=5
34type=0
35config=0
36
37# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
38[event6:base-stat]
39fd=6
40type=0
41config=7
42
43# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
44[event7:base-stat]
45fd=7
46type=0
47config=8
48
49# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
50[event8:base-stat]
51fd=8
52type=0
53config=1
54
55# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
56[event9:base-stat]
57fd=9
58type=0
59config=4
60
61# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
62[event10:base-stat]
63fd=10
64type=0
65config=5
66
67# PERF_TYPE_HW_CACHE /
68# PERF_COUNT_HW_CACHE_L1D << 0 |
69# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
70# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
71[event11:base-stat]
72fd=11
73type=3
74config=0
75
76# PERF_TYPE_HW_CACHE /
77# PERF_COUNT_HW_CACHE_L1D << 0 |
78# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
79# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
80[event12:base-stat]
81fd=12
82type=3
83config=65536
84
85# PERF_TYPE_HW_CACHE /
86# PERF_COUNT_HW_CACHE_LL << 0 |
87# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
88# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
89[event13:base-stat]
90fd=13
91type=3
92config=2
93
94# PERF_TYPE_HW_CACHE,
95# PERF_COUNT_HW_CACHE_LL << 0 |
96# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
97# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
98[event14:base-stat]
99fd=14
100type=3
101config=65538
diff --git a/tools/perf/tests/attr/test-stat-detailed-2 b/tools/perf/tests/attr/test-stat-detailed-2
new file mode 100644
index 000000000000..8de5acc31c27
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-detailed-2
@@ -0,0 +1,155 @@
1[config]
2command = stat
3args = -dd kill >/dev/null 2>&1
4ret = 1
5
6
7# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
8[event1:base-stat]
9fd=1
10type=1
11config=1
12
13# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
14[event2:base-stat]
15fd=2
16type=1
17config=3
18
19# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
20[event3:base-stat]
21fd=3
22type=1
23config=4
24
25# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
26[event4:base-stat]
27fd=4
28type=1
29config=2
30
31# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
32[event5:base-stat]
33fd=5
34type=0
35config=0
36
37# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
38[event6:base-stat]
39fd=6
40type=0
41config=7
42
43# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
44[event7:base-stat]
45fd=7
46type=0
47config=8
48
49# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
50[event8:base-stat]
51fd=8
52type=0
53config=1
54
55# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
56[event9:base-stat]
57fd=9
58type=0
59config=4
60
61# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
62[event10:base-stat]
63fd=10
64type=0
65config=5
66
67# PERF_TYPE_HW_CACHE /
68# PERF_COUNT_HW_CACHE_L1D << 0 |
69# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
70# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
71[event11:base-stat]
72fd=11
73type=3
74config=0
75
76# PERF_TYPE_HW_CACHE /
77# PERF_COUNT_HW_CACHE_L1D << 0 |
78# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
79# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
80[event12:base-stat]
81fd=12
82type=3
83config=65536
84
85# PERF_TYPE_HW_CACHE /
86# PERF_COUNT_HW_CACHE_LL << 0 |
87# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
88# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
89[event13:base-stat]
90fd=13
91type=3
92config=2
93
94# PERF_TYPE_HW_CACHE,
95# PERF_COUNT_HW_CACHE_LL << 0 |
96# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
97# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
98[event14:base-stat]
99fd=14
100type=3
101config=65538
102
103# PERF_TYPE_HW_CACHE,
104# PERF_COUNT_HW_CACHE_L1I << 0 |
105# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
106# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
107[event15:base-stat]
108fd=15
109type=3
110config=1
111
112# PERF_TYPE_HW_CACHE,
113# PERF_COUNT_HW_CACHE_L1I << 0 |
114# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
115# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
116[event16:base-stat]
117fd=16
118type=3
119config=65537
120
121# PERF_TYPE_HW_CACHE,
122# PERF_COUNT_HW_CACHE_DTLB << 0 |
123# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
124# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
125[event17:base-stat]
126fd=17
127type=3
128config=3
129
130# PERF_TYPE_HW_CACHE,
131# PERF_COUNT_HW_CACHE_DTLB << 0 |
132# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
133# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
134[event18:base-stat]
135fd=18
136type=3
137config=65539
138
139# PERF_TYPE_HW_CACHE,
140# PERF_COUNT_HW_CACHE_ITLB << 0 |
141# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
142# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
143[event19:base-stat]
144fd=19
145type=3
146config=4
147
148# PERF_TYPE_HW_CACHE,
149# PERF_COUNT_HW_CACHE_ITLB << 0 |
150# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
151# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
152[event20:base-stat]
153fd=20
154type=3
155config=65540
diff --git a/tools/perf/tests/attr/test-stat-detailed-3 b/tools/perf/tests/attr/test-stat-detailed-3
new file mode 100644
index 000000000000..0a1f45bf7d79
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-detailed-3
@@ -0,0 +1,173 @@
1[config]
2command = stat
3args = -ddd kill >/dev/null 2>&1
4ret = 1
5
6
7# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
8[event1:base-stat]
9fd=1
10type=1
11config=1
12
13# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
14[event2:base-stat]
15fd=2
16type=1
17config=3
18
19# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
20[event3:base-stat]
21fd=3
22type=1
23config=4
24
25# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
26[event4:base-stat]
27fd=4
28type=1
29config=2
30
31# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
32[event5:base-stat]
33fd=5
34type=0
35config=0
36
37# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
38[event6:base-stat]
39fd=6
40type=0
41config=7
42
43# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
44[event7:base-stat]
45fd=7
46type=0
47config=8
48
49# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
50[event8:base-stat]
51fd=8
52type=0
53config=1
54
55# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
56[event9:base-stat]
57fd=9
58type=0
59config=4
60
61# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
62[event10:base-stat]
63fd=10
64type=0
65config=5
66
67# PERF_TYPE_HW_CACHE /
68# PERF_COUNT_HW_CACHE_L1D << 0 |
69# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
70# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
71[event11:base-stat]
72fd=11
73type=3
74config=0
75
76# PERF_TYPE_HW_CACHE /
77# PERF_COUNT_HW_CACHE_L1D << 0 |
78# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
79# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
80[event12:base-stat]
81fd=12
82type=3
83config=65536
84
85# PERF_TYPE_HW_CACHE /
86# PERF_COUNT_HW_CACHE_LL << 0 |
87# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
88# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
89[event13:base-stat]
90fd=13
91type=3
92config=2
93
94# PERF_TYPE_HW_CACHE,
95# PERF_COUNT_HW_CACHE_LL << 0 |
96# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
97# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
98[event14:base-stat]
99fd=14
100type=3
101config=65538
102
103# PERF_TYPE_HW_CACHE,
104# PERF_COUNT_HW_CACHE_L1I << 0 |
105# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
106# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
107[event15:base-stat]
108fd=15
109type=3
110config=1
111
112# PERF_TYPE_HW_CACHE,
113# PERF_COUNT_HW_CACHE_L1I << 0 |
114# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
115# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
116[event16:base-stat]
117fd=16
118type=3
119config=65537
120
121# PERF_TYPE_HW_CACHE,
122# PERF_COUNT_HW_CACHE_DTLB << 0 |
123# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
124# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
125[event17:base-stat]
126fd=17
127type=3
128config=3
129
130# PERF_TYPE_HW_CACHE,
131# PERF_COUNT_HW_CACHE_DTLB << 0 |
132# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
133# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
134[event18:base-stat]
135fd=18
136type=3
137config=65539
138
139# PERF_TYPE_HW_CACHE,
140# PERF_COUNT_HW_CACHE_ITLB << 0 |
141# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
142# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
143[event19:base-stat]
144fd=19
145type=3
146config=4
147
148# PERF_TYPE_HW_CACHE,
149# PERF_COUNT_HW_CACHE_ITLB << 0 |
150# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
151# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
152[event20:base-stat]
153fd=20
154type=3
155config=65540
156
157# PERF_TYPE_HW_CACHE,
158# PERF_COUNT_HW_CACHE_L1D << 0 |
159# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
160# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
161[event21:base-stat]
162fd=21
163type=3
164config=512
165
166# PERF_TYPE_HW_CACHE,
167# PERF_COUNT_HW_CACHE_L1D << 0 |
168# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
169# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
170[event22:base-stat]
171fd=22
172type=3
173config=66048
diff --git a/tools/perf/tests/attr/test-stat-group b/tools/perf/tests/attr/test-stat-group
new file mode 100644
index 000000000000..fdc1596a8862
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-group
@@ -0,0 +1,15 @@
1[config]
2command = stat
3args = --group -e cycles,instructions kill >/dev/null 2>&1
4ret = 1
5
6[event-1:base-stat]
7fd=1
8group_fd=-1
9
10[event-2:base-stat]
11fd=2
12group_fd=1
13config=1
14disabled=0
15enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-stat-group1 b/tools/perf/tests/attr/test-stat-group1
new file mode 100644
index 000000000000..2a1f86e4a904
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-group1
@@ -0,0 +1,15 @@
1[config]
2command = stat
3args = -e '{cycles,instructions}' kill >/dev/null 2>&1
4ret = 1
5
6[event-1:base-stat]
7fd=1
8group_fd=-1
9
10[event-2:base-stat]
11fd=2
12group_fd=1
13config=1
14disabled=0
15enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-stat-no-inherit b/tools/perf/tests/attr/test-stat-no-inherit
new file mode 100644
index 000000000000..d54b2a1e3e28
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-no-inherit
@@ -0,0 +1,7 @@
1[config]
2command = stat
3args = -i -e cycles kill >/dev/null 2>&1
4ret = 1
5
6[event:base-stat]
7inherit=0
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
new file mode 100644
index 000000000000..186f67535494
--- /dev/null
+++ b/tools/perf/tests/builtin-test.c
@@ -0,0 +1,173 @@
1/*
2 * builtin-test.c
3 *
4 * Builtin regression testing command: ever growing number of sanity tests
5 */
6#include "builtin.h"
7#include "tests.h"
8#include "debug.h"
9#include "color.h"
10#include "parse-options.h"
11#include "symbol.h"
12
13static struct test {
14 const char *desc;
15 int (*func)(void);
16} tests[] = {
17 {
18 .desc = "vmlinux symtab matches kallsyms",
19 .func = test__vmlinux_matches_kallsyms,
20 },
21 {
22 .desc = "detect open syscall event",
23 .func = test__open_syscall_event,
24 },
25 {
26 .desc = "detect open syscall event on all cpus",
27 .func = test__open_syscall_event_on_all_cpus,
28 },
29 {
30 .desc = "read samples using the mmap interface",
31 .func = test__basic_mmap,
32 },
33 {
34 .desc = "parse events tests",
35 .func = test__parse_events,
36 },
37#if defined(__x86_64__) || defined(__i386__)
38 {
39 .desc = "x86 rdpmc test",
40 .func = test__rdpmc,
41 },
42#endif
43 {
44 .desc = "Validate PERF_RECORD_* events & perf_sample fields",
45 .func = test__PERF_RECORD,
46 },
47 {
48 .desc = "Test perf pmu format parsing",
49 .func = test__pmu,
50 },
51 {
52 .desc = "Test dso data interface",
53 .func = test__dso_data,
54 },
55 {
56 .desc = "roundtrip evsel->name check",
57 .func = test__perf_evsel__roundtrip_name_test,
58 },
59 {
60 .desc = "Check parsing of sched tracepoints fields",
61 .func = test__perf_evsel__tp_sched_test,
62 },
63 {
64 .desc = "Generate and check syscalls:sys_enter_open event fields",
65 .func = test__syscall_open_tp_fields,
66 },
67 {
68 .desc = "struct perf_event_attr setup",
69 .func = test__attr,
70 },
71 {
72 .func = NULL,
73 },
74};
75
76static bool perf_test__matches(int curr, int argc, const char *argv[])
77{
78 int i;
79
80 if (argc == 0)
81 return true;
82
83 for (i = 0; i < argc; ++i) {
84 char *end;
85 long nr = strtoul(argv[i], &end, 10);
86
87 if (*end == '\0') {
88 if (nr == curr + 1)
89 return true;
90 continue;
91 }
92
93 if (strstr(tests[curr].desc, argv[i]))
94 return true;
95 }
96
97 return false;
98}
99
100static int __cmd_test(int argc, const char *argv[])
101{
102 int i = 0;
103 int width = 0;
104
105 while (tests[i].func) {
106 int len = strlen(tests[i].desc);
107
108 if (width < len)
109 width = len;
110 ++i;
111 }
112
113 i = 0;
114 while (tests[i].func) {
115 int curr = i++, err;
116
117 if (!perf_test__matches(curr, argc, argv))
118 continue;
119
120 pr_info("%2d: %-*s:", i, width, tests[curr].desc);
121 pr_debug("\n--- start ---\n");
122 err = tests[curr].func();
123 pr_debug("---- end ----\n%s:", tests[curr].desc);
124 if (err)
125 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
126 else
127 pr_info(" Ok\n");
128 }
129
130 return 0;
131}
132
133static int perf_test__list(int argc, const char **argv)
134{
135 int i = 0;
136
137 while (tests[i].func) {
138 int curr = i++;
139
140 if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
141 continue;
142
143 pr_info("%2d: %s\n", i, tests[curr].desc);
144 }
145
146 return 0;
147}
148
149int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
150{
151 const char * const test_usage[] = {
152 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
153 NULL,
154 };
155 const struct option test_options[] = {
156 OPT_INCR('v', "verbose", &verbose,
157 "be more verbose (show symbol address, etc)"),
158 OPT_END()
159 };
160
161 argc = parse_options(argc, argv, test_options, test_usage, 0);
162 if (argc >= 1 && !strcmp(argv[0], "list"))
163 return perf_test__list(argc, argv);
164
165 symbol_conf.priv_size = sizeof(int);
166 symbol_conf.sort_by_name = true;
167 symbol_conf.try_vmlinux_path = true;
168
169 if (symbol__init() < 0)
170 return -1;
171
172 return __cmd_test(argc, argv);
173}
diff --git a/tools/perf/util/dso-test-data.c b/tools/perf/tests/dso-data.c
index c6caedeb1d6b..5eaffa2de9c5 100644
--- a/tools/perf/util/dso-test-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -6,7 +6,9 @@
6#include <fcntl.h> 6#include <fcntl.h>
7#include <string.h> 7#include <string.h>
8 8
9#include "machine.h"
9#include "symbol.h" 10#include "symbol.h"
11#include "tests.h"
10 12
11#define TEST_ASSERT_VAL(text, cond) \ 13#define TEST_ASSERT_VAL(text, cond) \
12do { \ 14do { \
@@ -24,6 +26,10 @@ static char *test_file(int size)
24 unsigned char *buf; 26 unsigned char *buf;
25 27
26 fd = mkstemp(templ); 28 fd = mkstemp(templ);
29 if (fd < 0) {
30 perror("mkstemp failed");
31 return NULL;
32 }
27 33
28 buf = malloc(size); 34 buf = malloc(size);
29 if (!buf) { 35 if (!buf) {
@@ -94,7 +100,7 @@ struct test_data_offset offsets[] = {
94 }, 100 },
95}; 101};
96 102
97int dso__test_data(void) 103int test__dso_data(void)
98{ 104{
99 struct machine machine; 105 struct machine machine;
100 struct dso *dso; 106 struct dso *dso;
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
new file mode 100644
index 000000000000..e61fc828a158
--- /dev/null
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -0,0 +1,114 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "parse-events.h"
4#include "tests.h"
5
6static int perf_evsel__roundtrip_cache_name_test(void)
7{
8 char name[128];
9 int type, op, err = 0, ret = 0, i, idx;
10 struct perf_evsel *evsel;
11 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
12
13 if (evlist == NULL)
14 return -ENOMEM;
15
16 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
17 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
18 /* skip invalid cache type */
19 if (!perf_evsel__is_cache_op_valid(type, op))
20 continue;
21
22 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
23 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
24 name, sizeof(name));
25 err = parse_events(evlist, name, 0);
26 if (err)
27 ret = err;
28 }
29 }
30 }
31
32 idx = 0;
33 evsel = perf_evlist__first(evlist);
34
35 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
36 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
37 /* skip invalid cache type */
38 if (!perf_evsel__is_cache_op_valid(type, op))
39 continue;
40
41 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
42 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
43 name, sizeof(name));
44 if (evsel->idx != idx)
45 continue;
46
47 ++idx;
48
49 if (strcmp(perf_evsel__name(evsel), name)) {
50 pr_debug("%s != %s\n", perf_evsel__name(evsel), name);
51 ret = -1;
52 }
53
54 evsel = perf_evsel__next(evsel);
55 }
56 }
57 }
58
59 perf_evlist__delete(evlist);
60 return ret;
61}
62
63static int __perf_evsel__name_array_test(const char *names[], int nr_names)
64{
65 int i, err;
66 struct perf_evsel *evsel;
67 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
68
69 if (evlist == NULL)
70 return -ENOMEM;
71
72 for (i = 0; i < nr_names; ++i) {
73 err = parse_events(evlist, names[i], 0);
74 if (err) {
75 pr_debug("failed to parse event '%s', err %d\n",
76 names[i], err);
77 goto out_delete_evlist;
78 }
79 }
80
81 err = 0;
82 list_for_each_entry(evsel, &evlist->entries, node) {
83 if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) {
84 --err;
85 pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]);
86 }
87 }
88
89out_delete_evlist:
90 perf_evlist__delete(evlist);
91 return err;
92}
93
94#define perf_evsel__name_array_test(names) \
95 __perf_evsel__name_array_test(names, ARRAY_SIZE(names))
96
97int test__perf_evsel__roundtrip_name_test(void)
98{
99 int err = 0, ret = 0;
100
101 err = perf_evsel__name_array_test(perf_evsel__hw_names);
102 if (err)
103 ret = err;
104
105 err = perf_evsel__name_array_test(perf_evsel__sw_names);
106 if (err)
107 ret = err;
108
109 err = perf_evsel__roundtrip_cache_name_test();
110 if (err)
111 ret = err;
112
113 return ret;
114}
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
new file mode 100644
index 000000000000..a5d2fcc5ae35
--- /dev/null
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -0,0 +1,84 @@
1#include "evsel.h"
2#include "tests.h"
3#include "event-parse.h"
4
5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
6 int size, bool should_be_signed)
7{
8 struct format_field *field = perf_evsel__field(evsel, name);
9 int is_signed;
10 int ret = 0;
11
12 if (field == NULL) {
13 pr_debug("%s: \"%s\" field not found!\n", evsel->name, name);
14 return -1;
15 }
16
17 is_signed = !!(field->flags | FIELD_IS_SIGNED);
18 if (should_be_signed && !is_signed) {
19 pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n",
20 evsel->name, name, is_signed, should_be_signed);
21 ret = -1;
22 }
23
24 if (field->size != size) {
25 pr_debug("%s: \"%s\" size (%d) should be %d!\n",
26 evsel->name, name, field->size, size);
27 ret = -1;
28 }
29
30 return ret;
31}
32
33int test__perf_evsel__tp_sched_test(void)
34{
35 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch", 0);
36 int ret = 0;
37
38 if (evsel == NULL) {
39 pr_debug("perf_evsel__new\n");
40 return -1;
41 }
42
43 if (perf_evsel__test_field(evsel, "prev_comm", 16, true))
44 ret = -1;
45
46 if (perf_evsel__test_field(evsel, "prev_pid", 4, true))
47 ret = -1;
48
49 if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
50 ret = -1;
51
52 if (perf_evsel__test_field(evsel, "prev_state", 8, true))
53 ret = -1;
54
55 if (perf_evsel__test_field(evsel, "next_comm", 16, true))
56 ret = -1;
57
58 if (perf_evsel__test_field(evsel, "next_pid", 4, true))
59 ret = -1;
60
61 if (perf_evsel__test_field(evsel, "next_prio", 4, true))
62 ret = -1;
63
64 perf_evsel__delete(evsel);
65
66 evsel = perf_evsel__newtp("sched", "sched_wakeup", 0);
67
68 if (perf_evsel__test_field(evsel, "comm", 16, true))
69 ret = -1;
70
71 if (perf_evsel__test_field(evsel, "pid", 4, true))
72 ret = -1;
73
74 if (perf_evsel__test_field(evsel, "prio", 4, true))
75 ret = -1;
76
77 if (perf_evsel__test_field(evsel, "success", 4, true))
78 ret = -1;
79
80 if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
81 ret = -1;
82
83 return ret;
84}
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
new file mode 100644
index 000000000000..e1746811e14b
--- /dev/null
+++ b/tools/perf/tests/mmap-basic.c
@@ -0,0 +1,162 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "thread_map.h"
4#include "cpumap.h"
5#include "tests.h"
6
7/*
8 * This test will generate random numbers of calls to some getpid syscalls,
9 * then establish an mmap for a group of events that are created to monitor
10 * the syscalls.
11 *
12 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
13 * sample.id field to map back to its respective perf_evsel instance.
14 *
15 * Then it checks if the number of syscalls reported as perf events by
16 * the kernel corresponds to the number of syscalls made.
17 */
18int test__basic_mmap(void)
19{
20 int err = -1;
21 union perf_event *event;
22 struct thread_map *threads;
23 struct cpu_map *cpus;
24 struct perf_evlist *evlist;
25 struct perf_event_attr attr = {
26 .type = PERF_TYPE_TRACEPOINT,
27 .read_format = PERF_FORMAT_ID,
28 .sample_type = PERF_SAMPLE_ID,
29 .watermark = 0,
30 };
31 cpu_set_t cpu_set;
32 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
33 "getpgid", };
34 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
35 (void*)getpgid };
36#define nsyscalls ARRAY_SIZE(syscall_names)
37 int ids[nsyscalls];
38 unsigned int nr_events[nsyscalls],
39 expected_nr_events[nsyscalls], i, j;
40 struct perf_evsel *evsels[nsyscalls], *evsel;
41
42 for (i = 0; i < nsyscalls; ++i) {
43 char name[64];
44
45 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
46 ids[i] = trace_event__id(name);
47 if (ids[i] < 0) {
48 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
49 return -1;
50 }
51 nr_events[i] = 0;
52 expected_nr_events[i] = random() % 257;
53 }
54
55 threads = thread_map__new(-1, getpid(), UINT_MAX);
56 if (threads == NULL) {
57 pr_debug("thread_map__new\n");
58 return -1;
59 }
60
61 cpus = cpu_map__new(NULL);
62 if (cpus == NULL) {
63 pr_debug("cpu_map__new\n");
64 goto out_free_threads;
65 }
66
67 CPU_ZERO(&cpu_set);
68 CPU_SET(cpus->map[0], &cpu_set);
69 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
70 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
71 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
72 cpus->map[0], strerror(errno));
73 goto out_free_cpus;
74 }
75
76 evlist = perf_evlist__new(cpus, threads);
77 if (evlist == NULL) {
78 pr_debug("perf_evlist__new\n");
79 goto out_free_cpus;
80 }
81
82 /* anonymous union fields, can't be initialized above */
83 attr.wakeup_events = 1;
84 attr.sample_period = 1;
85
86 for (i = 0; i < nsyscalls; ++i) {
87 attr.config = ids[i];
88 evsels[i] = perf_evsel__new(&attr, i);
89 if (evsels[i] == NULL) {
90 pr_debug("perf_evsel__new\n");
91 goto out_free_evlist;
92 }
93
94 perf_evlist__add(evlist, evsels[i]);
95
96 if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
97 pr_debug("failed to open counter: %s, "
98 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
99 strerror(errno));
100 goto out_close_fd;
101 }
102 }
103
104 if (perf_evlist__mmap(evlist, 128, true) < 0) {
105 pr_debug("failed to mmap events: %d (%s)\n", errno,
106 strerror(errno));
107 goto out_close_fd;
108 }
109
110 for (i = 0; i < nsyscalls; ++i)
111 for (j = 0; j < expected_nr_events[i]; ++j) {
112 int foo = syscalls[i]();
113 ++foo;
114 }
115
116 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
117 struct perf_sample sample;
118
119 if (event->header.type != PERF_RECORD_SAMPLE) {
120 pr_debug("unexpected %s event\n",
121 perf_event__name(event->header.type));
122 goto out_munmap;
123 }
124
125 err = perf_evlist__parse_sample(evlist, event, &sample);
126 if (err) {
127 pr_err("Can't parse sample, err = %d\n", err);
128 goto out_munmap;
129 }
130
131 evsel = perf_evlist__id2evsel(evlist, sample.id);
132 if (evsel == NULL) {
133 pr_debug("event with id %" PRIu64
134 " doesn't map to an evsel\n", sample.id);
135 goto out_munmap;
136 }
137 nr_events[evsel->idx]++;
138 }
139
140 list_for_each_entry(evsel, &evlist->entries, node) {
141 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
142 pr_debug("expected %d %s events, got %d\n",
143 expected_nr_events[evsel->idx],
144 perf_evsel__name(evsel), nr_events[evsel->idx]);
145 goto out_munmap;
146 }
147 }
148
149 err = 0;
150out_munmap:
151 perf_evlist__munmap(evlist);
152out_close_fd:
153 for (i = 0; i < nsyscalls; ++i)
154 perf_evsel__close_fd(evsels[i], 1, threads->nr);
155out_free_evlist:
156 perf_evlist__delete(evlist);
157out_free_cpus:
158 cpu_map__delete(cpus);
159out_free_threads:
160 thread_map__delete(threads);
161 return err;
162}
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c
new file mode 100644
index 000000000000..31072aba0d54
--- /dev/null
+++ b/tools/perf/tests/open-syscall-all-cpus.c
@@ -0,0 +1,120 @@
1#include "evsel.h"
2#include "tests.h"
3#include "thread_map.h"
4#include "cpumap.h"
5#include "debug.h"
6
7int test__open_syscall_event_on_all_cpus(void)
8{
9 int err = -1, fd, cpu;
10 struct thread_map *threads;
11 struct cpu_map *cpus;
12 struct perf_evsel *evsel;
13 struct perf_event_attr attr;
14 unsigned int nr_open_calls = 111, i;
15 cpu_set_t cpu_set;
16 int id = trace_event__id("sys_enter_open");
17
18 if (id < 0) {
19 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
20 return -1;
21 }
22
23 threads = thread_map__new(-1, getpid(), UINT_MAX);
24 if (threads == NULL) {
25 pr_debug("thread_map__new\n");
26 return -1;
27 }
28
29 cpus = cpu_map__new(NULL);
30 if (cpus == NULL) {
31 pr_debug("cpu_map__new\n");
32 goto out_thread_map_delete;
33 }
34
35
36 CPU_ZERO(&cpu_set);
37
38 memset(&attr, 0, sizeof(attr));
39 attr.type = PERF_TYPE_TRACEPOINT;
40 attr.config = id;
41 evsel = perf_evsel__new(&attr, 0);
42 if (evsel == NULL) {
43 pr_debug("perf_evsel__new\n");
44 goto out_thread_map_delete;
45 }
46
47 if (perf_evsel__open(evsel, cpus, threads) < 0) {
48 pr_debug("failed to open counter: %s, "
49 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
50 strerror(errno));
51 goto out_evsel_delete;
52 }
53
54 for (cpu = 0; cpu < cpus->nr; ++cpu) {
55 unsigned int ncalls = nr_open_calls + cpu;
56 /*
57 * XXX eventually lift this restriction in a way that
58 * keeps perf building on older glibc installations
59 * without CPU_ALLOC. 1024 cpus in 2010 still seems
60 * a reasonable upper limit tho :-)
61 */
62 if (cpus->map[cpu] >= CPU_SETSIZE) {
63 pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
64 continue;
65 }
66
67 CPU_SET(cpus->map[cpu], &cpu_set);
68 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
69 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
70 cpus->map[cpu],
71 strerror(errno));
72 goto out_close_fd;
73 }
74 for (i = 0; i < ncalls; ++i) {
75 fd = open("/etc/passwd", O_RDONLY);
76 close(fd);
77 }
78 CPU_CLR(cpus->map[cpu], &cpu_set);
79 }
80
81 /*
82 * Here we need to explicitely preallocate the counts, as if
83 * we use the auto allocation it will allocate just for 1 cpu,
84 * as we start by cpu 0.
85 */
86 if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
87 pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
88 goto out_close_fd;
89 }
90
91 err = 0;
92
93 for (cpu = 0; cpu < cpus->nr; ++cpu) {
94 unsigned int expected;
95
96 if (cpus->map[cpu] >= CPU_SETSIZE)
97 continue;
98
99 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
100 pr_debug("perf_evsel__read_on_cpu\n");
101 err = -1;
102 break;
103 }
104
105 expected = nr_open_calls + cpu;
106 if (evsel->counts->cpu[cpu].val != expected) {
107 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
108 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
109 err = -1;
110 }
111 }
112
113out_close_fd:
114 perf_evsel__close_fd(evsel, 1, threads->nr);
115out_evsel_delete:
116 perf_evsel__delete(evsel);
117out_thread_map_delete:
118 thread_map__delete(threads);
119 return err;
120}
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
new file mode 100644
index 000000000000..1c52fdc1164e
--- /dev/null
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -0,0 +1,117 @@
1#include "perf.h"
2#include "evlist.h"
3#include "evsel.h"
4#include "thread_map.h"
5#include "tests.h"
6
7int test__syscall_open_tp_fields(void)
8{
9 struct perf_record_opts opts = {
10 .target = {
11 .uid = UINT_MAX,
12 .uses_mmap = true,
13 },
14 .no_delay = true,
15 .freq = 1,
16 .mmap_pages = 256,
17 .raw_samples = true,
18 };
19 const char *filename = "/etc/passwd";
20 int flags = O_RDONLY | O_DIRECTORY;
21 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
22 struct perf_evsel *evsel;
23 int err = -1, i, nr_events = 0, nr_polls = 0;
24
25 if (evlist == NULL) {
26 pr_debug("%s: perf_evlist__new\n", __func__);
27 goto out;
28 }
29
30 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
31 if (evsel == NULL) {
32 pr_debug("%s: perf_evsel__newtp\n", __func__);
33 goto out_delete_evlist;
34 }
35
36 perf_evlist__add(evlist, evsel);
37
38 err = perf_evlist__create_maps(evlist, &opts.target);
39 if (err < 0) {
40 pr_debug("%s: perf_evlist__create_maps\n", __func__);
41 goto out_delete_evlist;
42 }
43
44 perf_evsel__config(evsel, &opts);
45
46 evlist->threads->map[0] = getpid();
47
48 err = perf_evlist__open(evlist);
49 if (err < 0) {
50 pr_debug("perf_evlist__open: %s\n", strerror(errno));
51 goto out_delete_evlist;
52 }
53
54 err = perf_evlist__mmap(evlist, UINT_MAX, false);
55 if (err < 0) {
56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
57 goto out_delete_evlist;
58 }
59
60 perf_evlist__enable(evlist);
61
62 /*
63 * Generate the event:
64 */
65 open(filename, flags);
66
67 while (1) {
68 int before = nr_events;
69
70 for (i = 0; i < evlist->nr_mmaps; i++) {
71 union perf_event *event;
72
73 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
74 const u32 type = event->header.type;
75 int tp_flags;
76 struct perf_sample sample;
77
78 ++nr_events;
79
80 if (type != PERF_RECORD_SAMPLE)
81 continue;
82
83 err = perf_evsel__parse_sample(evsel, event, &sample);
84 if (err) {
85 pr_err("Can't parse sample, err = %d\n", err);
86 goto out_munmap;
87 }
88
89 tp_flags = perf_evsel__intval(evsel, &sample, "flags");
90
91 if (flags != tp_flags) {
92 pr_debug("%s: Expected flags=%#x, got %#x\n",
93 __func__, flags, tp_flags);
94 goto out_munmap;
95 }
96
97 goto out_ok;
98 }
99 }
100
101 if (nr_events == before)
102 poll(evlist->pollfd, evlist->nr_fds, 10);
103
104 if (++nr_polls > 5) {
105 pr_debug("%s: no events!\n", __func__);
106 goto out_munmap;
107 }
108 }
109out_ok:
110 err = 0;
111out_munmap:
112 perf_evlist__munmap(evlist);
113out_delete_evlist:
114 perf_evlist__delete(evlist);
115out:
116 return err;
117}
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c
new file mode 100644
index 000000000000..98be8b518b4f
--- /dev/null
+++ b/tools/perf/tests/open-syscall.c
@@ -0,0 +1,66 @@
1#include "thread_map.h"
2#include "evsel.h"
3#include "debug.h"
4#include "tests.h"
5
6int test__open_syscall_event(void)
7{
8 int err = -1, fd;
9 struct thread_map *threads;
10 struct perf_evsel *evsel;
11 struct perf_event_attr attr;
12 unsigned int nr_open_calls = 111, i;
13 int id = trace_event__id("sys_enter_open");
14
15 if (id < 0) {
16 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
17 return -1;
18 }
19
20 threads = thread_map__new(-1, getpid(), UINT_MAX);
21 if (threads == NULL) {
22 pr_debug("thread_map__new\n");
23 return -1;
24 }
25
26 memset(&attr, 0, sizeof(attr));
27 attr.type = PERF_TYPE_TRACEPOINT;
28 attr.config = id;
29 evsel = perf_evsel__new(&attr, 0);
30 if (evsel == NULL) {
31 pr_debug("perf_evsel__new\n");
32 goto out_thread_map_delete;
33 }
34
35 if (perf_evsel__open_per_thread(evsel, threads) < 0) {
36 pr_debug("failed to open counter: %s, "
37 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
38 strerror(errno));
39 goto out_evsel_delete;
40 }
41
42 for (i = 0; i < nr_open_calls; ++i) {
43 fd = open("/etc/passwd", O_RDONLY);
44 close(fd);
45 }
46
47 if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
48 pr_debug("perf_evsel__read_on_cpu\n");
49 goto out_close_fd;
50 }
51
52 if (evsel->counts->cpu[0].val != nr_open_calls) {
53 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
54 nr_open_calls, evsel->counts->cpu[0].val);
55 goto out_close_fd;
56 }
57
58 err = 0;
59out_close_fd:
60 perf_evsel__close_fd(evsel, 1, threads->nr);
61out_evsel_delete:
62 perf_evsel__delete(evsel);
63out_thread_map_delete:
64 thread_map__delete(threads);
65 return err;
66}
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/tests/parse-events.c
index 6ef213b35ecd..32ee478905eb 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/tests/parse-events.c
@@ -3,6 +3,7 @@
3#include "evsel.h" 3#include "evsel.h"
4#include "evlist.h" 4#include "evlist.h"
5#include "sysfs.h" 5#include "sysfs.h"
6#include "tests.h"
6#include <linux/hw_breakpoint.h> 7#include <linux/hw_breakpoint.h>
7 8
8#define TEST_ASSERT_VAL(text, cond) \ 9#define TEST_ASSERT_VAL(text, cond) \
@@ -443,6 +444,23 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
443 return 0; 444 return 0;
444} 445}
445 446
447static int test__checkevent_pmu_events(struct perf_evlist *evlist)
448{
449 struct perf_evsel *evsel;
450
451 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
452 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
453 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
454 TEST_ASSERT_VAL("wrong exclude_user",
455 !evsel->attr.exclude_user);
456 TEST_ASSERT_VAL("wrong exclude_kernel",
457 evsel->attr.exclude_kernel);
458 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
459 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
460
461 return 0;
462}
463
446static int test__checkterms_simple(struct list_head *terms) 464static int test__checkterms_simple(struct list_head *terms)
447{ 465{
448 struct parse_events__term *term; 466 struct parse_events__term *term;
@@ -503,7 +521,7 @@ static int test__group1(struct perf_evlist *evlist)
503 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 521 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
504 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 522 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
505 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 523 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
506 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 524 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
507 525
508 /* cycles:upp */ 526 /* cycles:upp */
509 evsel = perf_evsel__next(evsel); 527 evsel = perf_evsel__next(evsel);
@@ -539,7 +557,7 @@ static int test__group2(struct perf_evlist *evlist)
539 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 557 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
540 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 558 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
541 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 559 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
542 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 560 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
543 561
544 /* cache-references + :u modifier */ 562 /* cache-references + :u modifier */
545 evsel = perf_evsel__next(evsel); 563 evsel = perf_evsel__next(evsel);
@@ -565,7 +583,7 @@ static int test__group2(struct perf_evlist *evlist)
565 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 583 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
566 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 584 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
567 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 585 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
568 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 586 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
569 587
570 return 0; 588 return 0;
571} 589}
@@ -588,7 +606,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
588 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); 606 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
589 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 607 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
590 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 608 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
591 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 609 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
592 TEST_ASSERT_VAL("wrong group name", 610 TEST_ASSERT_VAL("wrong group name",
593 !strcmp(leader->group_name, "group1")); 611 !strcmp(leader->group_name, "group1"));
594 612
@@ -618,7 +636,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
618 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 636 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
619 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 637 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
620 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 638 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
621 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 639 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
622 TEST_ASSERT_VAL("wrong group name", 640 TEST_ASSERT_VAL("wrong group name",
623 !strcmp(leader->group_name, "group2")); 641 !strcmp(leader->group_name, "group2"));
624 642
@@ -645,7 +663,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
645 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 663 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
646 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 664 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
647 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 665 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
648 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 666 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
649 667
650 return 0; 668 return 0;
651} 669}
@@ -669,7 +687,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
669 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 687 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
670 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); 688 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1);
671 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 689 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
672 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 690 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
673 691
674 /* instructions:kp + p */ 692 /* instructions:kp + p */
675 evsel = perf_evsel__next(evsel); 693 evsel = perf_evsel__next(evsel);
@@ -706,7 +724,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
706 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 724 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
707 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 725 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
708 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 726 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
709 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 727 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
710 728
711 /* instructions + G */ 729 /* instructions + G */
712 evsel = perf_evsel__next(evsel); 730 evsel = perf_evsel__next(evsel);
@@ -733,7 +751,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
733 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 751 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
734 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 752 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
735 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 753 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
736 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 754 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
737 755
738 /* instructions:G */ 756 /* instructions:G */
739 evsel = perf_evsel__next(evsel); 757 evsel = perf_evsel__next(evsel);
@@ -759,7 +777,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
759 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); 777 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
760 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 778 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
761 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 779 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
762 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 780 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
763 781
764 return 0; 782 return 0;
765} 783}
@@ -1024,7 +1042,52 @@ static int test_pmu(void)
1024 return !ret; 1042 return !ret;
1025} 1043}
1026 1044
1027int parse_events__test(void) 1045static int test_pmu_events(void)
1046{
1047 struct stat st;
1048 char path[PATH_MAX];
1049 struct dirent *ent;
1050 DIR *dir;
1051 int ret;
1052
1053 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/events/",
1054 sysfs_find_mountpoint());
1055
1056 ret = stat(path, &st);
1057 if (ret) {
1058 pr_debug("ommiting PMU cpu events tests\n");
1059 return 0;
1060 }
1061
1062 dir = opendir(path);
1063 if (!dir) {
1064 pr_debug("can't open pmu event dir");
1065 return -1;
1066 }
1067
1068 while (!ret && (ent = readdir(dir))) {
1069#define MAX_NAME 100
1070 struct test__event_st e;
1071 char name[MAX_NAME];
1072
1073 if (!strcmp(ent->d_name, ".") ||
1074 !strcmp(ent->d_name, ".."))
1075 continue;
1076
1077 snprintf(name, MAX_NAME, "cpu/event=%s/u", ent->d_name);
1078
1079 e.name = name;
1080 e.check = test__checkevent_pmu_events;
1081
1082 ret = test_event(&e);
1083#undef MAX_NAME
1084 }
1085
1086 closedir(dir);
1087 return ret;
1088}
1089
1090int test__parse_events(void)
1028{ 1091{
1029 int ret1, ret2 = 0; 1092 int ret1, ret2 = 0;
1030 1093
@@ -1040,6 +1103,12 @@ do { \
1040 if (test_pmu()) 1103 if (test_pmu())
1041 TEST_EVENTS(test__events_pmu); 1104 TEST_EVENTS(test__events_pmu);
1042 1105
1106 if (test_pmu()) {
1107 int ret = test_pmu_events();
1108 if (ret)
1109 return ret;
1110 }
1111
1043 ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms)); 1112 ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms));
1044 if (!ret2) 1113 if (!ret2)
1045 ret2 = ret1; 1114 ret2 = ret1;
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
new file mode 100644
index 000000000000..70e0d4421df8
--- /dev/null
+++ b/tools/perf/tests/perf-record.c
@@ -0,0 +1,312 @@
1#include <sched.h>
2#include "evlist.h"
3#include "evsel.h"
4#include "perf.h"
5#include "debug.h"
6#include "tests.h"
7
8static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp)
9{
10 int i, cpu = -1, nrcpus = 1024;
11realloc:
12 CPU_ZERO(maskp);
13
14 if (sched_getaffinity(pid, sizeof(*maskp), maskp) == -1) {
15 if (errno == EINVAL && nrcpus < (1024 << 8)) {
16 nrcpus = nrcpus << 2;
17 goto realloc;
18 }
19 perror("sched_getaffinity");
20 return -1;
21 }
22
23 for (i = 0; i < nrcpus; i++) {
24 if (CPU_ISSET(i, maskp)) {
25 if (cpu == -1)
26 cpu = i;
27 else
28 CPU_CLR(i, maskp);
29 }
30 }
31
32 return cpu;
33}
34
35int test__PERF_RECORD(void)
36{
37 struct perf_record_opts opts = {
38 .target = {
39 .uid = UINT_MAX,
40 .uses_mmap = true,
41 },
42 .no_delay = true,
43 .freq = 10,
44 .mmap_pages = 256,
45 };
46 cpu_set_t cpu_mask;
47 size_t cpu_mask_size = sizeof(cpu_mask);
48 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
49 struct perf_evsel *evsel;
50 struct perf_sample sample;
51 const char *cmd = "sleep";
52 const char *argv[] = { cmd, "1", NULL, };
53 char *bname;
54 u64 prev_time = 0;
55 bool found_cmd_mmap = false,
56 found_libc_mmap = false,
57 found_vdso_mmap = false,
58 found_ld_mmap = false;
59 int err = -1, errs = 0, i, wakeups = 0;
60 u32 cpu;
61 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
62
63 if (evlist == NULL || argv == NULL) {
64 pr_debug("Not enough memory to create evlist\n");
65 goto out;
66 }
67
68 /*
69 * We need at least one evsel in the evlist, use the default
70 * one: "cycles".
71 */
72 err = perf_evlist__add_default(evlist);
73 if (err < 0) {
74 pr_debug("Not enough memory to create evsel\n");
75 goto out_delete_evlist;
76 }
77
78 /*
79 * Create maps of threads and cpus to monitor. In this case
80 * we start with all threads and cpus (-1, -1) but then in
81 * perf_evlist__prepare_workload we'll fill in the only thread
82 * we're monitoring, the one forked there.
83 */
84 err = perf_evlist__create_maps(evlist, &opts.target);
85 if (err < 0) {
86 pr_debug("Not enough memory to create thread/cpu maps\n");
87 goto out_delete_evlist;
88 }
89
90 /*
91 * Prepare the workload in argv[] to run, it'll fork it, and then wait
92 * for perf_evlist__start_workload() to exec it. This is done this way
93 * so that we have time to open the evlist (calling sys_perf_event_open
94 * on all the fds) and then mmap them.
95 */
96 err = perf_evlist__prepare_workload(evlist, &opts, argv);
97 if (err < 0) {
98 pr_debug("Couldn't run the workload!\n");
99 goto out_delete_evlist;
100 }
101
102 /*
103 * Config the evsels, setting attr->comm on the first one, etc.
104 */
105 evsel = perf_evlist__first(evlist);
106 evsel->attr.sample_type |= PERF_SAMPLE_CPU;
107 evsel->attr.sample_type |= PERF_SAMPLE_TID;
108 evsel->attr.sample_type |= PERF_SAMPLE_TIME;
109 perf_evlist__config_attrs(evlist, &opts);
110
111 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
112 if (err < 0) {
113 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
114 goto out_delete_evlist;
115 }
116
117 cpu = err;
118
119 /*
120 * So that we can check perf_sample.cpu on all the samples.
121 */
122 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
123 pr_debug("sched_setaffinity: %s\n", strerror(errno));
124 goto out_delete_evlist;
125 }
126
127 /*
128 * Call sys_perf_event_open on all the fds on all the evsels,
129 * grouping them if asked to.
130 */
131 err = perf_evlist__open(evlist);
132 if (err < 0) {
133 pr_debug("perf_evlist__open: %s\n", strerror(errno));
134 goto out_delete_evlist;
135 }
136
137 /*
138 * mmap the first fd on a given CPU and ask for events for the other
139 * fds in the same CPU to be injected in the same mmap ring buffer
140 * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)).
141 */
142 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
143 if (err < 0) {
144 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
145 goto out_delete_evlist;
146 }
147
148 /*
149 * Now that all is properly set up, enable the events, they will
150 * count just on workload.pid, which will start...
151 */
152 perf_evlist__enable(evlist);
153
154 /*
155 * Now!
156 */
157 perf_evlist__start_workload(evlist);
158
159 while (1) {
160 int before = total_events;
161
162 for (i = 0; i < evlist->nr_mmaps; i++) {
163 union perf_event *event;
164
165 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
166 const u32 type = event->header.type;
167 const char *name = perf_event__name(type);
168
169 ++total_events;
170 if (type < PERF_RECORD_MAX)
171 nr_events[type]++;
172
173 err = perf_evlist__parse_sample(evlist, event, &sample);
174 if (err < 0) {
175 if (verbose)
176 perf_event__fprintf(event, stderr);
177 pr_debug("Couldn't parse sample\n");
178 goto out_err;
179 }
180
181 if (verbose) {
182 pr_info("%" PRIu64" %d ", sample.time, sample.cpu);
183 perf_event__fprintf(event, stderr);
184 }
185
186 if (prev_time > sample.time) {
187 pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n",
188 name, prev_time, sample.time);
189 ++errs;
190 }
191
192 prev_time = sample.time;
193
194 if (sample.cpu != cpu) {
195 pr_debug("%s with unexpected cpu, expected %d, got %d\n",
196 name, cpu, sample.cpu);
197 ++errs;
198 }
199
200 if ((pid_t)sample.pid != evlist->workload.pid) {
201 pr_debug("%s with unexpected pid, expected %d, got %d\n",
202 name, evlist->workload.pid, sample.pid);
203 ++errs;
204 }
205
206 if ((pid_t)sample.tid != evlist->workload.pid) {
207 pr_debug("%s with unexpected tid, expected %d, got %d\n",
208 name, evlist->workload.pid, sample.tid);
209 ++errs;
210 }
211
212 if ((type == PERF_RECORD_COMM ||
213 type == PERF_RECORD_MMAP ||
214 type == PERF_RECORD_FORK ||
215 type == PERF_RECORD_EXIT) &&
216 (pid_t)event->comm.pid != evlist->workload.pid) {
217 pr_debug("%s with unexpected pid/tid\n", name);
218 ++errs;
219 }
220
221 if ((type == PERF_RECORD_COMM ||
222 type == PERF_RECORD_MMAP) &&
223 event->comm.pid != event->comm.tid) {
224 pr_debug("%s with different pid/tid!\n", name);
225 ++errs;
226 }
227
228 switch (type) {
229 case PERF_RECORD_COMM:
230 if (strcmp(event->comm.comm, cmd)) {
231 pr_debug("%s with unexpected comm!\n", name);
232 ++errs;
233 }
234 break;
235 case PERF_RECORD_EXIT:
236 goto found_exit;
237 case PERF_RECORD_MMAP:
238 bname = strrchr(event->mmap.filename, '/');
239 if (bname != NULL) {
240 if (!found_cmd_mmap)
241 found_cmd_mmap = !strcmp(bname + 1, cmd);
242 if (!found_libc_mmap)
243 found_libc_mmap = !strncmp(bname + 1, "libc", 4);
244 if (!found_ld_mmap)
245 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
246 } else if (!found_vdso_mmap)
247 found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
248 break;
249
250 case PERF_RECORD_SAMPLE:
251 /* Just ignore samples for now */
252 break;
253 default:
254 pr_debug("Unexpected perf_event->header.type %d!\n",
255 type);
256 ++errs;
257 }
258 }
259 }
260
261 /*
262 * We don't use poll here because at least at 3.1 times the
263 * PERF_RECORD_{!SAMPLE} events don't honour
264 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
265 */
266 if (total_events == before && false)
267 poll(evlist->pollfd, evlist->nr_fds, -1);
268
269 sleep(1);
270 if (++wakeups > 5) {
271 pr_debug("No PERF_RECORD_EXIT event!\n");
272 break;
273 }
274 }
275
276found_exit:
277 if (nr_events[PERF_RECORD_COMM] > 1) {
278 pr_debug("Excessive number of PERF_RECORD_COMM events!\n");
279 ++errs;
280 }
281
282 if (nr_events[PERF_RECORD_COMM] == 0) {
283 pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd);
284 ++errs;
285 }
286
287 if (!found_cmd_mmap) {
288 pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd);
289 ++errs;
290 }
291
292 if (!found_libc_mmap) {
293 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc");
294 ++errs;
295 }
296
297 if (!found_ld_mmap) {
298 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld");
299 ++errs;
300 }
301
302 if (!found_vdso_mmap) {
303 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
304 ++errs;
305 }
306out_err:
307 perf_evlist__munmap(evlist);
308out_delete_evlist:
309 perf_evlist__delete(evlist);
310out:
311 return (err < 0 || errs > 0) ? -1 : 0;
312}
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
new file mode 100644
index 000000000000..a5f379863b8f
--- /dev/null
+++ b/tools/perf/tests/pmu.c
@@ -0,0 +1,178 @@
1#include "parse-events.h"
2#include "pmu.h"
3#include "util.h"
4#include "tests.h"
5
6/* Simulated format definitions. */
7static struct test_format {
8 const char *name;
9 const char *value;
10} test_formats[] = {
11 { "krava01", "config:0-1,62-63\n", },
12 { "krava02", "config:10-17\n", },
13 { "krava03", "config:5\n", },
14 { "krava11", "config1:0,2,4,6,8,20-28\n", },
15 { "krava12", "config1:63\n", },
16 { "krava13", "config1:45-47\n", },
17 { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
18 { "krava22", "config2:8,18,48,58\n", },
19 { "krava23", "config2:28-29,38\n", },
20};
21
22#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
23
24/* Simulated users input. */
25static struct parse_events__term test_terms[] = {
26 {
27 .config = (char *) "krava01",
28 .val.num = 15,
29 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
30 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
31 },
32 {
33 .config = (char *) "krava02",
34 .val.num = 170,
35 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
36 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
37 },
38 {
39 .config = (char *) "krava03",
40 .val.num = 1,
41 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
42 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
43 },
44 {
45 .config = (char *) "krava11",
46 .val.num = 27,
47 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
48 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
49 },
50 {
51 .config = (char *) "krava12",
52 .val.num = 1,
53 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
54 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
55 },
56 {
57 .config = (char *) "krava13",
58 .val.num = 2,
59 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
60 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
61 },
62 {
63 .config = (char *) "krava21",
64 .val.num = 119,
65 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
66 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
67 },
68 {
69 .config = (char *) "krava22",
70 .val.num = 11,
71 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
72 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
73 },
74 {
75 .config = (char *) "krava23",
76 .val.num = 2,
77 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
78 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
79 },
80};
81#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
82
83/*
84 * Prepare format directory data, exported by kernel
85 * at /sys/bus/event_source/devices/<dev>/format.
86 */
87static char *test_format_dir_get(void)
88{
89 static char dir[PATH_MAX];
90 unsigned int i;
91
92 snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
93 if (!mkdtemp(dir))
94 return NULL;
95
96 for (i = 0; i < TEST_FORMATS_CNT; i++) {
97 static char name[PATH_MAX];
98 struct test_format *format = &test_formats[i];
99 FILE *file;
100
101 snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
102
103 file = fopen(name, "w");
104 if (!file)
105 return NULL;
106
107 if (1 != fwrite(format->value, strlen(format->value), 1, file))
108 break;
109
110 fclose(file);
111 }
112
113 return dir;
114}
115
116/* Cleanup format directory. */
117static int test_format_dir_put(char *dir)
118{
119 char buf[PATH_MAX];
120 snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
121 if (system(buf))
122 return -1;
123
124 snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
125 return system(buf);
126}
127
128static struct list_head *test_terms_list(void)
129{
130 static LIST_HEAD(terms);
131 unsigned int i;
132
133 for (i = 0; i < TERMS_CNT; i++)
134 list_add_tail(&test_terms[i].list, &terms);
135
136 return &terms;
137}
138
139#undef TERMS_CNT
140
141int test__pmu(void)
142{
143 char *format = test_format_dir_get();
144 LIST_HEAD(formats);
145 struct list_head *terms = test_terms_list();
146 int ret;
147
148 if (!format)
149 return -EINVAL;
150
151 do {
152 struct perf_event_attr attr;
153
154 memset(&attr, 0, sizeof(attr));
155
156 ret = perf_pmu__format_parse(format, &formats);
157 if (ret)
158 break;
159
160 ret = perf_pmu__config_terms(&formats, &attr, terms);
161 if (ret)
162 break;
163
164 ret = -EINVAL;
165
166 if (attr.config != 0xc00000000002a823)
167 break;
168 if (attr.config1 != 0x8000400000000145)
169 break;
170 if (attr.config2 != 0x0400000020041d07)
171 break;
172
173 ret = 0;
174 } while (0);
175
176 test_format_dir_put(format);
177 return ret;
178}
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
new file mode 100644
index 000000000000..ff94886aad99
--- /dev/null
+++ b/tools/perf/tests/rdpmc.c
@@ -0,0 +1,175 @@
1#include <unistd.h>
2#include <stdlib.h>
3#include <signal.h>
4#include <sys/mman.h>
5#include "types.h"
6#include "perf.h"
7#include "debug.h"
8#include "tests.h"
9
10#if defined(__x86_64__) || defined(__i386__)
11
12#define barrier() asm volatile("" ::: "memory")
13
14static u64 rdpmc(unsigned int counter)
15{
16 unsigned int low, high;
17
18 asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
19
20 return low | ((u64)high) << 32;
21}
22
23static u64 rdtsc(void)
24{
25 unsigned int low, high;
26
27 asm volatile("rdtsc" : "=a" (low), "=d" (high));
28
29 return low | ((u64)high) << 32;
30}
31
32static u64 mmap_read_self(void *addr)
33{
34 struct perf_event_mmap_page *pc = addr;
35 u32 seq, idx, time_mult = 0, time_shift = 0;
36 u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
37
38 do {
39 seq = pc->lock;
40 barrier();
41
42 enabled = pc->time_enabled;
43 running = pc->time_running;
44
45 if (enabled != running) {
46 cyc = rdtsc();
47 time_mult = pc->time_mult;
48 time_shift = pc->time_shift;
49 time_offset = pc->time_offset;
50 }
51
52 idx = pc->index;
53 count = pc->offset;
54 if (idx)
55 count += rdpmc(idx - 1);
56
57 barrier();
58 } while (pc->lock != seq);
59
60 if (enabled != running) {
61 u64 quot, rem;
62
63 quot = (cyc >> time_shift);
64 rem = cyc & ((1 << time_shift) - 1);
65 delta = time_offset + quot * time_mult +
66 ((rem * time_mult) >> time_shift);
67
68 enabled += delta;
69 if (idx)
70 running += delta;
71
72 quot = count / running;
73 rem = count % running;
74 count = quot * enabled + (rem * enabled) / running;
75 }
76
77 return count;
78}
79
80/*
81 * If the RDPMC instruction faults then signal this back to the test parent task:
82 */
83static void segfault_handler(int sig __maybe_unused,
84 siginfo_t *info __maybe_unused,
85 void *uc __maybe_unused)
86{
87 exit(-1);
88}
89
90static int __test__rdpmc(void)
91{
92 volatile int tmp = 0;
93 u64 i, loops = 1000;
94 int n;
95 int fd;
96 void *addr;
97 struct perf_event_attr attr = {
98 .type = PERF_TYPE_HARDWARE,
99 .config = PERF_COUNT_HW_INSTRUCTIONS,
100 .exclude_kernel = 1,
101 };
102 u64 delta_sum = 0;
103 struct sigaction sa;
104
105 sigfillset(&sa.sa_mask);
106 sa.sa_sigaction = segfault_handler;
107 sigaction(SIGSEGV, &sa, NULL);
108
109 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
110 if (fd < 0) {
111 pr_err("Error: sys_perf_event_open() syscall returned "
112 "with %d (%s)\n", fd, strerror(errno));
113 return -1;
114 }
115
116 addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
117 if (addr == (void *)(-1)) {
118 pr_err("Error: mmap() syscall returned with (%s)\n",
119 strerror(errno));
120 goto out_close;
121 }
122
123 for (n = 0; n < 6; n++) {
124 u64 stamp, now, delta;
125
126 stamp = mmap_read_self(addr);
127
128 for (i = 0; i < loops; i++)
129 tmp++;
130
131 now = mmap_read_self(addr);
132 loops *= 10;
133
134 delta = now - stamp;
135 pr_debug("%14d: %14Lu\n", n, (long long)delta);
136
137 delta_sum += delta;
138 }
139
140 munmap(addr, page_size);
141 pr_debug(" ");
142out_close:
143 close(fd);
144
145 if (!delta_sum)
146 return -1;
147
148 return 0;
149}
150
151int test__rdpmc(void)
152{
153 int status = 0;
154 int wret = 0;
155 int ret;
156 int pid;
157
158 pid = fork();
159 if (pid < 0)
160 return -1;
161
162 if (!pid) {
163 ret = __test__rdpmc();
164
165 exit(ret);
166 }
167
168 wret = waitpid(pid, &status, 0);
169 if (wret < 0 || status)
170 return -1;
171
172 return 0;
173}
174
175#endif
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
new file mode 100644
index 000000000000..fc121edab016
--- /dev/null
+++ b/tools/perf/tests/tests.h
@@ -0,0 +1,22 @@
1#ifndef TESTS_H
2#define TESTS_H
3
4/* Tests */
5int test__vmlinux_matches_kallsyms(void);
6int test__open_syscall_event(void);
7int test__open_syscall_event_on_all_cpus(void);
8int test__basic_mmap(void);
9int test__PERF_RECORD(void);
10int test__rdpmc(void);
11int test__perf_evsel__roundtrip_name_test(void);
12int test__perf_evsel__tp_sched_test(void);
13int test__syscall_open_tp_fields(void);
14int test__pmu(void);
15int test__attr(void);
16int test__dso_data(void);
17int test__parse_events(void);
18
19/* Util */
20int trace_event__id(const char *evname);
21
22#endif /* TESTS_H */
diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c
new file mode 100644
index 000000000000..748f2e8f6961
--- /dev/null
+++ b/tools/perf/tests/util.c
@@ -0,0 +1,30 @@
1#include <stdio.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include "tests.h"
8#include "debugfs.h"
9
10int trace_event__id(const char *evname)
11{
12 char *filename;
13 int err = -1, fd;
14
15 if (asprintf(&filename,
16 "%s/syscalls/%s/id",
17 tracing_events_path, evname) < 0)
18 return -1;
19
20 fd = open(filename, O_RDONLY);
21 if (fd >= 0) {
22 char id[16];
23 if (read(fd, id, sizeof(id)) > 0)
24 err = atoi(id);
25 close(fd);
26 }
27
28 free(filename);
29 return err;
30}
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
new file mode 100644
index 000000000000..0d1cdbee2f59
--- /dev/null
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -0,0 +1,230 @@
1#include <linux/compiler.h>
2#include <linux/rbtree.h>
3#include <string.h>
4#include "map.h"
5#include "symbol.h"
6#include "util.h"
7#include "tests.h"
8#include "debug.h"
9#include "machine.h"
10
11static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
12 struct symbol *sym)
13{
14 bool *visited = symbol__priv(sym);
15 *visited = true;
16 return 0;
17}
18
19int test__vmlinux_matches_kallsyms(void)
20{
21 int err = -1;
22 struct rb_node *nd;
23 struct symbol *sym;
24 struct map *kallsyms_map, *vmlinux_map;
25 struct machine kallsyms, vmlinux;
26 enum map_type type = MAP__FUNCTION;
27 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
28
29 /*
30 * Step 1:
31 *
32 * Init the machines that will hold kernel, modules obtained from
33 * both vmlinux + .ko files and from /proc/kallsyms split by modules.
34 */
35 machine__init(&kallsyms, "", HOST_KERNEL_ID);
36 machine__init(&vmlinux, "", HOST_KERNEL_ID);
37
38 /*
39 * Step 2:
40 *
41 * Create the kernel maps for kallsyms and the DSO where we will then
42 * load /proc/kallsyms. Also create the modules maps from /proc/modules
43 * and find the .ko files that match them in /lib/modules/`uname -r`/.
44 */
45 if (machine__create_kernel_maps(&kallsyms) < 0) {
46 pr_debug("machine__create_kernel_maps ");
47 return -1;
48 }
49
50 /*
51 * Step 3:
52 *
53 * Load and split /proc/kallsyms into multiple maps, one per module.
54 */
55 if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) {
56 pr_debug("dso__load_kallsyms ");
57 goto out;
58 }
59
60 /*
61 * Step 4:
62 *
63 * kallsyms will be internally on demand sorted by name so that we can
64 * find the reference relocation * symbol, i.e. the symbol we will use
65 * to see if the running kernel was relocated by checking if it has the
66 * same value in the vmlinux file we load.
67 */
68 kallsyms_map = machine__kernel_map(&kallsyms, type);
69
70 sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL);
71 if (sym == NULL) {
72 pr_debug("dso__find_symbol_by_name ");
73 goto out;
74 }
75
76 ref_reloc_sym.addr = sym->start;
77
78 /*
79 * Step 5:
80 *
81 * Now repeat step 2, this time for the vmlinux file we'll auto-locate.
82 */
83 if (machine__create_kernel_maps(&vmlinux) < 0) {
84 pr_debug("machine__create_kernel_maps ");
85 goto out;
86 }
87
88 vmlinux_map = machine__kernel_map(&vmlinux, type);
89 map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym;
90
91 /*
92 * Step 6:
93 *
94 * Locate a vmlinux file in the vmlinux path that has a buildid that
95 * matches the one of the running kernel.
96 *
97 * While doing that look if we find the ref reloc symbol, if we find it
98 * we'll have its ref_reloc_symbol.unrelocated_addr and then
99 * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines
100 * to fixup the symbols.
101 */
102 if (machine__load_vmlinux_path(&vmlinux, type,
103 vmlinux_matches_kallsyms_filter) <= 0) {
104 pr_debug("machine__load_vmlinux_path ");
105 goto out;
106 }
107
108 err = 0;
109 /*
110 * Step 7:
111 *
112 * Now look at the symbols in the vmlinux DSO and check if we find all of them
113 * in the kallsyms dso. For the ones that are in both, check its names and
114 * end addresses too.
115 */
116 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
117 struct symbol *pair, *first_pair;
118 bool backwards = true;
119
120 sym = rb_entry(nd, struct symbol, rb_node);
121
122 if (sym->start == sym->end)
123 continue;
124
125 first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
126 pair = first_pair;
127
128 if (pair && pair->start == sym->start) {
129next_pair:
130 if (strcmp(sym->name, pair->name) == 0) {
131 /*
132 * kallsyms don't have the symbol end, so we
133 * set that by using the next symbol start - 1,
134 * in some cases we get this up to a page
135 * wrong, trace_kmalloc when I was developing
136 * this code was one such example, 2106 bytes
137 * off the real size. More than that and we
138 * _really_ have a problem.
139 */
140 s64 skew = sym->end - pair->end;
141 if (llabs(skew) < page_size)
142 continue;
143
144 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
145 sym->start, sym->name, sym->end, pair->end);
146 } else {
147 struct rb_node *nnd;
148detour:
149 nnd = backwards ? rb_prev(&pair->rb_node) :
150 rb_next(&pair->rb_node);
151 if (nnd) {
152 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
153
154 if (next->start == sym->start) {
155 pair = next;
156 goto next_pair;
157 }
158 }
159
160 if (backwards) {
161 backwards = false;
162 pair = first_pair;
163 goto detour;
164 }
165
166 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
167 sym->start, sym->name, pair->name);
168 }
169 } else
170 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
171
172 err = -1;
173 }
174
175 if (!verbose)
176 goto out;
177
178 pr_info("Maps only in vmlinux:\n");
179
180 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
181 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
182 /*
183 * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
184 * the kernel will have the path for the vmlinux file being used,
185 * so use the short name, less descriptive but the same ("[kernel]" in
186 * both cases.
187 */
188 pair = map_groups__find_by_name(&kallsyms.kmaps, type,
189 (pos->dso->kernel ?
190 pos->dso->short_name :
191 pos->dso->name));
192 if (pair)
193 pair->priv = 1;
194 else
195 map__fprintf(pos, stderr);
196 }
197
198 pr_info("Maps in vmlinux with a different name in kallsyms:\n");
199
200 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
201 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
202
203 pair = map_groups__find(&kallsyms.kmaps, type, pos->start);
204 if (pair == NULL || pair->priv)
205 continue;
206
207 if (pair->start == pos->start) {
208 pair->priv = 1;
209 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
210 pos->start, pos->end, pos->pgoff, pos->dso->name);
211 if (pos->pgoff != pair->pgoff || pos->end != pair->end)
212 pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
213 pair->start, pair->end, pair->pgoff);
214 pr_info(" %s\n", pair->dso->name);
215 pair->priv = 1;
216 }
217 }
218
219 pr_info("Maps only in kallsyms:\n");
220
221 for (nd = rb_first(&kallsyms.kmaps.maps[type]);
222 nd; nd = rb_next(nd)) {
223 struct map *pos = rb_entry(nd, struct map, rb_node);
224
225 if (!pos->priv)
226 map__fprintf(pos, stderr);
227 }
228out:
229 return err;
230}
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 8f8cd2d73b3b..5dab3ca96980 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -188,6 +188,12 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
188 struct disasm_line *cursor = ab->selection, *target; 188 struct disasm_line *cursor = ab->selection, *target;
189 struct browser_disasm_line *btarget, *bcursor; 189 struct browser_disasm_line *btarget, *bcursor;
190 unsigned int from, to; 190 unsigned int from, to;
191 struct map_symbol *ms = ab->b.priv;
192 struct symbol *sym = ms->sym;
193
194 /* PLT symbols contain external offsets */
195 if (strstr(sym->name, "@plt"))
196 return;
191 197
192 if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) || 198 if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
193 !disasm_line__has_offset(cursor)) 199 !disasm_line__has_offset(cursor))
@@ -386,9 +392,8 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
386 browser->b.nr_entries = browser->nr_asm_entries; 392 browser->b.nr_entries = browser->nr_asm_entries;
387} 393}
388 394
389static bool annotate_browser__callq(struct annotate_browser *browser, 395static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
390 int evidx, void (*timer)(void *arg), 396 struct hist_browser_timer *hbt)
391 void *arg, int delay_secs)
392{ 397{
393 struct map_symbol *ms = browser->b.priv; 398 struct map_symbol *ms = browser->b.priv;
394 struct disasm_line *dl = browser->selection; 399 struct disasm_line *dl = browser->selection;
@@ -418,7 +423,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
418 } 423 }
419 424
420 pthread_mutex_unlock(&notes->lock); 425 pthread_mutex_unlock(&notes->lock);
421 symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs); 426 symbol__tui_annotate(target, ms->map, evidx, hbt);
422 ui_browser__show_title(&browser->b, sym->name); 427 ui_browser__show_title(&browser->b, sym->name);
423 return true; 428 return true;
424} 429}
@@ -602,13 +607,13 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser
602} 607}
603 608
604static int annotate_browser__run(struct annotate_browser *browser, int evidx, 609static int annotate_browser__run(struct annotate_browser *browser, int evidx,
605 void(*timer)(void *arg), 610 struct hist_browser_timer *hbt)
606 void *arg, int delay_secs)
607{ 611{
608 struct rb_node *nd = NULL; 612 struct rb_node *nd = NULL;
609 struct map_symbol *ms = browser->b.priv; 613 struct map_symbol *ms = browser->b.priv;
610 struct symbol *sym = ms->sym; 614 struct symbol *sym = ms->sym;
611 const char *help = "Press 'h' for help on key bindings"; 615 const char *help = "Press 'h' for help on key bindings";
616 int delay_secs = hbt ? hbt->refresh : 0;
612 int key; 617 int key;
613 618
614 if (ui_browser__show(&browser->b, sym->name, help) < 0) 619 if (ui_browser__show(&browser->b, sym->name, help) < 0)
@@ -639,8 +644,8 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
639 644
640 switch (key) { 645 switch (key) {
641 case K_TIMER: 646 case K_TIMER:
642 if (timer != NULL) 647 if (hbt)
643 timer(arg); 648 hbt->timer(hbt->arg);
644 649
645 if (delay_secs != 0) 650 if (delay_secs != 0)
646 symbol__annotate_decay_histogram(sym, evidx); 651 symbol__annotate_decay_histogram(sym, evidx);
@@ -676,8 +681,14 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
676 "o Toggle disassembler output/simplified view\n" 681 "o Toggle disassembler output/simplified view\n"
677 "s Toggle source code view\n" 682 "s Toggle source code view\n"
678 "/ Search string\n" 683 "/ Search string\n"
684 "r Run available scripts\n"
679 "? Search previous string\n"); 685 "? Search previous string\n");
680 continue; 686 continue;
687 case 'r':
688 {
689 script_browse(NULL);
690 continue;
691 }
681 case 'H': 692 case 'H':
682 nd = browser->curr_hot; 693 nd = browser->curr_hot;
683 break; 694 break;
@@ -734,7 +745,7 @@ show_help:
734 goto show_sup_ins; 745 goto show_sup_ins;
735 goto out; 746 goto out;
736 } else if (!(annotate_browser__jump(browser) || 747 } else if (!(annotate_browser__jump(browser) ||
737 annotate_browser__callq(browser, evidx, timer, arg, delay_secs))) { 748 annotate_browser__callq(browser, evidx, hbt))) {
738show_sup_ins: 749show_sup_ins:
739 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); 750 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
740 } 751 }
@@ -757,16 +768,21 @@ out:
757} 768}
758 769
759int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 770int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
760 void(*timer)(void *arg), void *arg, int delay_secs) 771 struct hist_browser_timer *hbt)
761{ 772{
762 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 773 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt);
763 timer, arg, delay_secs);
764} 774}
765 775
766static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, 776static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
767 size_t size) 777 size_t size)
768{ 778{
769 u64 offset; 779 u64 offset;
780 struct map_symbol *ms = browser->b.priv;
781 struct symbol *sym = ms->sym;
782
783 /* PLT symbols contain external offsets */
784 if (strstr(sym->name, "@plt"))
785 return;
770 786
771 for (offset = 0; offset < size; ++offset) { 787 for (offset = 0; offset < size; ++offset) {
772 struct disasm_line *dl = browser->offsets[offset], *dlt; 788 struct disasm_line *dl = browser->offsets[offset], *dlt;
@@ -810,8 +826,7 @@ static inline int width_jumps(int n)
810} 826}
811 827
812int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 828int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
813 void(*timer)(void *arg), void *arg, 829 struct hist_browser_timer *hbt)
814 int delay_secs)
815{ 830{
816 struct disasm_line *pos, *n; 831 struct disasm_line *pos, *n;
817 struct annotation *notes; 832 struct annotation *notes;
@@ -893,7 +908,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
893 908
894 annotate_browser__update_addr_width(&browser); 909 annotate_browser__update_addr_width(&browser);
895 910
896 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); 911 ret = annotate_browser__run(&browser, evidx, hbt);
897 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 912 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
898 list_del(&pos->node); 913 list_del(&pos->node);
899 disasm_line__free(pos); 914 disasm_line__free(pos);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index ef2f93ca7496..ccc4bd161420 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -11,6 +11,7 @@
11#include "../../util/pstack.h" 11#include "../../util/pstack.h"
12#include "../../util/sort.h" 12#include "../../util/sort.h"
13#include "../../util/util.h" 13#include "../../util/util.h"
14#include "../../arch/common.h"
14 15
15#include "../browser.h" 16#include "../browser.h"
16#include "../helpline.h" 17#include "../helpline.h"
@@ -310,10 +311,11 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
310} 311}
311 312
312static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 313static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
313 void(*timer)(void *arg), void *arg, int delay_secs) 314 struct hist_browser_timer *hbt)
314{ 315{
315 int key; 316 int key;
316 char title[160]; 317 char title[160];
318 int delay_secs = hbt ? hbt->refresh : 0;
317 319
318 browser->b.entries = &browser->hists->entries; 320 browser->b.entries = &browser->hists->entries;
319 browser->b.nr_entries = browser->hists->nr_entries; 321 browser->b.nr_entries = browser->hists->nr_entries;
@@ -330,7 +332,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
330 332
331 switch (key) { 333 switch (key) {
332 case K_TIMER: 334 case K_TIMER:
333 timer(arg); 335 hbt->timer(hbt->arg);
334 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 336 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
335 337
336 if (browser->hists->stats.nr_lost_warned != 338 if (browser->hists->stats.nr_lost_warned !=
@@ -1127,11 +1129,17 @@ static inline void free_popup_options(char **options, int n)
1127 } 1129 }
1128} 1130}
1129 1131
1132/* Check whether the browser is for 'top' or 'report' */
1133static inline bool is_report_browser(void *timer)
1134{
1135 return timer == NULL;
1136}
1137
1130static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1138static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1131 const char *helpline, const char *ev_name, 1139 const char *helpline, const char *ev_name,
1132 bool left_exits, 1140 bool left_exits,
1133 void(*timer)(void *arg), void *arg, 1141 struct hist_browser_timer *hbt,
1134 int delay_secs) 1142 struct perf_session_env *env)
1135{ 1143{
1136 struct hists *hists = &evsel->hists; 1144 struct hists *hists = &evsel->hists;
1137 struct hist_browser *browser = hist_browser__new(hists); 1145 struct hist_browser *browser = hist_browser__new(hists);
@@ -1141,6 +1149,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1141 int nr_options = 0; 1149 int nr_options = 0;
1142 int key = -1; 1150 int key = -1;
1143 char buf[64]; 1151 char buf[64];
1152 char script_opt[64];
1153 int delay_secs = hbt ? hbt->refresh : 0;
1144 1154
1145 if (browser == NULL) 1155 if (browser == NULL)
1146 return -1; 1156 return -1;
@@ -1159,10 +1169,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1159 int choice = 0, 1169 int choice = 0,
1160 annotate = -2, zoom_dso = -2, zoom_thread = -2, 1170 annotate = -2, zoom_dso = -2, zoom_thread = -2,
1161 annotate_f = -2, annotate_t = -2, browse_map = -2; 1171 annotate_f = -2, annotate_t = -2, browse_map = -2;
1172 int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2;
1162 1173
1163 nr_options = 0; 1174 nr_options = 0;
1164 1175
1165 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs); 1176 key = hist_browser__run(browser, ev_name, hbt);
1166 1177
1167 if (browser->he_selection != NULL) { 1178 if (browser->he_selection != NULL) {
1168 thread = hist_browser__selected_thread(browser); 1179 thread = hist_browser__selected_thread(browser);
@@ -1211,6 +1222,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1211 hist_browser__reset(browser); 1222 hist_browser__reset(browser);
1212 } 1223 }
1213 continue; 1224 continue;
1225 case 'r':
1226 if (is_report_browser(hbt))
1227 goto do_scripts;
1228 continue;
1214 case K_F1: 1229 case K_F1:
1215 case 'h': 1230 case 'h':
1216 case '?': 1231 case '?':
@@ -1229,6 +1244,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1229 "E Expand all callchains\n" 1244 "E Expand all callchains\n"
1230 "d Zoom into current DSO\n" 1245 "d Zoom into current DSO\n"
1231 "t Zoom into current Thread\n" 1246 "t Zoom into current Thread\n"
1247 "r Run available scripts('perf report' only)\n"
1232 "P Print histograms to perf.hist.N\n" 1248 "P Print histograms to perf.hist.N\n"
1233 "V Verbose (DSO names in callchains, etc)\n" 1249 "V Verbose (DSO names in callchains, etc)\n"
1234 "/ Filter symbol by name"); 1250 "/ Filter symbol by name");
@@ -1317,6 +1333,25 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1317 browser->selection->map != NULL && 1333 browser->selection->map != NULL &&
1318 asprintf(&options[nr_options], "Browse map details") > 0) 1334 asprintf(&options[nr_options], "Browse map details") > 0)
1319 browse_map = nr_options++; 1335 browse_map = nr_options++;
1336
1337 /* perf script support */
1338 if (browser->he_selection) {
1339 struct symbol *sym;
1340
1341 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
1342 browser->he_selection->thread->comm) > 0)
1343 scripts_comm = nr_options++;
1344
1345 sym = browser->he_selection->ms.sym;
1346 if (sym && sym->namelen &&
1347 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1348 sym->name) > 0)
1349 scripts_symbol = nr_options++;
1350 }
1351
1352 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1353 scripts_all = nr_options++;
1354
1320add_exit_option: 1355add_exit_option:
1321 options[nr_options++] = (char *)"Exit"; 1356 options[nr_options++] = (char *)"Exit";
1322retry_popup_menu: 1357retry_popup_menu:
@@ -1334,6 +1369,9 @@ retry_popup_menu:
1334 struct hist_entry *he; 1369 struct hist_entry *he;
1335 int err; 1370 int err;
1336do_annotate: 1371do_annotate:
1372 if (!objdump_path && perf_session_env__lookup_objdump(env))
1373 continue;
1374
1337 he = hist_browser__selected_entry(browser); 1375 he = hist_browser__selected_entry(browser);
1338 if (he == NULL) 1376 if (he == NULL)
1339 continue; 1377 continue;
@@ -1356,8 +1394,7 @@ do_annotate:
1356 * Don't let this be freed, say, by hists__decay_entry. 1394 * Don't let this be freed, say, by hists__decay_entry.
1357 */ 1395 */
1358 he->used = true; 1396 he->used = true;
1359 err = hist_entry__tui_annotate(he, evsel->idx, 1397 err = hist_entry__tui_annotate(he, evsel->idx, hbt);
1360 timer, arg, delay_secs);
1361 he->used = false; 1398 he->used = false;
1362 /* 1399 /*
1363 * offer option to annotate the other branch source or target 1400 * offer option to annotate the other branch source or target
@@ -1411,6 +1448,20 @@ zoom_out_thread:
1411 hists__filter_by_thread(hists); 1448 hists__filter_by_thread(hists);
1412 hist_browser__reset(browser); 1449 hist_browser__reset(browser);
1413 } 1450 }
1451 /* perf scripts support */
1452 else if (choice == scripts_all || choice == scripts_comm ||
1453 choice == scripts_symbol) {
1454do_scripts:
1455 memset(script_opt, 0, 64);
1456
1457 if (choice == scripts_comm)
1458 sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm);
1459
1460 if (choice == scripts_symbol)
1461 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1462
1463 script_browse(script_opt);
1464 }
1414 } 1465 }
1415out_free_stack: 1466out_free_stack:
1416 pstack__delete(fstack); 1467 pstack__delete(fstack);
@@ -1424,6 +1475,7 @@ struct perf_evsel_menu {
1424 struct ui_browser b; 1475 struct ui_browser b;
1425 struct perf_evsel *selection; 1476 struct perf_evsel *selection;
1426 bool lost_events, lost_events_warned; 1477 bool lost_events, lost_events_warned;
1478 struct perf_session_env *env;
1427}; 1479};
1428 1480
1429static void perf_evsel_menu__write(struct ui_browser *browser, 1481static void perf_evsel_menu__write(struct ui_browser *browser,
@@ -1466,11 +1518,12 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1466 1518
1467static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 1519static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1468 int nr_events, const char *help, 1520 int nr_events, const char *help,
1469 void(*timer)(void *arg), void *arg, int delay_secs) 1521 struct hist_browser_timer *hbt)
1470{ 1522{
1471 struct perf_evlist *evlist = menu->b.priv; 1523 struct perf_evlist *evlist = menu->b.priv;
1472 struct perf_evsel *pos; 1524 struct perf_evsel *pos;
1473 const char *ev_name, *title = "Available samples"; 1525 const char *ev_name, *title = "Available samples";
1526 int delay_secs = hbt ? hbt->refresh : 0;
1474 int key; 1527 int key;
1475 1528
1476 if (ui_browser__show(&menu->b, title, 1529 if (ui_browser__show(&menu->b, title,
@@ -1482,7 +1535,7 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1482 1535
1483 switch (key) { 1536 switch (key) {
1484 case K_TIMER: 1537 case K_TIMER:
1485 timer(arg); 1538 hbt->timer(hbt->arg);
1486 1539
1487 if (!menu->lost_events_warned && menu->lost_events) { 1540 if (!menu->lost_events_warned && menu->lost_events) {
1488 ui_browser__warn_lost_events(&menu->b); 1541 ui_browser__warn_lost_events(&menu->b);
@@ -1500,12 +1553,12 @@ browse_hists:
1500 * Give the calling tool a chance to populate the non 1553 * Give the calling tool a chance to populate the non
1501 * default evsel resorted hists tree. 1554 * default evsel resorted hists tree.
1502 */ 1555 */
1503 if (timer) 1556 if (hbt)
1504 timer(arg); 1557 hbt->timer(hbt->arg);
1505 ev_name = perf_evsel__name(pos); 1558 ev_name = perf_evsel__name(pos);
1506 key = perf_evsel__hists_browse(pos, nr_events, help, 1559 key = perf_evsel__hists_browse(pos, nr_events, help,
1507 ev_name, true, timer, 1560 ev_name, true, hbt,
1508 arg, delay_secs); 1561 menu->env);
1509 ui_browser__show_title(&menu->b, title); 1562 ui_browser__show_title(&menu->b, title);
1510 switch (key) { 1563 switch (key) {
1511 case K_TAB: 1564 case K_TAB:
@@ -1553,8 +1606,8 @@ out:
1553 1606
1554static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1607static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1555 const char *help, 1608 const char *help,
1556 void(*timer)(void *arg), void *arg, 1609 struct hist_browser_timer *hbt,
1557 int delay_secs) 1610 struct perf_session_env *env)
1558{ 1611{
1559 struct perf_evsel *pos; 1612 struct perf_evsel *pos;
1560 struct perf_evsel_menu menu = { 1613 struct perf_evsel_menu menu = {
@@ -1566,6 +1619,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1566 .nr_entries = evlist->nr_entries, 1619 .nr_entries = evlist->nr_entries,
1567 .priv = evlist, 1620 .priv = evlist,
1568 }, 1621 },
1622 .env = env,
1569 }; 1623 };
1570 1624
1571 ui_helpline__push("Press ESC to exit"); 1625 ui_helpline__push("Press ESC to exit");
@@ -1578,23 +1632,20 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1578 menu.b.width = line_len; 1632 menu.b.width = line_len;
1579 } 1633 }
1580 1634
1581 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer, 1635 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, hbt);
1582 arg, delay_secs);
1583} 1636}
1584 1637
1585int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 1638int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1586 void(*timer)(void *arg), void *arg, 1639 struct hist_browser_timer *hbt,
1587 int delay_secs) 1640 struct perf_session_env *env)
1588{ 1641{
1589 if (evlist->nr_entries == 1) { 1642 if (evlist->nr_entries == 1) {
1590 struct perf_evsel *first = list_entry(evlist->entries.next, 1643 struct perf_evsel *first = list_entry(evlist->entries.next,
1591 struct perf_evsel, node); 1644 struct perf_evsel, node);
1592 const char *ev_name = perf_evsel__name(first); 1645 const char *ev_name = perf_evsel__name(first);
1593 return perf_evsel__hists_browse(first, evlist->nr_entries, help, 1646 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1594 ev_name, false, timer, arg, 1647 ev_name, false, hbt, env);
1595 delay_secs);
1596 } 1648 }
1597 1649
1598 return __perf_evlist__tui_browse_hists(evlist, help, 1650 return __perf_evlist__tui_browse_hists(evlist, help, hbt, env);
1599 timer, arg, delay_secs);
1600} 1651}
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
new file mode 100644
index 000000000000..cbbd44b0d93e
--- /dev/null
+++ b/tools/perf/ui/browsers/scripts.c
@@ -0,0 +1,189 @@
1#include <elf.h>
2#include <newt.h>
3#include <inttypes.h>
4#include <sys/ttydefaults.h>
5#include <string.h>
6#include "../../util/sort.h"
7#include "../../util/util.h"
8#include "../../util/hist.h"
9#include "../../util/debug.h"
10#include "../../util/symbol.h"
11#include "../browser.h"
12#include "../helpline.h"
13#include "../libslang.h"
14
15/* 2048 lines should be enough for a script output */
16#define MAX_LINES 2048
17
18/* 160 bytes for one output line */
19#define AVERAGE_LINE_LEN 160
20
21struct script_line {
22 struct list_head node;
23 char line[AVERAGE_LINE_LEN];
24};
25
26struct perf_script_browser {
27 struct ui_browser b;
28 struct list_head entries;
29 const char *script_name;
30 int nr_lines;
31};
32
33#define SCRIPT_NAMELEN 128
34#define SCRIPT_MAX_NO 64
35/*
36 * Usually the full path for a script is:
37 * /home/username/libexec/perf-core/scripts/python/xxx.py
38 * /home/username/libexec/perf-core/scripts/perl/xxx.pl
39 * So 256 should be long enough to contain the full path.
40 */
41#define SCRIPT_FULLPATH_LEN 256
42
43/*
44 * When success, will copy the full path of the selected script
45 * into the buffer pointed by script_name, and return 0.
46 * Return -1 on failure.
47 */
48static int list_scripts(char *script_name)
49{
50 char *buf, *names[SCRIPT_MAX_NO], *paths[SCRIPT_MAX_NO];
51 int i, num, choice, ret = -1;
52
53 /* Preset the script name to SCRIPT_NAMELEN */
54 buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
55 if (!buf)
56 return ret;
57
58 for (i = 0; i < SCRIPT_MAX_NO; i++) {
59 names[i] = buf + i * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
60 paths[i] = names[i] + SCRIPT_NAMELEN;
61 }
62
63 num = find_scripts(names, paths);
64 if (num > 0) {
65 choice = ui__popup_menu(num, names);
66 if (choice < num && choice >= 0) {
67 strcpy(script_name, paths[choice]);
68 ret = 0;
69 }
70 }
71
72 free(buf);
73 return ret;
74}
75
76static void script_browser__write(struct ui_browser *browser,
77 void *entry, int row)
78{
79 struct script_line *sline = list_entry(entry, struct script_line, node);
80 bool current_entry = ui_browser__is_current_entry(browser, row);
81
82 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
83 HE_COLORSET_NORMAL);
84
85 slsmg_write_nstring(sline->line, browser->width);
86}
87
88static int script_browser__run(struct perf_script_browser *self)
89{
90 int key;
91
92 if (ui_browser__show(&self->b, self->script_name,
93 "Press <- or ESC to exit") < 0)
94 return -1;
95
96 while (1) {
97 key = ui_browser__run(&self->b, 0);
98
99 /* We can add some special key handling here if needed */
100 break;
101 }
102
103 ui_browser__hide(&self->b);
104 return key;
105}
106
107
108int script_browse(const char *script_opt)
109{
110 char cmd[SCRIPT_FULLPATH_LEN*2], script_name[SCRIPT_FULLPATH_LEN];
111 char *line = NULL;
112 size_t len = 0;
113 ssize_t retlen;
114 int ret = -1, nr_entries = 0;
115 FILE *fp;
116 void *buf;
117 struct script_line *sline;
118
119 struct perf_script_browser script = {
120 .b = {
121 .refresh = ui_browser__list_head_refresh,
122 .seek = ui_browser__list_head_seek,
123 .write = script_browser__write,
124 },
125 .script_name = script_name,
126 };
127
128 INIT_LIST_HEAD(&script.entries);
129
130 /* Save each line of the output in one struct script_line object. */
131 buf = zalloc((sizeof(*sline)) * MAX_LINES);
132 if (!buf)
133 return -1;
134 sline = buf;
135
136 memset(script_name, 0, SCRIPT_FULLPATH_LEN);
137 if (list_scripts(script_name))
138 goto exit;
139
140 sprintf(cmd, "perf script -s %s ", script_name);
141
142 if (script_opt)
143 strcat(cmd, script_opt);
144
145 if (input_name) {
146 strcat(cmd, " -i ");
147 strcat(cmd, input_name);
148 }
149
150 strcat(cmd, " 2>&1");
151
152 fp = popen(cmd, "r");
153 if (!fp)
154 goto exit;
155
156 while ((retlen = getline(&line, &len, fp)) != -1) {
157 strncpy(sline->line, line, AVERAGE_LINE_LEN);
158
159 /* If one output line is very large, just cut it short */
160 if (retlen >= AVERAGE_LINE_LEN) {
161 sline->line[AVERAGE_LINE_LEN - 1] = '\0';
162 sline->line[AVERAGE_LINE_LEN - 2] = '\n';
163 }
164 list_add_tail(&sline->node, &script.entries);
165
166 if (script.b.width < retlen)
167 script.b.width = retlen;
168
169 if (nr_entries++ >= MAX_LINES - 1)
170 break;
171 sline++;
172 }
173
174 if (script.b.width > AVERAGE_LINE_LEN)
175 script.b.width = AVERAGE_LINE_LEN;
176
177 if (line)
178 free(line);
179 pclose(fp);
180
181 script.nr_lines = nr_entries;
182 script.b.nr_entries = nr_entries;
183 script.b.entries = &script.entries;
184
185 ret = script_browser__run(&script);
186exit:
187 free(buf);
188 return ret;
189}
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 4125c6284114..253b6219a39e 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -237,9 +237,7 @@ static GtkWidget *perf_gtk__setup_statusbar(void)
237 237
238int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, 238int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
239 const char *help, 239 const char *help,
240 void (*timer) (void *arg)__maybe_unused, 240 struct hist_browser_timer *hbt __maybe_unused)
241 void *arg __maybe_unused,
242 int delay_secs __maybe_unused)
243{ 241{
244 struct perf_evsel *pos; 242 struct perf_evsel *pos;
245 GtkWidget *vbox; 243 GtkWidget *vbox;
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 687af0bba187..856320e2cc05 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -30,6 +30,7 @@ struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
30int perf_gtk__deactivate_context(struct perf_gtk_context **ctx); 30int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
31 31
32void perf_gtk__init_helpline(void); 32void perf_gtk__init_helpline(void);
33void perf_gtk__init_progress(void);
33void perf_gtk__init_hpp(void); 34void perf_gtk__init_hpp(void);
34 35
35#ifndef HAVE_GTK_INFO_BAR 36#ifndef HAVE_GTK_INFO_BAR
diff --git a/tools/perf/ui/gtk/progress.c b/tools/perf/ui/gtk/progress.c
new file mode 100644
index 000000000000..482bcf3df9b7
--- /dev/null
+++ b/tools/perf/ui/gtk/progress.c
@@ -0,0 +1,59 @@
1#include <inttypes.h>
2
3#include "gtk.h"
4#include "../progress.h"
5#include "util.h"
6
7static GtkWidget *dialog;
8static GtkWidget *progress;
9
10static void gtk_progress_update(u64 curr, u64 total, const char *title)
11{
12 double fraction = total ? 1.0 * curr / total : 0.0;
13 char buf[1024];
14
15 if (dialog == NULL) {
16 GtkWidget *vbox = gtk_vbox_new(TRUE, 5);
17 GtkWidget *label = gtk_label_new(title);
18
19 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
20 progress = gtk_progress_bar_new();
21
22 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, FALSE, 3);
23 gtk_box_pack_start(GTK_BOX(vbox), progress, TRUE, TRUE, 3);
24
25 gtk_container_add(GTK_CONTAINER(dialog), vbox);
26
27 gtk_window_set_title(GTK_WINDOW(dialog), "perf");
28 gtk_window_resize(GTK_WINDOW(dialog), 300, 80);
29 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
30
31 gtk_widget_show_all(dialog);
32 }
33
34 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
35 snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, curr, total);
36 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf);
37
38 /* we didn't call gtk_main yet, so do it manually */
39 while (gtk_events_pending())
40 gtk_main_iteration();
41}
42
43static void gtk_progress_finish(void)
44{
45 /* this will also destroy all of its children */
46 gtk_widget_destroy(dialog);
47
48 dialog = NULL;
49}
50
51static struct ui_progress gtk_progress_fns = {
52 .update = gtk_progress_update,
53 .finish = gtk_progress_finish,
54};
55
56void perf_gtk__init_progress(void)
57{
58 progress_fns = &gtk_progress_fns;
59}
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
index 3c4c6ef78283..6c2dd2e423f3 100644
--- a/tools/perf/ui/gtk/setup.c
+++ b/tools/perf/ui/gtk/setup.c
@@ -8,7 +8,9 @@ int perf_gtk__init(void)
8{ 8{
9 perf_error__register(&perf_gtk_eops); 9 perf_error__register(&perf_gtk_eops);
10 perf_gtk__init_helpline(); 10 perf_gtk__init_helpline();
11 perf_gtk__init_progress();
11 perf_gtk__init_hpp(); 12 perf_gtk__init_hpp();
13
12 return gtk_init_check(NULL, NULL) ? 0 : -1; 14 return gtk_init_check(NULL, NULL) ? 0 : -1;
13} 15}
14 16
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
index ccb046aac98b..c06942a41c78 100644
--- a/tools/perf/ui/gtk/util.c
+++ b/tools/perf/ui/gtk/util.c
@@ -111,14 +111,3 @@ struct perf_error_ops perf_gtk_eops = {
111 .warning = perf_gtk__warning_statusbar, 111 .warning = perf_gtk__warning_statusbar,
112#endif 112#endif
113}; 113};
114
115/*
116 * FIXME: Functions below should be implemented properly.
117 * For now, just add stubs for NO_NEWT=1 build.
118 */
119#ifndef NEWT_SUPPORT
120void ui_progress__update(u64 curr __maybe_unused, u64 total __maybe_unused,
121 const char *title __maybe_unused)
122{
123}
124#endif
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index f5a1e4f65263..aa84130024d5 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -161,7 +161,7 @@ static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
161 161
162static double baseline_percent(struct hist_entry *he) 162static double baseline_percent(struct hist_entry *he)
163{ 163{
164 struct hist_entry *pair = he->pair; 164 struct hist_entry *pair = hist_entry__next_pair(he);
165 struct hists *pair_hists = pair ? pair->hists : NULL; 165 struct hists *pair_hists = pair ? pair->hists : NULL;
166 double percent = 0.0; 166 double percent = 0.0;
167 167
@@ -179,7 +179,10 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
179{ 179{
180 double percent = baseline_percent(he); 180 double percent = baseline_percent(he);
181 181
182 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); 182 if (hist_entry__has_pairs(he))
183 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
184 else
185 return scnprintf(hpp->buf, hpp->size, " ");
183} 186}
184 187
185static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) 188static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
@@ -187,7 +190,10 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
187 double percent = baseline_percent(he); 190 double percent = baseline_percent(he);
188 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; 191 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
189 192
190 return scnprintf(hpp->buf, hpp->size, fmt, percent); 193 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
194 return scnprintf(hpp->buf, hpp->size, fmt, percent);
195 else
196 return scnprintf(hpp->buf, hpp->size, " ");
191} 197}
192 198
193static int hpp__header_samples(struct perf_hpp *hpp) 199static int hpp__header_samples(struct perf_hpp *hpp)
@@ -228,6 +234,26 @@ static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
228 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); 234 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
229} 235}
230 236
237static int hpp__header_period_baseline(struct perf_hpp *hpp)
238{
239 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
240
241 return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
242}
243
244static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
245{
246 return 12;
247}
248
249static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
250{
251 struct hist_entry *pair = hist_entry__next_pair(he);
252 u64 period = pair ? pair->stat.period : 0;
253 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
254
255 return scnprintf(hpp->buf, hpp->size, fmt, period);
256}
231static int hpp__header_delta(struct perf_hpp *hpp) 257static int hpp__header_delta(struct perf_hpp *hpp)
232{ 258{
233 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 259 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
@@ -242,30 +268,79 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
242 268
243static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) 269static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
244{ 270{
245 struct hist_entry *pair = he->pair;
246 struct hists *pair_hists = pair ? pair->hists : NULL;
247 struct hists *hists = he->hists;
248 u64 old_total, new_total;
249 double old_percent = 0, new_percent = 0;
250 double diff;
251 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; 271 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
252 char buf[32] = " "; 272 char buf[32] = " ";
273 double diff;
253 274
254 old_total = pair_hists ? pair_hists->stats.total_period : 0; 275 if (he->diff.computed)
255 if (old_total > 0 && pair) 276 diff = he->diff.period_ratio_delta;
256 old_percent = 100.0 * pair->stat.period / old_total; 277 else
257 278 diff = perf_diff__compute_delta(he);
258 new_total = hists->stats.total_period;
259 if (new_total > 0)
260 new_percent = 100.0 * he->stat.period / new_total;
261 279
262 diff = new_percent - old_percent;
263 if (fabs(diff) >= 0.01) 280 if (fabs(diff) >= 0.01)
264 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); 281 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
265 282
266 return scnprintf(hpp->buf, hpp->size, fmt, buf); 283 return scnprintf(hpp->buf, hpp->size, fmt, buf);
267} 284}
268 285
286static int hpp__header_ratio(struct perf_hpp *hpp)
287{
288 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
289
290 return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
291}
292
293static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
294{
295 return 14;
296}
297
298static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
299{
300 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
301 char buf[32] = " ";
302 double ratio;
303
304 if (he->diff.computed)
305 ratio = he->diff.period_ratio;
306 else
307 ratio = perf_diff__compute_ratio(he);
308
309 if (ratio > 0.0)
310 scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
311
312 return scnprintf(hpp->buf, hpp->size, fmt, buf);
313}
314
315static int hpp__header_wdiff(struct perf_hpp *hpp)
316{
317 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
318
319 return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
320}
321
322static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
323{
324 return 14;
325}
326
327static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
328{
329 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
330 char buf[32] = " ";
331 s64 wdiff;
332
333 if (he->diff.computed)
334 wdiff = he->diff.wdiff;
335 else
336 wdiff = perf_diff__compute_wdiff(he);
337
338 if (wdiff != 0)
339 scnprintf(buf, sizeof(buf), "%14ld", wdiff);
340
341 return scnprintf(hpp->buf, hpp->size, fmt, buf);
342}
343
269static int hpp__header_displ(struct perf_hpp *hpp) 344static int hpp__header_displ(struct perf_hpp *hpp)
270{ 345{
271 return scnprintf(hpp->buf, hpp->size, "Displ."); 346 return scnprintf(hpp->buf, hpp->size, "Displ.");
@@ -279,7 +354,7 @@ static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
279static int hpp__entry_displ(struct perf_hpp *hpp, 354static int hpp__entry_displ(struct perf_hpp *hpp,
280 struct hist_entry *he) 355 struct hist_entry *he)
281{ 356{
282 struct hist_entry *pair = he->pair; 357 struct hist_entry *pair = hist_entry__next_pair(he);
283 long displacement = pair ? pair->position - he->position : 0; 358 long displacement = pair ? pair->position - he->position : 0;
284 const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; 359 const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
285 char buf[32] = " "; 360 char buf[32] = " ";
@@ -290,6 +365,27 @@ static int hpp__entry_displ(struct perf_hpp *hpp,
290 return scnprintf(hpp->buf, hpp->size, fmt, buf); 365 return scnprintf(hpp->buf, hpp->size, fmt, buf);
291} 366}
292 367
368static int hpp__header_formula(struct perf_hpp *hpp)
369{
370 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
371
372 return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
373}
374
375static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
376{
377 return 70;
378}
379
380static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
381{
382 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
383 char buf[96] = " ";
384
385 perf_diff__formula(buf, sizeof(buf), he);
386 return scnprintf(hpp->buf, hpp->size, fmt, buf);
387}
388
293#define HPP__COLOR_PRINT_FNS(_name) \ 389#define HPP__COLOR_PRINT_FNS(_name) \
294 .header = hpp__header_ ## _name, \ 390 .header = hpp__header_ ## _name, \
295 .width = hpp__width_ ## _name, \ 391 .width = hpp__width_ ## _name, \
@@ -310,8 +406,12 @@ struct perf_hpp_fmt perf_hpp__format[] = {
310 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, 406 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) },
311 { .cond = false, HPP__PRINT_FNS(samples) }, 407 { .cond = false, HPP__PRINT_FNS(samples) },
312 { .cond = false, HPP__PRINT_FNS(period) }, 408 { .cond = false, HPP__PRINT_FNS(period) },
409 { .cond = false, HPP__PRINT_FNS(period_baseline) },
313 { .cond = false, HPP__PRINT_FNS(delta) }, 410 { .cond = false, HPP__PRINT_FNS(delta) },
314 { .cond = false, HPP__PRINT_FNS(displ) } 411 { .cond = false, HPP__PRINT_FNS(ratio) },
412 { .cond = false, HPP__PRINT_FNS(wdiff) },
413 { .cond = false, HPP__PRINT_FNS(displ) },
414 { .cond = false, HPP__PRINT_FNS(formula) }
315}; 415};
316 416
317#undef HPP__COLOR_PRINT_FNS 417#undef HPP__COLOR_PRINT_FNS
diff --git a/tools/perf/ui/progress.c b/tools/perf/ui/progress.c
index 13aa64e50e11..3ec695607a4d 100644
--- a/tools/perf/ui/progress.c
+++ b/tools/perf/ui/progress.c
@@ -1,32 +1,26 @@
1#include "../cache.h" 1#include "../cache.h"
2#include "progress.h" 2#include "progress.h"
3#include "libslang.h"
4#include "ui.h"
5#include "browser.h"
6 3
7void ui_progress__update(u64 curr, u64 total, const char *title) 4static void nop_progress_update(u64 curr __maybe_unused,
5 u64 total __maybe_unused,
6 const char *title __maybe_unused)
8{ 7{
9 int bar, y; 8}
10 /*
11 * FIXME: We should have a per UI backend way of showing progress,
12 * stdio will just show a percentage as NN%, etc.
13 */
14 if (use_browser <= 0)
15 return;
16 9
17 if (total == 0) 10static struct ui_progress default_progress_fns =
18 return; 11{
12 .update = nop_progress_update,
13};
19 14
20 ui__refresh_dimensions(true); 15struct ui_progress *progress_fns = &default_progress_fns;
21 pthread_mutex_lock(&ui__lock); 16
22 y = SLtt_Screen_Rows / 2 - 2; 17void ui_progress__update(u64 curr, u64 total, const char *title)
23 SLsmg_set_color(0); 18{
24 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols); 19 return progress_fns->update(curr, total, title);
25 SLsmg_gotorc(y++, 1); 20}
26 SLsmg_write_string((char *)title); 21
27 SLsmg_set_color(HE_COLORSET_SELECTED); 22void ui_progress__finish(void)
28 bar = ((SLtt_Screen_Cols - 2) * curr) / total; 23{
29 SLsmg_fill_region(y, 1, 1, bar, ' '); 24 if (progress_fns->finish)
30 SLsmg_refresh(); 25 progress_fns->finish();
31 pthread_mutex_unlock(&ui__lock);
32} 26}
diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h
index d9c205b59aa1..257cc224f9cf 100644
--- a/tools/perf/ui/progress.h
+++ b/tools/perf/ui/progress.h
@@ -3,6 +3,16 @@
3 3
4#include <../types.h> 4#include <../types.h>
5 5
6struct ui_progress {
7 void (*update)(u64, u64, const char *);
8 void (*finish)(void);
9};
10
11extern struct ui_progress *progress_fns;
12
13void ui_progress__init(void);
14
6void ui_progress__update(u64 curr, u64 total, const char *title); 15void ui_progress__update(u64 curr, u64 total, const char *title);
16void ui_progress__finish(void);
7 17
8#endif 18#endif
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index fbd4e32d0743..f0ee204f99bb 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -342,7 +342,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
342 const char *sep = symbol_conf.field_sep; 342 const char *sep = symbol_conf.field_sep;
343 const char *col_width = symbol_conf.col_width_list_str; 343 const char *col_width = symbol_conf.col_width_list_str;
344 int idx, nr_rows = 0; 344 int idx, nr_rows = 0;
345 char bf[64]; 345 char bf[96];
346 struct perf_hpp dummy_hpp = { 346 struct perf_hpp dummy_hpp = {
347 .buf = bf, 347 .buf = bf,
348 .size = sizeof(bf), 348 .size = sizeof(bf),
diff --git a/tools/perf/ui/tui/progress.c b/tools/perf/ui/tui/progress.c
new file mode 100644
index 000000000000..6c2184d53cbf
--- /dev/null
+++ b/tools/perf/ui/tui/progress.c
@@ -0,0 +1,42 @@
1#include "../cache.h"
2#include "../progress.h"
3#include "../libslang.h"
4#include "../ui.h"
5#include "../browser.h"
6
7static void tui_progress__update(u64 curr, u64 total, const char *title)
8{
9 int bar, y;
10 /*
11 * FIXME: We should have a per UI backend way of showing progress,
12 * stdio will just show a percentage as NN%, etc.
13 */
14 if (use_browser <= 0)
15 return;
16
17 if (total == 0)
18 return;
19
20 ui__refresh_dimensions(true);
21 pthread_mutex_lock(&ui__lock);
22 y = SLtt_Screen_Rows / 2 - 2;
23 SLsmg_set_color(0);
24 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
25 SLsmg_gotorc(y++, 1);
26 SLsmg_write_string((char *)title);
27 SLsmg_set_color(HE_COLORSET_SELECTED);
28 bar = ((SLtt_Screen_Cols - 2) * curr) / total;
29 SLsmg_fill_region(y, 1, 1, bar, ' ');
30 SLsmg_refresh();
31 pthread_mutex_unlock(&ui__lock);
32}
33
34static struct ui_progress tui_progress_fns =
35{
36 .update = tui_progress__update,
37};
38
39void ui_progress__init(void)
40{
41 progress_fns = &tui_progress_fns;
42}
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index 60debb81537a..81efa192e86c 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -118,6 +118,7 @@ int ui__init(void)
118 newtSetSuspendCallback(newt_suspend, NULL); 118 newtSetSuspendCallback(newt_suspend, NULL);
119 ui_helpline__init(); 119 ui_helpline__init();
120 ui_browser__init(); 120 ui_browser__init();
121 ui_progress__init();
121 122
122 signal(SIGSEGV, ui__signal); 123 signal(SIGSEGV, ui__signal);
123 signal(SIGFPE, ui__signal); 124 signal(SIGFPE, ui__signal);
diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h
index 7b67045479f6..d86359c99907 100644
--- a/tools/perf/ui/ui.h
+++ b/tools/perf/ui/ui.h
@@ -3,9 +3,37 @@
3 3
4#include <pthread.h> 4#include <pthread.h>
5#include <stdbool.h> 5#include <stdbool.h>
6#include <linux/compiler.h>
6 7
7extern pthread_mutex_t ui__lock; 8extern pthread_mutex_t ui__lock;
8 9
10extern int use_browser;
11
12void setup_browser(bool fallback_to_pager);
13void exit_browser(bool wait_for_ok);
14
15#ifdef NEWT_SUPPORT
16int ui__init(void);
17void ui__exit(bool wait_for_ok);
18#else
19static inline int ui__init(void)
20{
21 return -1;
22}
23static inline void ui__exit(bool wait_for_ok __maybe_unused) {}
24#endif
25
26#ifdef GTK2_SUPPORT
27int perf_gtk__init(void);
28void perf_gtk__exit(bool wait_for_ok);
29#else
30static inline int perf_gtk__init(void)
31{
32 return -1;
33}
34static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {}
35#endif
36
9void ui__refresh_dimensions(bool force); 37void ui__refresh_dimensions(bool force);
10 38
11#endif /* _PERF_UI_H_ */ 39#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 95264f304179..6aa34e5afdcf 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -9,18 +9,14 @@ GVF=${OUTPUT}PERF-VERSION-FILE
9LF=' 9LF='
10' 10'
11 11
12#
12# First check if there is a .git to get the version from git describe 13# First check if there is a .git to get the version from git describe
13# otherwise try to get the version from the kernel makefile 14# otherwise try to get the version from the kernel Makefile
15#
14if test -d ../../.git -o -f ../../.git && 16if test -d ../../.git -o -f ../../.git &&
15 VN=$(git describe --match 'v[0-9].[0-9]*' --abbrev=4 HEAD 2>/dev/null) && 17 VN=$(git tag 2>/dev/null | tail -1 | grep -E "v[0-9].[0-9]*")
16 case "$VN" in
17 *$LF*) (exit 1) ;;
18 v[0-9]*)
19 git update-index -q --refresh
20 test -z "$(git diff-index --name-only HEAD --)" ||
21 VN="$VN-dirty" ;;
22 esac
23then 18then
19 VN=$(echo $VN"-g"$(git log -1 --abbrev=4 --pretty=format:"%h" HEAD))
24 VN=$(echo "$VN" | sed -e 's/-/./g'); 20 VN=$(echo "$VN" | sed -e 's/-/./g');
25else 21else
26 VN=$(MAKEFLAGS= make -sC ../.. kernelversion) 22 VN=$(MAKEFLAGS= make -sC ../.. kernelversion)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index f0a910371377..07aaeea60000 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -15,6 +15,7 @@
15#include "debug.h" 15#include "debug.h"
16#include "annotate.h" 16#include "annotate.h"
17#include <pthread.h> 17#include <pthread.h>
18#include <linux/bitops.h>
18 19
19const char *disassembler_style; 20const char *disassembler_style;
20const char *objdump_path; 21const char *objdump_path;
@@ -170,15 +171,15 @@ static int lock__parse(struct ins_operands *ops)
170 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) 171 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
171 goto out_free_ops; 172 goto out_free_ops;
172 173
173 ops->locked.ins = ins__find(name); 174 ops->locked.ins = ins__find(name);
174 if (ops->locked.ins == NULL) 175 if (ops->locked.ins == NULL)
175 goto out_free_ops; 176 goto out_free_ops;
176 177
177 if (!ops->locked.ins->ops) 178 if (!ops->locked.ins->ops)
178 return 0; 179 return 0;
179 180
180 if (ops->locked.ins->ops->parse) 181 if (ops->locked.ins->ops->parse)
181 ops->locked.ins->ops->parse(ops->locked.ops); 182 ops->locked.ins->ops->parse(ops->locked.ops);
182 183
183 return 0; 184 return 0;
184 185
@@ -400,6 +401,8 @@ static struct ins instructions[] = {
400 { .name = "testb", .ops = &mov_ops, }, 401 { .name = "testb", .ops = &mov_ops, },
401 { .name = "testl", .ops = &mov_ops, }, 402 { .name = "testl", .ops = &mov_ops, },
402 { .name = "xadd", .ops = &mov_ops, }, 403 { .name = "xadd", .ops = &mov_ops, },
404 { .name = "xbeginl", .ops = &jump_ops, },
405 { .name = "xbeginq", .ops = &jump_ops, },
403}; 406};
404 407
405static int ins__cmp(const void *name, const void *insp) 408static int ins__cmp(const void *name, const void *insp)
@@ -855,21 +858,68 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
855 struct source_line *iter; 858 struct source_line *iter;
856 struct rb_node **p = &root->rb_node; 859 struct rb_node **p = &root->rb_node;
857 struct rb_node *parent = NULL; 860 struct rb_node *parent = NULL;
861 int ret;
858 862
859 while (*p != NULL) { 863 while (*p != NULL) {
860 parent = *p; 864 parent = *p;
861 iter = rb_entry(parent, struct source_line, node); 865 iter = rb_entry(parent, struct source_line, node);
862 866
863 if (src_line->percent > iter->percent) 867 ret = strcmp(iter->path, src_line->path);
868 if (ret == 0) {
869 iter->percent_sum += src_line->percent;
870 return;
871 }
872
873 if (ret < 0)
864 p = &(*p)->rb_left; 874 p = &(*p)->rb_left;
865 else 875 else
866 p = &(*p)->rb_right; 876 p = &(*p)->rb_right;
867 } 877 }
868 878
879 src_line->percent_sum = src_line->percent;
880
869 rb_link_node(&src_line->node, parent, p); 881 rb_link_node(&src_line->node, parent, p);
870 rb_insert_color(&src_line->node, root); 882 rb_insert_color(&src_line->node, root);
871} 883}
872 884
885static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
886{
887 struct source_line *iter;
888 struct rb_node **p = &root->rb_node;
889 struct rb_node *parent = NULL;
890
891 while (*p != NULL) {
892 parent = *p;
893 iter = rb_entry(parent, struct source_line, node);
894
895 if (src_line->percent_sum > iter->percent_sum)
896 p = &(*p)->rb_left;
897 else
898 p = &(*p)->rb_right;
899 }
900
901 rb_link_node(&src_line->node, parent, p);
902 rb_insert_color(&src_line->node, root);
903}
904
905static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
906{
907 struct source_line *src_line;
908 struct rb_node *node;
909
910 node = rb_first(src_root);
911 while (node) {
912 struct rb_node *next;
913
914 src_line = rb_entry(node, struct source_line, node);
915 next = rb_next(node);
916 rb_erase(node, src_root);
917
918 __resort_source_line(dest_root, src_line);
919 node = next;
920 }
921}
922
873static void symbol__free_source_line(struct symbol *sym, int len) 923static void symbol__free_source_line(struct symbol *sym, int len)
874{ 924{
875 struct annotation *notes = symbol__annotation(sym); 925 struct annotation *notes = symbol__annotation(sym);
@@ -894,6 +944,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
894 struct source_line *src_line; 944 struct source_line *src_line;
895 struct annotation *notes = symbol__annotation(sym); 945 struct annotation *notes = symbol__annotation(sym);
896 struct sym_hist *h = annotation__histogram(notes, evidx); 946 struct sym_hist *h = annotation__histogram(notes, evidx);
947 struct rb_root tmp_root = RB_ROOT;
897 948
898 if (!h->sum) 949 if (!h->sum)
899 return 0; 950 return 0;
@@ -928,12 +979,13 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
928 goto next; 979 goto next;
929 980
930 strcpy(src_line[i].path, path); 981 strcpy(src_line[i].path, path);
931 insert_source_line(root, &src_line[i]); 982 insert_source_line(&tmp_root, &src_line[i]);
932 983
933 next: 984 next:
934 pclose(fp); 985 pclose(fp);
935 } 986 }
936 987
988 resort_source_line(root, &tmp_root);
937 return 0; 989 return 0;
938} 990}
939 991
@@ -957,7 +1009,7 @@ static void print_summary(struct rb_root *root, const char *filename)
957 char *path; 1009 char *path;
958 1010
959 src_line = rb_entry(node, struct source_line, node); 1011 src_line = rb_entry(node, struct source_line, node);
960 percent = src_line->percent; 1012 percent = src_line->percent_sum;
961 color = get_percent_color(percent); 1013 color = get_percent_color(percent);
962 path = src_line->path; 1014 path = src_line->path;
963 1015
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 39242dcee8f2..8eec94358a4a 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -5,6 +5,7 @@
5#include <stdint.h> 5#include <stdint.h>
6#include "types.h" 6#include "types.h"
7#include "symbol.h" 7#include "symbol.h"
8#include "hist.h"
8#include <linux/list.h> 9#include <linux/list.h>
9#include <linux/rbtree.h> 10#include <linux/rbtree.h>
10#include <pthread.h> 11#include <pthread.h>
@@ -75,6 +76,7 @@ struct sym_hist {
75struct source_line { 76struct source_line {
76 struct rb_node node; 77 struct rb_node node;
77 double percent; 78 double percent;
79 double percent_sum;
78 char *path; 80 char *path;
79}; 81};
80 82
@@ -140,20 +142,18 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
140 142
141#ifdef NEWT_SUPPORT 143#ifdef NEWT_SUPPORT
142int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 144int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
143 void(*timer)(void *arg), void *arg, int delay_secs); 145 struct hist_browser_timer *hbt);
144#else 146#else
145static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, 147static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
146 struct map *map __maybe_unused, 148 struct map *map __maybe_unused,
147 int evidx __maybe_unused, 149 int evidx __maybe_unused,
148 void(*timer)(void *arg) __maybe_unused, 150 struct hist_browser_timer *hbt
149 void *arg __maybe_unused, 151 __maybe_unused)
150 int delay_secs __maybe_unused)
151{ 152{
152 return 0; 153 return 0;
153} 154}
154#endif 155#endif
155 156
156extern const char *disassembler_style; 157extern const char *disassembler_style;
157extern const char *objdump_path;
158 158
159#endif /* __PERF_ANNOTATE_H */ 159#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 8e3a740ddbd4..5295625c0c00 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -16,11 +16,11 @@
16#include "session.h" 16#include "session.h"
17#include "tool.h" 17#include "tool.h"
18 18
19static int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
20 union perf_event *event, 20 union perf_event *event,
21 struct perf_sample *sample __maybe_unused, 21 struct perf_sample *sample __maybe_unused,
22 struct perf_evsel *evsel __maybe_unused, 22 struct perf_evsel *evsel __maybe_unused,
23 struct machine *machine) 23 struct machine *machine)
24{ 24{
25 struct addr_location al; 25 struct addr_location al;
26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
@@ -64,12 +64,27 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
64struct perf_tool build_id__mark_dso_hit_ops = { 64struct perf_tool build_id__mark_dso_hit_ops = {
65 .sample = build_id__mark_dso_hit, 65 .sample = build_id__mark_dso_hit,
66 .mmap = perf_event__process_mmap, 66 .mmap = perf_event__process_mmap,
67 .fork = perf_event__process_task, 67 .fork = perf_event__process_fork,
68 .exit = perf_event__exit_del_thread, 68 .exit = perf_event__exit_del_thread,
69 .attr = perf_event__process_attr, 69 .attr = perf_event__process_attr,
70 .build_id = perf_event__process_build_id, 70 .build_id = perf_event__process_build_id,
71}; 71};
72 72
73int build_id__sprintf(const u8 *build_id, int len, char *bf)
74{
75 char *bid = bf;
76 const u8 *raw = build_id;
77 int i;
78
79 for (i = 0; i < len; ++i) {
80 sprintf(bid, "%02x", *raw);
81 ++raw;
82 bid += 2;
83 }
84
85 return raw - build_id;
86}
87
73char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 88char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
74{ 89{
75 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 90 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index a993ba87d996..a811f5c62e18 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -1,10 +1,19 @@
1#ifndef PERF_BUILD_ID_H_ 1#ifndef PERF_BUILD_ID_H_
2#define PERF_BUILD_ID_H_ 1 2#define PERF_BUILD_ID_H_ 1
3 3
4#include "session.h" 4#define BUILD_ID_SIZE 20
5
6#include "tool.h"
7#include "types.h"
5 8
6extern struct perf_tool build_id__mark_dso_hit_ops; 9extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso;
7 11
12int build_id__sprintf(const u8 *build_id, int len, char *bf);
8char *dso__build_id_filename(struct dso *self, char *bf, size_t size); 13char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
9 14
15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
16 struct perf_sample *sample, struct perf_evsel *evsel,
17 struct machine *machine);
18
10#endif 19#endif
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 2bd51370ad28..26e367239873 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -5,6 +5,7 @@
5#include "util.h" 5#include "util.h"
6#include "strbuf.h" 6#include "strbuf.h"
7#include "../perf.h" 7#include "../perf.h"
8#include "../ui/ui.h"
8 9
9#define CMD_EXEC_PATH "--exec-path" 10#define CMD_EXEC_PATH "--exec-path"
10#define CMD_PERF_DIR "--perf-dir=" 11#define CMD_PERF_DIR "--perf-dir="
@@ -31,44 +32,6 @@ extern const char *pager_program;
31extern int pager_in_use(void); 32extern int pager_in_use(void);
32extern int pager_use_color; 33extern int pager_use_color;
33 34
34extern int use_browser;
35
36#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT)
37void setup_browser(bool fallback_to_pager);
38void exit_browser(bool wait_for_ok);
39
40#ifdef NEWT_SUPPORT
41int ui__init(void);
42void ui__exit(bool wait_for_ok);
43#else
44static inline int ui__init(void)
45{
46 return -1;
47}
48static inline void ui__exit(bool wait_for_ok __maybe_unused) {}
49#endif
50
51#ifdef GTK2_SUPPORT
52int perf_gtk__init(void);
53void perf_gtk__exit(bool wait_for_ok);
54#else
55static inline int perf_gtk__init(void)
56{
57 return -1;
58}
59static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {}
60#endif
61
62#else /* NEWT_SUPPORT || GTK2_SUPPORT */
63
64static inline void setup_browser(bool fallback_to_pager)
65{
66 if (fallback_to_pager)
67 setup_pager();
68}
69static inline void exit_browser(bool wait_for_ok __maybe_unused) {}
70#endif /* NEWT_SUPPORT || GTK2_SUPPORT */
71
72char *alias_lookup(const char *alias); 35char *alias_lookup(const char *alias);
73int split_cmdline(char *cmdline, const char ***argv); 36int split_cmdline(char *cmdline, const char ***argv);
74 37
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index dec98750b484..83e8d234af6b 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -26,6 +26,7 @@ int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
26static inline void ui_progress__update(u64 curr __maybe_unused, 26static inline void ui_progress__update(u64 curr __maybe_unused,
27 u64 total __maybe_unused, 27 u64 total __maybe_unused,
28 const char *title __maybe_unused) {} 28 const char *title __maybe_unused) {}
29static inline void ui_progress__finish(void) {}
29 30
30#define ui__error(format, arg...) ui__warning(format, ##arg) 31#define ui__error(format, arg...) ui__warning(format, ##arg)
31 32
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
new file mode 100644
index 000000000000..d6d9a465acdb
--- /dev/null
+++ b/tools/perf/util/dso.c
@@ -0,0 +1,595 @@
1#include "symbol.h"
2#include "dso.h"
3#include "machine.h"
4#include "util.h"
5#include "debug.h"
6
7char dso__symtab_origin(const struct dso *dso)
8{
9 static const char origin[] = {
10 [DSO_BINARY_TYPE__KALLSYMS] = 'k',
11 [DSO_BINARY_TYPE__VMLINUX] = 'v',
12 [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
13 [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
14 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
15 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
16 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
17 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
18 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
19 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
20 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
21 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
22 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
23 };
24
25 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
26 return '!';
27 return origin[dso->symtab_type];
28}
29
30int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
31 char *root_dir, char *file, size_t size)
32{
33 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
34 int ret = 0;
35
36 switch (type) {
37 case DSO_BINARY_TYPE__DEBUGLINK: {
38 char *debuglink;
39
40 strncpy(file, dso->long_name, size);
41 debuglink = file + dso->long_name_len;
42 while (debuglink != file && *debuglink != '/')
43 debuglink--;
44 if (*debuglink == '/')
45 debuglink++;
46 filename__read_debuglink(dso->long_name, debuglink,
47 size - (debuglink - file));
48 }
49 break;
50 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
51 /* skip the locally configured cache if a symfs is given */
52 if (symbol_conf.symfs[0] ||
53 (dso__build_id_filename(dso, file, size) == NULL))
54 ret = -1;
55 break;
56
57 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
58 snprintf(file, size, "%s/usr/lib/debug%s.debug",
59 symbol_conf.symfs, dso->long_name);
60 break;
61
62 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
63 snprintf(file, size, "%s/usr/lib/debug%s",
64 symbol_conf.symfs, dso->long_name);
65 break;
66
67 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
68 if (!dso->has_build_id) {
69 ret = -1;
70 break;
71 }
72
73 build_id__sprintf(dso->build_id,
74 sizeof(dso->build_id),
75 build_id_hex);
76 snprintf(file, size,
77 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
78 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
79 break;
80
81 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
82 snprintf(file, size, "%s%s",
83 symbol_conf.symfs, dso->long_name);
84 break;
85
86 case DSO_BINARY_TYPE__GUEST_KMODULE:
87 snprintf(file, size, "%s%s%s", symbol_conf.symfs,
88 root_dir, dso->long_name);
89 break;
90
91 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
92 snprintf(file, size, "%s%s", symbol_conf.symfs,
93 dso->long_name);
94 break;
95
96 default:
97 case DSO_BINARY_TYPE__KALLSYMS:
98 case DSO_BINARY_TYPE__VMLINUX:
99 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
100 case DSO_BINARY_TYPE__GUEST_VMLINUX:
101 case DSO_BINARY_TYPE__JAVA_JIT:
102 case DSO_BINARY_TYPE__NOT_FOUND:
103 ret = -1;
104 break;
105 }
106
107 return ret;
108}
109
110static int open_dso(struct dso *dso, struct machine *machine)
111{
112 char *root_dir = (char *) "";
113 char *name;
114 int fd;
115
116 name = malloc(PATH_MAX);
117 if (!name)
118 return -ENOMEM;
119
120 if (machine)
121 root_dir = machine->root_dir;
122
123 if (dso__binary_type_file(dso, dso->data_type,
124 root_dir, name, PATH_MAX)) {
125 free(name);
126 return -EINVAL;
127 }
128
129 fd = open(name, O_RDONLY);
130 free(name);
131 return fd;
132}
133
134int dso__data_fd(struct dso *dso, struct machine *machine)
135{
136 static enum dso_binary_type binary_type_data[] = {
137 DSO_BINARY_TYPE__BUILD_ID_CACHE,
138 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
139 DSO_BINARY_TYPE__NOT_FOUND,
140 };
141 int i = 0;
142
143 if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
144 return open_dso(dso, machine);
145
146 do {
147 int fd;
148
149 dso->data_type = binary_type_data[i++];
150
151 fd = open_dso(dso, machine);
152 if (fd >= 0)
153 return fd;
154
155 } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
156
157 return -EINVAL;
158}
159
160static void
161dso_cache__free(struct rb_root *root)
162{
163 struct rb_node *next = rb_first(root);
164
165 while (next) {
166 struct dso_cache *cache;
167
168 cache = rb_entry(next, struct dso_cache, rb_node);
169 next = rb_next(&cache->rb_node);
170 rb_erase(&cache->rb_node, root);
171 free(cache);
172 }
173}
174
175static struct dso_cache*
176dso_cache__find(struct rb_root *root, u64 offset)
177{
178 struct rb_node **p = &root->rb_node;
179 struct rb_node *parent = NULL;
180 struct dso_cache *cache;
181
182 while (*p != NULL) {
183 u64 end;
184
185 parent = *p;
186 cache = rb_entry(parent, struct dso_cache, rb_node);
187 end = cache->offset + DSO__DATA_CACHE_SIZE;
188
189 if (offset < cache->offset)
190 p = &(*p)->rb_left;
191 else if (offset >= end)
192 p = &(*p)->rb_right;
193 else
194 return cache;
195 }
196 return NULL;
197}
198
199static void
200dso_cache__insert(struct rb_root *root, struct dso_cache *new)
201{
202 struct rb_node **p = &root->rb_node;
203 struct rb_node *parent = NULL;
204 struct dso_cache *cache;
205 u64 offset = new->offset;
206
207 while (*p != NULL) {
208 u64 end;
209
210 parent = *p;
211 cache = rb_entry(parent, struct dso_cache, rb_node);
212 end = cache->offset + DSO__DATA_CACHE_SIZE;
213
214 if (offset < cache->offset)
215 p = &(*p)->rb_left;
216 else if (offset >= end)
217 p = &(*p)->rb_right;
218 }
219
220 rb_link_node(&new->rb_node, parent, p);
221 rb_insert_color(&new->rb_node, root);
222}
223
224static ssize_t
225dso_cache__memcpy(struct dso_cache *cache, u64 offset,
226 u8 *data, u64 size)
227{
228 u64 cache_offset = offset - cache->offset;
229 u64 cache_size = min(cache->size - cache_offset, size);
230
231 memcpy(data, cache->data + cache_offset, cache_size);
232 return cache_size;
233}
234
235static ssize_t
236dso_cache__read(struct dso *dso, struct machine *machine,
237 u64 offset, u8 *data, ssize_t size)
238{
239 struct dso_cache *cache;
240 ssize_t ret;
241 int fd;
242
243 fd = dso__data_fd(dso, machine);
244 if (fd < 0)
245 return -1;
246
247 do {
248 u64 cache_offset;
249
250 ret = -ENOMEM;
251
252 cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
253 if (!cache)
254 break;
255
256 cache_offset = offset & DSO__DATA_CACHE_MASK;
257 ret = -EINVAL;
258
259 if (-1 == lseek(fd, cache_offset, SEEK_SET))
260 break;
261
262 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
263 if (ret <= 0)
264 break;
265
266 cache->offset = cache_offset;
267 cache->size = ret;
268 dso_cache__insert(&dso->cache, cache);
269
270 ret = dso_cache__memcpy(cache, offset, data, size);
271
272 } while (0);
273
274 if (ret <= 0)
275 free(cache);
276
277 close(fd);
278 return ret;
279}
280
281static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
282 u64 offset, u8 *data, ssize_t size)
283{
284 struct dso_cache *cache;
285
286 cache = dso_cache__find(&dso->cache, offset);
287 if (cache)
288 return dso_cache__memcpy(cache, offset, data, size);
289 else
290 return dso_cache__read(dso, machine, offset, data, size);
291}
292
293ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
294 u64 offset, u8 *data, ssize_t size)
295{
296 ssize_t r = 0;
297 u8 *p = data;
298
299 do {
300 ssize_t ret;
301
302 ret = dso_cache_read(dso, machine, offset, p, size);
303 if (ret < 0)
304 return ret;
305
306 /* Reached EOF, return what we have. */
307 if (!ret)
308 break;
309
310 BUG_ON(ret > size);
311
312 r += ret;
313 p += ret;
314 offset += ret;
315 size -= ret;
316
317 } while (size);
318
319 return r;
320}
321
322ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
323 struct machine *machine, u64 addr,
324 u8 *data, ssize_t size)
325{
326 u64 offset = map->map_ip(map, addr);
327 return dso__data_read_offset(dso, machine, offset, data, size);
328}
329
330struct map *dso__new_map(const char *name)
331{
332 struct map *map = NULL;
333 struct dso *dso = dso__new(name);
334
335 if (dso)
336 map = map__new2(0, dso, MAP__FUNCTION);
337
338 return map;
339}
340
341struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
342 const char *short_name, int dso_type)
343{
344 /*
345 * The kernel dso could be created by build_id processing.
346 */
347 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
348
349 /*
350 * We need to run this in all cases, since during the build_id
351 * processing we had no idea this was the kernel dso.
352 */
353 if (dso != NULL) {
354 dso__set_short_name(dso, short_name);
355 dso->kernel = dso_type;
356 }
357
358 return dso;
359}
360
361void dso__set_long_name(struct dso *dso, char *name)
362{
363 if (name == NULL)
364 return;
365 dso->long_name = name;
366 dso->long_name_len = strlen(name);
367}
368
369void dso__set_short_name(struct dso *dso, const char *name)
370{
371 if (name == NULL)
372 return;
373 dso->short_name = name;
374 dso->short_name_len = strlen(name);
375}
376
377static void dso__set_basename(struct dso *dso)
378{
379 dso__set_short_name(dso, basename(dso->long_name));
380}
381
382int dso__name_len(const struct dso *dso)
383{
384 if (!dso)
385 return strlen("[unknown]");
386 if (verbose)
387 return dso->long_name_len;
388
389 return dso->short_name_len;
390}
391
392bool dso__loaded(const struct dso *dso, enum map_type type)
393{
394 return dso->loaded & (1 << type);
395}
396
397bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
398{
399 return dso->sorted_by_name & (1 << type);
400}
401
402void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
403{
404 dso->sorted_by_name |= (1 << type);
405}
406
407struct dso *dso__new(const char *name)
408{
409 struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
410
411 if (dso != NULL) {
412 int i;
413 strcpy(dso->name, name);
414 dso__set_long_name(dso, dso->name);
415 dso__set_short_name(dso, dso->name);
416 for (i = 0; i < MAP__NR_TYPES; ++i)
417 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
418 dso->cache = RB_ROOT;
419 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
420 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
421 dso->loaded = 0;
422 dso->sorted_by_name = 0;
423 dso->has_build_id = 0;
424 dso->kernel = DSO_TYPE_USER;
425 dso->needs_swap = DSO_SWAP__UNSET;
426 INIT_LIST_HEAD(&dso->node);
427 }
428
429 return dso;
430}
431
432void dso__delete(struct dso *dso)
433{
434 int i;
435 for (i = 0; i < MAP__NR_TYPES; ++i)
436 symbols__delete(&dso->symbols[i]);
437 if (dso->sname_alloc)
438 free((char *)dso->short_name);
439 if (dso->lname_alloc)
440 free(dso->long_name);
441 dso_cache__free(&dso->cache);
442 free(dso);
443}
444
445void dso__set_build_id(struct dso *dso, void *build_id)
446{
447 memcpy(dso->build_id, build_id, sizeof(dso->build_id));
448 dso->has_build_id = 1;
449}
450
451bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
452{
453 return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
454}
455
456void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
457{
458 char path[PATH_MAX];
459
460 if (machine__is_default_guest(machine))
461 return;
462 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
463 if (sysfs__read_build_id(path, dso->build_id,
464 sizeof(dso->build_id)) == 0)
465 dso->has_build_id = true;
466}
467
468int dso__kernel_module_get_build_id(struct dso *dso,
469 const char *root_dir)
470{
471 char filename[PATH_MAX];
472 /*
473 * kernel module short names are of the form "[module]" and
474 * we need just "module" here.
475 */
476 const char *name = dso->short_name + 1;
477
478 snprintf(filename, sizeof(filename),
479 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
480 root_dir, (int)strlen(name) - 1, name);
481
482 if (sysfs__read_build_id(filename, dso->build_id,
483 sizeof(dso->build_id)) == 0)
484 dso->has_build_id = true;
485
486 return 0;
487}
488
489bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
490{
491 bool have_build_id = false;
492 struct dso *pos;
493
494 list_for_each_entry(pos, head, node) {
495 if (with_hits && !pos->hit)
496 continue;
497 if (pos->has_build_id) {
498 have_build_id = true;
499 continue;
500 }
501 if (filename__read_build_id(pos->long_name, pos->build_id,
502 sizeof(pos->build_id)) > 0) {
503 have_build_id = true;
504 pos->has_build_id = true;
505 }
506 }
507
508 return have_build_id;
509}
510
511void dsos__add(struct list_head *head, struct dso *dso)
512{
513 list_add_tail(&dso->node, head);
514}
515
516struct dso *dsos__find(struct list_head *head, const char *name)
517{
518 struct dso *pos;
519
520 list_for_each_entry(pos, head, node)
521 if (strcmp(pos->long_name, name) == 0)
522 return pos;
523 return NULL;
524}
525
526struct dso *__dsos__findnew(struct list_head *head, const char *name)
527{
528 struct dso *dso = dsos__find(head, name);
529
530 if (!dso) {
531 dso = dso__new(name);
532 if (dso != NULL) {
533 dsos__add(head, dso);
534 dso__set_basename(dso);
535 }
536 }
537
538 return dso;
539}
540
541size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
542 bool with_hits)
543{
544 struct dso *pos;
545 size_t ret = 0;
546
547 list_for_each_entry(pos, head, node) {
548 if (with_hits && !pos->hit)
549 continue;
550 ret += dso__fprintf_buildid(pos, fp);
551 ret += fprintf(fp, " %s\n", pos->long_name);
552 }
553 return ret;
554}
555
556size_t __dsos__fprintf(struct list_head *head, FILE *fp)
557{
558 struct dso *pos;
559 size_t ret = 0;
560
561 list_for_each_entry(pos, head, node) {
562 int i;
563 for (i = 0; i < MAP__NR_TYPES; ++i)
564 ret += dso__fprintf(pos, i, fp);
565 }
566
567 return ret;
568}
569
570size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
571{
572 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
573
574 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
575 return fprintf(fp, "%s", sbuild_id);
576}
577
578size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
579{
580 struct rb_node *nd;
581 size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
582
583 if (dso->short_name != dso->long_name)
584 ret += fprintf(fp, "%s, ", dso->long_name);
585 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
586 dso->loaded ? "" : "NOT ");
587 ret += dso__fprintf_buildid(dso, fp);
588 ret += fprintf(fp, ")\n");
589 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
590 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
591 ret += symbol__fprintf(pos, fp);
592 }
593
594 return ret;
595}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
new file mode 100644
index 000000000000..e03276940b99
--- /dev/null
+++ b/tools/perf/util/dso.h
@@ -0,0 +1,148 @@
1#ifndef __PERF_DSO
2#define __PERF_DSO
3
4#include <linux/types.h>
5#include <linux/rbtree.h>
6#include "types.h"
7#include "map.h"
8
9enum dso_binary_type {
10 DSO_BINARY_TYPE__KALLSYMS = 0,
11 DSO_BINARY_TYPE__GUEST_KALLSYMS,
12 DSO_BINARY_TYPE__VMLINUX,
13 DSO_BINARY_TYPE__GUEST_VMLINUX,
14 DSO_BINARY_TYPE__JAVA_JIT,
15 DSO_BINARY_TYPE__DEBUGLINK,
16 DSO_BINARY_TYPE__BUILD_ID_CACHE,
17 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
18 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
19 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
20 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
21 DSO_BINARY_TYPE__GUEST_KMODULE,
22 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
23 DSO_BINARY_TYPE__NOT_FOUND,
24};
25
26enum dso_kernel_type {
27 DSO_TYPE_USER = 0,
28 DSO_TYPE_KERNEL,
29 DSO_TYPE_GUEST_KERNEL
30};
31
32enum dso_swap_type {
33 DSO_SWAP__UNSET,
34 DSO_SWAP__NO,
35 DSO_SWAP__YES,
36};
37
38#define DSO__SWAP(dso, type, val) \
39({ \
40 type ____r = val; \
41 BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \
42 if (dso->needs_swap == DSO_SWAP__YES) { \
43 switch (sizeof(____r)) { \
44 case 2: \
45 ____r = bswap_16(val); \
46 break; \
47 case 4: \
48 ____r = bswap_32(val); \
49 break; \
50 case 8: \
51 ____r = bswap_64(val); \
52 break; \
53 default: \
54 BUG_ON(1); \
55 } \
56 } \
57 ____r; \
58})
59
60#define DSO__DATA_CACHE_SIZE 4096
61#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
62
63struct dso_cache {
64 struct rb_node rb_node;
65 u64 offset;
66 u64 size;
67 char data[0];
68};
69
70struct dso {
71 struct list_head node;
72 struct rb_root symbols[MAP__NR_TYPES];
73 struct rb_root symbol_names[MAP__NR_TYPES];
74 struct rb_root cache;
75 enum dso_kernel_type kernel;
76 enum dso_swap_type needs_swap;
77 enum dso_binary_type symtab_type;
78 enum dso_binary_type data_type;
79 u8 adjust_symbols:1;
80 u8 has_build_id:1;
81 u8 hit:1;
82 u8 annotate_warned:1;
83 u8 sname_alloc:1;
84 u8 lname_alloc:1;
85 u8 sorted_by_name;
86 u8 loaded;
87 u8 build_id[BUILD_ID_SIZE];
88 const char *short_name;
89 char *long_name;
90 u16 long_name_len;
91 u16 short_name_len;
92 char name[0];
93};
94
95static inline void dso__set_loaded(struct dso *dso, enum map_type type)
96{
97 dso->loaded |= (1 << type);
98}
99
100struct dso *dso__new(const char *name);
101void dso__delete(struct dso *dso);
102
103void dso__set_short_name(struct dso *dso, const char *name);
104void dso__set_long_name(struct dso *dso, char *name);
105
106int dso__name_len(const struct dso *dso);
107
108bool dso__loaded(const struct dso *dso, enum map_type type);
109
110bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
111void dso__set_sorted_by_name(struct dso *dso, enum map_type type);
112void dso__sort_by_name(struct dso *dso, enum map_type type);
113
114void dso__set_build_id(struct dso *dso, void *build_id);
115bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
116void dso__read_running_kernel_build_id(struct dso *dso,
117 struct machine *machine);
118int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
119
120char dso__symtab_origin(const struct dso *dso);
121int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
122 char *root_dir, char *file, size_t size);
123
124int dso__data_fd(struct dso *dso, struct machine *machine);
125ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
126 u64 offset, u8 *data, ssize_t size);
127ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
128 struct machine *machine, u64 addr,
129 u8 *data, ssize_t size);
130
131struct map *dso__new_map(const char *name);
132struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
133 const char *short_name, int dso_type);
134
135void dsos__add(struct list_head *head, struct dso *dso);
136struct dso *dsos__find(struct list_head *head, const char *name);
137struct dso *__dsos__findnew(struct list_head *head, const char *name);
138bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
139
140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
141 bool with_hits);
142size_t __dsos__fprintf(struct list_head *head, FILE *fp);
143
144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
145size_t dso__fprintf_symbols_by_name(struct dso *dso,
146 enum map_type type, FILE *fp);
147size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
148#endif /* __PERF_DSO */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 6715b1938725..3cf2c3e0605f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,6 +1,7 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "machine.h"
4#include "sort.h" 5#include "sort.h"
5#include "string.h" 6#include "string.h"
6#include "strlist.h" 7#include "strlist.h"
@@ -192,55 +193,43 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
192 event->header.misc = PERF_RECORD_MISC_USER; 193 event->header.misc = PERF_RECORD_MISC_USER;
193 194
194 while (1) { 195 while (1) {
195 char bf[BUFSIZ], *pbf = bf; 196 char bf[BUFSIZ];
196 int n; 197 char prot[5];
198 char execname[PATH_MAX];
199 char anonstr[] = "//anon";
197 size_t size; 200 size_t size;
201
198 if (fgets(bf, sizeof(bf), fp) == NULL) 202 if (fgets(bf, sizeof(bf), fp) == NULL)
199 break; 203 break;
200 204
205 /* ensure null termination since stack will be reused. */
206 strcpy(execname, "");
207
201 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 208 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
202 n = hex2u64(pbf, &event->mmap.start); 209 sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
203 if (n < 0) 210 &event->mmap.start, &event->mmap.len, prot,
204 continue; 211 &event->mmap.pgoff, execname);
205 pbf += n + 1; 212
206 n = hex2u64(pbf, &event->mmap.len); 213 if (prot[2] != 'x')
207 if (n < 0)
208 continue; 214 continue;
209 pbf += n + 3; 215
210 if (*pbf == 'x') { /* vm_exec */ 216 if (!strcmp(execname, ""))
211 char anonstr[] = "//anon\n"; 217 strcpy(execname, anonstr);
212 char *execname = strchr(bf, '/'); 218
213 219 size = strlen(execname) + 1;
214 /* Catch VDSO */ 220 memcpy(event->mmap.filename, execname, size);
215 if (execname == NULL) 221 size = PERF_ALIGN(size, sizeof(u64));
216 execname = strstr(bf, "[vdso]"); 222 event->mmap.len -= event->mmap.start;
217 223 event->mmap.header.size = (sizeof(event->mmap) -
218 /* Catch anonymous mmaps */ 224 (sizeof(event->mmap.filename) - size));
219 if ((execname == NULL) && !strstr(bf, "[")) 225 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
220 execname = anonstr; 226 event->mmap.header.size += machine->id_hdr_size;
221 227 event->mmap.pid = tgid;
222 if (execname == NULL) 228 event->mmap.tid = pid;
223 continue; 229
224 230 if (process(tool, event, &synth_sample, machine) != 0) {
225 pbf += 3; 231 rc = -1;
226 n = hex2u64(pbf, &event->mmap.pgoff); 232 break;
227
228 size = strlen(execname);
229 execname[size - 1] = '\0'; /* Remove \n */
230 memcpy(event->mmap.filename, execname, size);
231 size = PERF_ALIGN(size, sizeof(u64));
232 event->mmap.len -= event->mmap.start;
233 event->mmap.header.size = (sizeof(event->mmap) -
234 (sizeof(event->mmap.filename) - size));
235 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
236 event->mmap.header.size += machine->id_hdr_size;
237 event->mmap.pid = tgid;
238 event->mmap.tid = pid;
239
240 if (process(tool, event, &synth_sample, machine) != 0) {
241 rc = -1;
242 break;
243 }
244 } 233 }
245 } 234 }
246 235
@@ -404,16 +393,15 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
404 393
405 if (*end) /* only interested in proper numerical dirents */ 394 if (*end) /* only interested in proper numerical dirents */
406 continue; 395 continue;
407 396 /*
408 if (__event__synthesize_thread(comm_event, mmap_event, pid, 1, 397 * We may race with exiting thread, so don't stop just because
409 process, tool, machine) != 0) { 398 * one thread couldn't be synthesized.
410 err = -1; 399 */
411 goto out_closedir; 400 __event__synthesize_thread(comm_event, mmap_event, pid, 1,
412 } 401 process, tool, machine);
413 } 402 }
414 403
415 err = 0; 404 err = 0;
416out_closedir:
417 closedir(proc); 405 closedir(proc);
418out_free_mmap: 406out_free_mmap:
419 free(mmap_event); 407 free(mmap_event);
@@ -519,134 +507,15 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
519 struct perf_sample *sample __maybe_unused, 507 struct perf_sample *sample __maybe_unused,
520 struct machine *machine) 508 struct machine *machine)
521{ 509{
522 struct thread *thread = machine__findnew_thread(machine, event->comm.tid); 510 return machine__process_comm_event(machine, event);
523
524 if (dump_trace)
525 perf_event__fprintf_comm(event, stdout);
526
527 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
528 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
529 return -1;
530 }
531
532 return 0;
533} 511}
534 512
535int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 513int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
536 union perf_event *event, 514 union perf_event *event,
537 struct perf_sample *sample __maybe_unused, 515 struct perf_sample *sample __maybe_unused,
538 struct machine *machine __maybe_unused) 516 struct machine *machine)
539{
540 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
541 event->lost.id, event->lost.lost);
542 return 0;
543}
544
545static void perf_event__set_kernel_mmap_len(union perf_event *event,
546 struct map **maps)
547{
548 maps[MAP__FUNCTION]->start = event->mmap.start;
549 maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len;
550 /*
551 * Be a bit paranoid here, some perf.data file came with
552 * a zero sized synthesized MMAP event for the kernel.
553 */
554 if (maps[MAP__FUNCTION]->end == 0)
555 maps[MAP__FUNCTION]->end = ~0ULL;
556}
557
558static int perf_event__process_kernel_mmap(struct perf_tool *tool
559 __maybe_unused,
560 union perf_event *event,
561 struct machine *machine)
562{ 517{
563 struct map *map; 518 return machine__process_lost_event(machine, event);
564 char kmmap_prefix[PATH_MAX];
565 enum dso_kernel_type kernel_type;
566 bool is_kernel_mmap;
567
568 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
569 if (machine__is_host(machine))
570 kernel_type = DSO_TYPE_KERNEL;
571 else
572 kernel_type = DSO_TYPE_GUEST_KERNEL;
573
574 is_kernel_mmap = memcmp(event->mmap.filename,
575 kmmap_prefix,
576 strlen(kmmap_prefix) - 1) == 0;
577 if (event->mmap.filename[0] == '/' ||
578 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
579
580 char short_module_name[1024];
581 char *name, *dot;
582
583 if (event->mmap.filename[0] == '/') {
584 name = strrchr(event->mmap.filename, '/');
585 if (name == NULL)
586 goto out_problem;
587
588 ++name; /* skip / */
589 dot = strrchr(name, '.');
590 if (dot == NULL)
591 goto out_problem;
592 snprintf(short_module_name, sizeof(short_module_name),
593 "[%.*s]", (int)(dot - name), name);
594 strxfrchar(short_module_name, '-', '_');
595 } else
596 strcpy(short_module_name, event->mmap.filename);
597
598 map = machine__new_module(machine, event->mmap.start,
599 event->mmap.filename);
600 if (map == NULL)
601 goto out_problem;
602
603 name = strdup(short_module_name);
604 if (name == NULL)
605 goto out_problem;
606
607 map->dso->short_name = name;
608 map->dso->sname_alloc = 1;
609 map->end = map->start + event->mmap.len;
610 } else if (is_kernel_mmap) {
611 const char *symbol_name = (event->mmap.filename +
612 strlen(kmmap_prefix));
613 /*
614 * Should be there already, from the build-id table in
615 * the header.
616 */
617 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
618 kmmap_prefix);
619 if (kernel == NULL)
620 goto out_problem;
621
622 kernel->kernel = kernel_type;
623 if (__machine__create_kernel_maps(machine, kernel) < 0)
624 goto out_problem;
625
626 perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
627
628 /*
629 * Avoid using a zero address (kptr_restrict) for the ref reloc
630 * symbol. Effectively having zero here means that at record
631 * time /proc/sys/kernel/kptr_restrict was non zero.
632 */
633 if (event->mmap.pgoff != 0) {
634 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
635 symbol_name,
636 event->mmap.pgoff);
637 }
638
639 if (machine__is_default_guest(machine)) {
640 /*
641 * preload dso of guest kernel and modules
642 */
643 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
644 NULL);
645 }
646 }
647 return 0;
648out_problem:
649 return -1;
650} 519}
651 520
652size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 521size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
@@ -656,43 +525,12 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
656 event->mmap.len, event->mmap.pgoff, event->mmap.filename); 525 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
657} 526}
658 527
659int perf_event__process_mmap(struct perf_tool *tool, 528int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
660 union perf_event *event, 529 union perf_event *event,
661 struct perf_sample *sample __maybe_unused, 530 struct perf_sample *sample __maybe_unused,
662 struct machine *machine) 531 struct machine *machine)
663{ 532{
664 struct thread *thread; 533 return machine__process_mmap_event(machine, event);
665 struct map *map;
666 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
667 int ret = 0;
668
669 if (dump_trace)
670 perf_event__fprintf_mmap(event, stdout);
671
672 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
673 cpumode == PERF_RECORD_MISC_KERNEL) {
674 ret = perf_event__process_kernel_mmap(tool, event, machine);
675 if (ret < 0)
676 goto out_problem;
677 return 0;
678 }
679
680 thread = machine__findnew_thread(machine, event->mmap.pid);
681 if (thread == NULL)
682 goto out_problem;
683 map = map__new(&machine->user_dsos, event->mmap.start,
684 event->mmap.len, event->mmap.pgoff,
685 event->mmap.pid, event->mmap.filename,
686 MAP__FUNCTION);
687 if (map == NULL)
688 goto out_problem;
689
690 thread__insert_map(thread, map);
691 return 0;
692
693out_problem:
694 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
695 return 0;
696} 534}
697 535
698size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 536size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
@@ -702,29 +540,20 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
702 event->fork.ppid, event->fork.ptid); 540 event->fork.ppid, event->fork.ptid);
703} 541}
704 542
705int perf_event__process_task(struct perf_tool *tool __maybe_unused, 543int perf_event__process_fork(struct perf_tool *tool __maybe_unused,
706 union perf_event *event, 544 union perf_event *event,
707 struct perf_sample *sample __maybe_unused, 545 struct perf_sample *sample __maybe_unused,
708 struct machine *machine) 546 struct machine *machine)
709{ 547{
710 struct thread *thread = machine__findnew_thread(machine, event->fork.tid); 548 return machine__process_fork_event(machine, event);
711 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); 549}
712
713 if (dump_trace)
714 perf_event__fprintf_task(event, stdout);
715
716 if (event->header.type == PERF_RECORD_EXIT) {
717 machine__remove_thread(machine, thread);
718 return 0;
719 }
720
721 if (thread == NULL || parent == NULL ||
722 thread__fork(thread, parent) < 0) {
723 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
724 return -1;
725 }
726 550
727 return 0; 551int perf_event__process_exit(struct perf_tool *tool __maybe_unused,
552 union perf_event *event,
553 struct perf_sample *sample __maybe_unused,
554 struct machine *machine)
555{
556 return machine__process_exit_event(machine, event);
728} 557}
729 558
730size_t perf_event__fprintf(union perf_event *event, FILE *fp) 559size_t perf_event__fprintf(union perf_event *event, FILE *fp)
@@ -750,27 +579,12 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
750 return ret; 579 return ret;
751} 580}
752 581
753int perf_event__process(struct perf_tool *tool, union perf_event *event, 582int perf_event__process(struct perf_tool *tool __maybe_unused,
754 struct perf_sample *sample, struct machine *machine) 583 union perf_event *event,
584 struct perf_sample *sample __maybe_unused,
585 struct machine *machine)
755{ 586{
756 switch (event->header.type) { 587 return machine__process_event(machine, event);
757 case PERF_RECORD_COMM:
758 perf_event__process_comm(tool, event, sample, machine);
759 break;
760 case PERF_RECORD_MMAP:
761 perf_event__process_mmap(tool, event, sample, machine);
762 break;
763 case PERF_RECORD_FORK:
764 case PERF_RECORD_EXIT:
765 perf_event__process_task(tool, event, sample, machine);
766 break;
767 case PERF_RECORD_LOST:
768 perf_event__process_lost(tool, event, sample, machine);
769 default:
770 break;
771 }
772
773 return 0;
774} 588}
775 589
776void thread__find_addr_map(struct thread *self, 590void thread__find_addr_map(struct thread *self,
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 21b99e741a87..0d573ff4771a 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -6,6 +6,7 @@
6 6
7#include "../perf.h" 7#include "../perf.h"
8#include "map.h" 8#include "map.h"
9#include "build-id.h"
9 10
10/* 11/*
11 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 12 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -96,8 +97,6 @@ struct perf_sample {
96 struct stack_dump user_stack; 97 struct stack_dump user_stack;
97}; 98};
98 99
99#define BUILD_ID_SIZE 20
100
101struct build_id_event { 100struct build_id_event {
102 struct perf_event_header header; 101 struct perf_event_header header;
103 pid_t pid; 102 pid_t pid;
@@ -191,7 +190,11 @@ int perf_event__process_mmap(struct perf_tool *tool,
191 union perf_event *event, 190 union perf_event *event,
192 struct perf_sample *sample, 191 struct perf_sample *sample,
193 struct machine *machine); 192 struct machine *machine);
194int perf_event__process_task(struct perf_tool *tool, 193int perf_event__process_fork(struct perf_tool *tool,
194 union perf_event *event,
195 struct perf_sample *sample,
196 struct machine *machine);
197int perf_event__process_exit(struct perf_tool *tool,
195 union perf_event *event, 198 union perf_event *event,
196 struct perf_sample *sample, 199 struct perf_sample *sample,
197 struct machine *machine); 200 struct machine *machine);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 186b87730396..705293489e3c 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -52,15 +52,13 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
52void perf_evlist__config_attrs(struct perf_evlist *evlist, 52void perf_evlist__config_attrs(struct perf_evlist *evlist,
53 struct perf_record_opts *opts) 53 struct perf_record_opts *opts)
54{ 54{
55 struct perf_evsel *evsel, *first; 55 struct perf_evsel *evsel;
56 56
57 if (evlist->cpus->map[0] < 0) 57 if (evlist->cpus->map[0] < 0)
58 opts->no_inherit = true; 58 opts->no_inherit = true;
59 59
60 first = perf_evlist__first(evlist);
61
62 list_for_each_entry(evsel, &evlist->entries, node) { 60 list_for_each_entry(evsel, &evlist->entries, node) {
63 perf_evsel__config(evsel, opts, first); 61 perf_evsel__config(evsel, opts);
64 62
65 if (evlist->nr_entries > 1) 63 if (evlist->nr_entries > 1)
66 evsel->attr.sample_type |= PERF_SAMPLE_ID; 64 evsel->attr.sample_type |= PERF_SAMPLE_ID;
@@ -224,6 +222,8 @@ void perf_evlist__disable(struct perf_evlist *evlist)
224 222
225 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 223 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
226 list_for_each_entry(pos, &evlist->entries, node) { 224 list_for_each_entry(pos, &evlist->entries, node) {
225 if (perf_evsel__is_group_member(pos))
226 continue;
227 for (thread = 0; thread < evlist->threads->nr; thread++) 227 for (thread = 0; thread < evlist->threads->nr; thread++)
228 ioctl(FD(pos, cpu, thread), 228 ioctl(FD(pos, cpu, thread),
229 PERF_EVENT_IOC_DISABLE, 0); 229 PERF_EVENT_IOC_DISABLE, 0);
@@ -238,6 +238,8 @@ void perf_evlist__enable(struct perf_evlist *evlist)
238 238
239 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { 239 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) {
240 list_for_each_entry(pos, &evlist->entries, node) { 240 list_for_each_entry(pos, &evlist->entries, node) {
241 if (perf_evsel__is_group_member(pos))
242 continue;
241 for (thread = 0; thread < evlist->threads->nr; thread++) 243 for (thread = 0; thread < evlist->threads->nr; thread++)
242 ioctl(FD(pos, cpu, thread), 244 ioctl(FD(pos, cpu, thread),
243 PERF_EVENT_IOC_ENABLE, 0); 245 PERF_EVENT_IOC_ENABLE, 0);
@@ -325,8 +327,6 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
325 327
326union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 328union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
327{ 329{
328 /* XXX Move this to perf.c, making it generally available */
329 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
330 struct perf_mmap *md = &evlist->mmap[idx]; 330 struct perf_mmap *md = &evlist->mmap[idx];
331 unsigned int head = perf_mmap__read_head(md); 331 unsigned int head = perf_mmap__read_head(md);
332 unsigned int old = md->prev; 332 unsigned int old = md->prev;
@@ -528,7 +528,6 @@ out_unmap:
528int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 528int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
529 bool overwrite) 529 bool overwrite)
530{ 530{
531 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
532 struct perf_evsel *evsel; 531 struct perf_evsel *evsel;
533 const struct cpu_map *cpus = evlist->cpus; 532 const struct cpu_map *cpus = evlist->cpus;
534 const struct thread_map *threads = evlist->threads; 533 const struct thread_map *threads = evlist->threads;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d144d464ce39..1b16dd1edc8e 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -404,13 +404,40 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
404 return evsel->name ?: "unknown"; 404 return evsel->name ?: "unknown";
405} 405}
406 406
407void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, 407/*
408 struct perf_evsel *first) 408 * The enable_on_exec/disabled value strategy:
409 *
410 * 1) For any type of traced program:
411 * - all independent events and group leaders are disabled
412 * - all group members are enabled
413 *
414 * Group members are ruled by group leaders. They need to
415 * be enabled, because the group scheduling relies on that.
416 *
417 * 2) For traced programs executed by perf:
418 * - all independent events and group leaders have
419 * enable_on_exec set
420 * - we don't specifically enable or disable any event during
421 * the record command
422 *
423 * Independent events and group leaders are initially disabled
424 * and get enabled by exec. Group members are ruled by group
425 * leaders as stated in 1).
426 *
427 * 3) For traced programs attached by perf (pid/tid):
428 * - we specifically enable or disable all events during
429 * the record command
430 *
431 * When attaching events to already running traced we
432 * enable/disable events specifically, as there's no
433 * initial traced exec call.
434 */
435void perf_evsel__config(struct perf_evsel *evsel,
436 struct perf_record_opts *opts)
409{ 437{
410 struct perf_event_attr *attr = &evsel->attr; 438 struct perf_event_attr *attr = &evsel->attr;
411 int track = !evsel->idx; /* only the first counter needs these */ 439 int track = !evsel->idx; /* only the first counter needs these */
412 440
413 attr->disabled = 1;
414 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 441 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
415 attr->inherit = !opts->no_inherit; 442 attr->inherit = !opts->no_inherit;
416 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 443 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -486,10 +513,21 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
486 attr->mmap = track; 513 attr->mmap = track;
487 attr->comm = track; 514 attr->comm = track;
488 515
489 if (perf_target__none(&opts->target) && 516 /*
490 (!opts->group || evsel == first)) { 517 * XXX see the function comment above
518 *
519 * Disabling only independent events or group leaders,
520 * keeping group members enabled.
521 */
522 if (!perf_evsel__is_group_member(evsel))
523 attr->disabled = 1;
524
525 /*
526 * Setting enable_on_exec for independent events and
527 * group leaders for traced executed by perf.
528 */
529 if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel))
491 attr->enable_on_exec = 1; 530 attr->enable_on_exec = 1;
492 }
493} 531}
494 532
495int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 533int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -669,7 +707,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
669 struct perf_evsel *leader = evsel->leader; 707 struct perf_evsel *leader = evsel->leader;
670 int fd; 708 int fd;
671 709
672 if (!leader) 710 if (!perf_evsel__is_group_member(evsel))
673 return -1; 711 return -1;
674 712
675 /* 713 /*
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index d99b476ef37c..3d2b8017438c 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -93,8 +93,7 @@ void perf_evsel__exit(struct perf_evsel *evsel);
93void perf_evsel__delete(struct perf_evsel *evsel); 93void perf_evsel__delete(struct perf_evsel *evsel);
94 94
95void perf_evsel__config(struct perf_evsel *evsel, 95void perf_evsel__config(struct perf_evsel *evsel,
96 struct perf_record_opts *opts, 96 struct perf_record_opts *opts);
97 struct perf_evsel *first);
98 97
99bool perf_evsel__is_cache_op_valid(u8 type, u8 op); 98bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
100 99
@@ -226,4 +225,9 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
226{ 225{
227 return list_entry(evsel->node.next, struct perf_evsel, node); 226 return list_entry(evsel->node.next, struct perf_evsel, node);
228} 227}
228
229static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel)
230{
231 return evsel->leader != NULL;
232}
229#endif /* __PERF_EVSEL_H */ 233#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 566b84c695c8..b7da4634a047 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,6 +23,7 @@
23#include "pmu.h" 23#include "pmu.h"
24#include "vdso.h" 24#include "vdso.h"
25#include "strbuf.h" 25#include "strbuf.h"
26#include "build-id.h"
26 27
27static bool no_buildid_cache = false; 28static bool no_buildid_cache = false;
28 29
@@ -2342,6 +2343,16 @@ static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
2342 return -1; 2343 return -1;
2343} 2344}
2344 2345
2346bool is_perf_magic(u64 magic)
2347{
2348 if (!memcmp(&magic, __perf_magic1, sizeof(magic))
2349 || magic == __perf_magic2
2350 || magic == __perf_magic2_sw)
2351 return true;
2352
2353 return false;
2354}
2355
2345static int check_magic_endian(u64 magic, uint64_t hdr_sz, 2356static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2346 bool is_pipe, struct perf_header *ph) 2357 bool is_pipe, struct perf_header *ph)
2347{ 2358{
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 9bc00783f24f..20f0344accb1 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -154,6 +154,7 @@ int perf_event__synthesize_build_id(struct perf_tool *tool,
154int perf_event__process_build_id(struct perf_tool *tool, 154int perf_event__process_build_id(struct perf_tool *tool,
155 union perf_event *event, 155 union perf_event *event,
156 struct perf_session *session); 156 struct perf_session *session);
157bool is_perf_magic(u64 magic);
157 158
158/* 159/*
159 * arch specific callback 160 * arch specific callback
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 277947a669b2..cb17e2a8c6ed 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -244,6 +244,8 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
244 he->ms.map->referenced = true; 244 he->ms.map->referenced = true;
245 if (symbol_conf.use_callchain) 245 if (symbol_conf.use_callchain)
246 callchain_init(he->callchain); 246 callchain_init(he->callchain);
247
248 INIT_LIST_HEAD(&he->pairs.node);
247 } 249 }
248 250
249 return he; 251 return he;
@@ -410,6 +412,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
410 412
411void hist_entry__free(struct hist_entry *he) 413void hist_entry__free(struct hist_entry *he)
412{ 414{
415 free(he->branch_info);
413 free(he); 416 free(he);
414} 417}
415 418
@@ -713,3 +716,99 @@ void hists__inc_nr_events(struct hists *hists, u32 type)
713 ++hists->stats.nr_events[0]; 716 ++hists->stats.nr_events[0];
714 ++hists->stats.nr_events[type]; 717 ++hists->stats.nr_events[type];
715} 718}
719
720static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
721 struct hist_entry *pair)
722{
723 struct rb_node **p = &hists->entries.rb_node;
724 struct rb_node *parent = NULL;
725 struct hist_entry *he;
726 int cmp;
727
728 while (*p != NULL) {
729 parent = *p;
730 he = rb_entry(parent, struct hist_entry, rb_node);
731
732 cmp = hist_entry__cmp(pair, he);
733
734 if (!cmp)
735 goto out;
736
737 if (cmp < 0)
738 p = &(*p)->rb_left;
739 else
740 p = &(*p)->rb_right;
741 }
742
743 he = hist_entry__new(pair);
744 if (he) {
745 memset(&he->stat, 0, sizeof(he->stat));
746 he->hists = hists;
747 rb_link_node(&he->rb_node, parent, p);
748 rb_insert_color(&he->rb_node, &hists->entries);
749 hists__inc_nr_entries(hists, he);
750 }
751out:
752 return he;
753}
754
755static struct hist_entry *hists__find_entry(struct hists *hists,
756 struct hist_entry *he)
757{
758 struct rb_node *n = hists->entries.rb_node;
759
760 while (n) {
761 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
762 int64_t cmp = hist_entry__cmp(he, iter);
763
764 if (cmp < 0)
765 n = n->rb_left;
766 else if (cmp > 0)
767 n = n->rb_right;
768 else
769 return iter;
770 }
771
772 return NULL;
773}
774
775/*
776 * Look for pairs to link to the leader buckets (hist_entries):
777 */
778void hists__match(struct hists *leader, struct hists *other)
779{
780 struct rb_node *nd;
781 struct hist_entry *pos, *pair;
782
783 for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) {
784 pos = rb_entry(nd, struct hist_entry, rb_node);
785 pair = hists__find_entry(other, pos);
786
787 if (pair)
788 hist__entry_add_pair(pos, pair);
789 }
790}
791
792/*
793 * Look for entries in the other hists that are not present in the leader, if
794 * we find them, just add a dummy entry on the leader hists, with period=0,
795 * nr_events=0, to serve as the list header.
796 */
797int hists__link(struct hists *leader, struct hists *other)
798{
799 struct rb_node *nd;
800 struct hist_entry *pos, *pair;
801
802 for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) {
803 pos = rb_entry(nd, struct hist_entry, rb_node);
804
805 if (!hist_entry__has_pairs(pos)) {
806 pair = hists__add_dummy_entry(leader, pos);
807 if (pair == NULL)
808 return -1;
809 hist__entry_add_pair(pair, pos);
810 }
811 }
812
813 return 0;
814}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 66cb31fe81d2..8b091a51e4a2 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -4,6 +4,7 @@
4#include <linux/types.h> 4#include <linux/types.h>
5#include <pthread.h> 5#include <pthread.h>
6#include "callchain.h" 6#include "callchain.h"
7#include "header.h"
7 8
8extern struct callchain_param callchain_param; 9extern struct callchain_param callchain_param;
9 10
@@ -114,6 +115,9 @@ bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
114void hists__reset_col_len(struct hists *hists); 115void hists__reset_col_len(struct hists *hists);
115void hists__calc_col_len(struct hists *hists, struct hist_entry *he); 116void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
116 117
118void hists__match(struct hists *leader, struct hists *other);
119int hists__link(struct hists *leader, struct hists *other);
120
117struct perf_hpp { 121struct perf_hpp {
118 char *buf; 122 char *buf;
119 size_t size; 123 size_t size;
@@ -140,8 +144,12 @@ enum {
140 PERF_HPP__OVERHEAD_GUEST_US, 144 PERF_HPP__OVERHEAD_GUEST_US,
141 PERF_HPP__SAMPLES, 145 PERF_HPP__SAMPLES,
142 PERF_HPP__PERIOD, 146 PERF_HPP__PERIOD,
147 PERF_HPP__PERIOD_BASELINE,
143 PERF_HPP__DELTA, 148 PERF_HPP__DELTA,
149 PERF_HPP__RATIO,
150 PERF_HPP__WEIGHTED_DIFF,
144 PERF_HPP__DISPL, 151 PERF_HPP__DISPL,
152 PERF_HPP__FORMULA,
145 153
146 PERF_HPP__MAX_INDEX 154 PERF_HPP__MAX_INDEX
147}; 155};
@@ -153,21 +161,27 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
153 161
154struct perf_evlist; 162struct perf_evlist;
155 163
164struct hist_browser_timer {
165 void (*timer)(void *arg);
166 void *arg;
167 int refresh;
168};
169
156#ifdef NEWT_SUPPORT 170#ifdef NEWT_SUPPORT
157#include "../ui/keysyms.h" 171#include "../ui/keysyms.h"
158int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 172int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
159 void(*timer)(void *arg), void *arg, int delay_secs); 173 struct hist_browser_timer *hbt);
160 174
161int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 175int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
162 void(*timer)(void *arg), void *arg, 176 struct hist_browser_timer *hbt,
163 int refresh); 177 struct perf_session_env *env);
178int script_browse(const char *script_opt);
164#else 179#else
165static inline 180static inline
166int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, 181int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
167 const char *help __maybe_unused, 182 const char *help __maybe_unused,
168 void(*timer)(void *arg) __maybe_unused, 183 struct hist_browser_timer *hbt __maybe_unused,
169 void *arg __maybe_unused, 184 struct perf_session_env *env __maybe_unused)
170 int refresh __maybe_unused)
171{ 185{
172 return 0; 186 return 0;
173} 187}
@@ -175,28 +189,29 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
175static inline int hist_entry__tui_annotate(struct hist_entry *self 189static inline int hist_entry__tui_annotate(struct hist_entry *self
176 __maybe_unused, 190 __maybe_unused,
177 int evidx __maybe_unused, 191 int evidx __maybe_unused,
178 void(*timer)(void *arg) 192 struct hist_browser_timer *hbt
179 __maybe_unused, 193 __maybe_unused)
180 void *arg __maybe_unused,
181 int delay_secs __maybe_unused)
182{ 194{
183 return 0; 195 return 0;
184} 196}
197
198static inline int script_browse(const char *script_opt __maybe_unused)
199{
200 return 0;
201}
202
185#define K_LEFT -1 203#define K_LEFT -1
186#define K_RIGHT -2 204#define K_RIGHT -2
187#endif 205#endif
188 206
189#ifdef GTK2_SUPPORT 207#ifdef GTK2_SUPPORT
190int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, 208int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
191 void(*timer)(void *arg), void *arg, 209 struct hist_browser_timer *hbt __maybe_unused);
192 int refresh);
193#else 210#else
194static inline 211static inline
195int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, 212int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
196 const char *help __maybe_unused, 213 const char *help __maybe_unused,
197 void(*timer)(void *arg) __maybe_unused, 214 struct hist_browser_timer *hbt __maybe_unused)
198 void *arg __maybe_unused,
199 int refresh __maybe_unused)
200{ 215{
201 return 0; 216 return 0;
202} 217}
@@ -204,4 +219,8 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
204 219
205unsigned int hists__sort_list_width(struct hists *self); 220unsigned int hists__sort_list_width(struct hists *self);
206 221
222double perf_diff__compute_delta(struct hist_entry *he);
223double perf_diff__compute_ratio(struct hist_entry *he);
224s64 perf_diff__compute_wdiff(struct hist_entry *he);
225int perf_diff__formula(char *buf, size_t size, struct hist_entry *he);
207#endif /* __PERF_HIST_H */ 226#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
new file mode 100644
index 000000000000..1f09d0581e6b
--- /dev/null
+++ b/tools/perf/util/machine.c
@@ -0,0 +1,464 @@
1#include "debug.h"
2#include "event.h"
3#include "machine.h"
4#include "map.h"
5#include "strlist.h"
6#include "thread.h"
7#include <stdbool.h>
8
9int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
10{
11 map_groups__init(&machine->kmaps);
12 RB_CLEAR_NODE(&machine->rb_node);
13 INIT_LIST_HEAD(&machine->user_dsos);
14 INIT_LIST_HEAD(&machine->kernel_dsos);
15
16 machine->threads = RB_ROOT;
17 INIT_LIST_HEAD(&machine->dead_threads);
18 machine->last_match = NULL;
19
20 machine->kmaps.machine = machine;
21 machine->pid = pid;
22
23 machine->root_dir = strdup(root_dir);
24 if (machine->root_dir == NULL)
25 return -ENOMEM;
26
27 if (pid != HOST_KERNEL_ID) {
28 struct thread *thread = machine__findnew_thread(machine, pid);
29 char comm[64];
30
31 if (thread == NULL)
32 return -ENOMEM;
33
34 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
35 thread__set_comm(thread, comm);
36 }
37
38 return 0;
39}
40
41static void dsos__delete(struct list_head *dsos)
42{
43 struct dso *pos, *n;
44
45 list_for_each_entry_safe(pos, n, dsos, node) {
46 list_del(&pos->node);
47 dso__delete(pos);
48 }
49}
50
51void machine__exit(struct machine *machine)
52{
53 map_groups__exit(&machine->kmaps);
54 dsos__delete(&machine->user_dsos);
55 dsos__delete(&machine->kernel_dsos);
56 free(machine->root_dir);
57 machine->root_dir = NULL;
58}
59
60void machine__delete(struct machine *machine)
61{
62 machine__exit(machine);
63 free(machine);
64}
65
66struct machine *machines__add(struct rb_root *machines, pid_t pid,
67 const char *root_dir)
68{
69 struct rb_node **p = &machines->rb_node;
70 struct rb_node *parent = NULL;
71 struct machine *pos, *machine = malloc(sizeof(*machine));
72
73 if (machine == NULL)
74 return NULL;
75
76 if (machine__init(machine, root_dir, pid) != 0) {
77 free(machine);
78 return NULL;
79 }
80
81 while (*p != NULL) {
82 parent = *p;
83 pos = rb_entry(parent, struct machine, rb_node);
84 if (pid < pos->pid)
85 p = &(*p)->rb_left;
86 else
87 p = &(*p)->rb_right;
88 }
89
90 rb_link_node(&machine->rb_node, parent, p);
91 rb_insert_color(&machine->rb_node, machines);
92
93 return machine;
94}
95
96struct machine *machines__find(struct rb_root *machines, pid_t pid)
97{
98 struct rb_node **p = &machines->rb_node;
99 struct rb_node *parent = NULL;
100 struct machine *machine;
101 struct machine *default_machine = NULL;
102
103 while (*p != NULL) {
104 parent = *p;
105 machine = rb_entry(parent, struct machine, rb_node);
106 if (pid < machine->pid)
107 p = &(*p)->rb_left;
108 else if (pid > machine->pid)
109 p = &(*p)->rb_right;
110 else
111 return machine;
112 if (!machine->pid)
113 default_machine = machine;
114 }
115
116 return default_machine;
117}
118
119struct machine *machines__findnew(struct rb_root *machines, pid_t pid)
120{
121 char path[PATH_MAX];
122 const char *root_dir = "";
123 struct machine *machine = machines__find(machines, pid);
124
125 if (machine && (machine->pid == pid))
126 goto out;
127
128 if ((pid != HOST_KERNEL_ID) &&
129 (pid != DEFAULT_GUEST_KERNEL_ID) &&
130 (symbol_conf.guestmount)) {
131 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
132 if (access(path, R_OK)) {
133 static struct strlist *seen;
134
135 if (!seen)
136 seen = strlist__new(true, NULL);
137
138 if (!strlist__has_entry(seen, path)) {
139 pr_err("Can't access file %s\n", path);
140 strlist__add(seen, path);
141 }
142 machine = NULL;
143 goto out;
144 }
145 root_dir = path;
146 }
147
148 machine = machines__add(machines, pid, root_dir);
149out:
150 return machine;
151}
152
153void machines__process(struct rb_root *machines,
154 machine__process_t process, void *data)
155{
156 struct rb_node *nd;
157
158 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
159 struct machine *pos = rb_entry(nd, struct machine, rb_node);
160 process(pos, data);
161 }
162}
163
164char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
165{
166 if (machine__is_host(machine))
167 snprintf(bf, size, "[%s]", "kernel.kallsyms");
168 else if (machine__is_default_guest(machine))
169 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
170 else {
171 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms",
172 machine->pid);
173 }
174
175 return bf;
176}
177
178void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
179{
180 struct rb_node *node;
181 struct machine *machine;
182
183 for (node = rb_first(machines); node; node = rb_next(node)) {
184 machine = rb_entry(node, struct machine, rb_node);
185 machine->id_hdr_size = id_hdr_size;
186 }
187
188 return;
189}
190
191static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid,
192 bool create)
193{
194 struct rb_node **p = &machine->threads.rb_node;
195 struct rb_node *parent = NULL;
196 struct thread *th;
197
198 /*
199 * Font-end cache - PID lookups come in blocks,
200 * so most of the time we dont have to look up
201 * the full rbtree:
202 */
203 if (machine->last_match && machine->last_match->pid == pid)
204 return machine->last_match;
205
206 while (*p != NULL) {
207 parent = *p;
208 th = rb_entry(parent, struct thread, rb_node);
209
210 if (th->pid == pid) {
211 machine->last_match = th;
212 return th;
213 }
214
215 if (pid < th->pid)
216 p = &(*p)->rb_left;
217 else
218 p = &(*p)->rb_right;
219 }
220
221 if (!create)
222 return NULL;
223
224 th = thread__new(pid);
225 if (th != NULL) {
226 rb_link_node(&th->rb_node, parent, p);
227 rb_insert_color(&th->rb_node, &machine->threads);
228 machine->last_match = th;
229 }
230
231 return th;
232}
233
234struct thread *machine__findnew_thread(struct machine *machine, pid_t pid)
235{
236 return __machine__findnew_thread(machine, pid, true);
237}
238
239struct thread *machine__find_thread(struct machine *machine, pid_t pid)
240{
241 return __machine__findnew_thread(machine, pid, false);
242}
243
244int machine__process_comm_event(struct machine *machine, union perf_event *event)
245{
246 struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
247
248 if (dump_trace)
249 perf_event__fprintf_comm(event, stdout);
250
251 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
252 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
253 return -1;
254 }
255
256 return 0;
257}
258
259int machine__process_lost_event(struct machine *machine __maybe_unused,
260 union perf_event *event)
261{
262 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
263 event->lost.id, event->lost.lost);
264 return 0;
265}
266
267static void machine__set_kernel_mmap_len(struct machine *machine,
268 union perf_event *event)
269{
270 int i;
271
272 for (i = 0; i < MAP__NR_TYPES; i++) {
273 machine->vmlinux_maps[i]->start = event->mmap.start;
274 machine->vmlinux_maps[i]->end = (event->mmap.start +
275 event->mmap.len);
276 /*
277 * Be a bit paranoid here, some perf.data file came with
278 * a zero sized synthesized MMAP event for the kernel.
279 */
280 if (machine->vmlinux_maps[i]->end == 0)
281 machine->vmlinux_maps[i]->end = ~0ULL;
282 }
283}
284
285static int machine__process_kernel_mmap_event(struct machine *machine,
286 union perf_event *event)
287{
288 struct map *map;
289 char kmmap_prefix[PATH_MAX];
290 enum dso_kernel_type kernel_type;
291 bool is_kernel_mmap;
292
293 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
294 if (machine__is_host(machine))
295 kernel_type = DSO_TYPE_KERNEL;
296 else
297 kernel_type = DSO_TYPE_GUEST_KERNEL;
298
299 is_kernel_mmap = memcmp(event->mmap.filename,
300 kmmap_prefix,
301 strlen(kmmap_prefix) - 1) == 0;
302 if (event->mmap.filename[0] == '/' ||
303 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
304
305 char short_module_name[1024];
306 char *name, *dot;
307
308 if (event->mmap.filename[0] == '/') {
309 name = strrchr(event->mmap.filename, '/');
310 if (name == NULL)
311 goto out_problem;
312
313 ++name; /* skip / */
314 dot = strrchr(name, '.');
315 if (dot == NULL)
316 goto out_problem;
317 snprintf(short_module_name, sizeof(short_module_name),
318 "[%.*s]", (int)(dot - name), name);
319 strxfrchar(short_module_name, '-', '_');
320 } else
321 strcpy(short_module_name, event->mmap.filename);
322
323 map = machine__new_module(machine, event->mmap.start,
324 event->mmap.filename);
325 if (map == NULL)
326 goto out_problem;
327
328 name = strdup(short_module_name);
329 if (name == NULL)
330 goto out_problem;
331
332 map->dso->short_name = name;
333 map->dso->sname_alloc = 1;
334 map->end = map->start + event->mmap.len;
335 } else if (is_kernel_mmap) {
336 const char *symbol_name = (event->mmap.filename +
337 strlen(kmmap_prefix));
338 /*
339 * Should be there already, from the build-id table in
340 * the header.
341 */
342 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
343 kmmap_prefix);
344 if (kernel == NULL)
345 goto out_problem;
346
347 kernel->kernel = kernel_type;
348 if (__machine__create_kernel_maps(machine, kernel) < 0)
349 goto out_problem;
350
351 machine__set_kernel_mmap_len(machine, event);
352
353 /*
354 * Avoid using a zero address (kptr_restrict) for the ref reloc
355 * symbol. Effectively having zero here means that at record
356 * time /proc/sys/kernel/kptr_restrict was non zero.
357 */
358 if (event->mmap.pgoff != 0) {
359 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
360 symbol_name,
361 event->mmap.pgoff);
362 }
363
364 if (machine__is_default_guest(machine)) {
365 /*
366 * preload dso of guest kernel and modules
367 */
368 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
369 NULL);
370 }
371 }
372 return 0;
373out_problem:
374 return -1;
375}
376
377int machine__process_mmap_event(struct machine *machine, union perf_event *event)
378{
379 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
380 struct thread *thread;
381 struct map *map;
382 int ret = 0;
383
384 if (dump_trace)
385 perf_event__fprintf_mmap(event, stdout);
386
387 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
388 cpumode == PERF_RECORD_MISC_KERNEL) {
389 ret = machine__process_kernel_mmap_event(machine, event);
390 if (ret < 0)
391 goto out_problem;
392 return 0;
393 }
394
395 thread = machine__findnew_thread(machine, event->mmap.pid);
396 if (thread == NULL)
397 goto out_problem;
398 map = map__new(&machine->user_dsos, event->mmap.start,
399 event->mmap.len, event->mmap.pgoff,
400 event->mmap.pid, event->mmap.filename,
401 MAP__FUNCTION);
402 if (map == NULL)
403 goto out_problem;
404
405 thread__insert_map(thread, map);
406 return 0;
407
408out_problem:
409 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
410 return 0;
411}
412
413int machine__process_fork_event(struct machine *machine, union perf_event *event)
414{
415 struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
416 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
417
418 if (dump_trace)
419 perf_event__fprintf_task(event, stdout);
420
421 if (thread == NULL || parent == NULL ||
422 thread__fork(thread, parent) < 0) {
423 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
424 return -1;
425 }
426
427 return 0;
428}
429
430int machine__process_exit_event(struct machine *machine, union perf_event *event)
431{
432 struct thread *thread = machine__find_thread(machine, event->fork.tid);
433
434 if (dump_trace)
435 perf_event__fprintf_task(event, stdout);
436
437 if (thread != NULL)
438 machine__remove_thread(machine, thread);
439
440 return 0;
441}
442
443int machine__process_event(struct machine *machine, union perf_event *event)
444{
445 int ret;
446
447 switch (event->header.type) {
448 case PERF_RECORD_COMM:
449 ret = machine__process_comm_event(machine, event); break;
450 case PERF_RECORD_MMAP:
451 ret = machine__process_mmap_event(machine, event); break;
452 case PERF_RECORD_FORK:
453 ret = machine__process_fork_event(machine, event); break;
454 case PERF_RECORD_EXIT:
455 ret = machine__process_exit_event(machine, event); break;
456 case PERF_RECORD_LOST:
457 ret = machine__process_lost_event(machine, event); break;
458 default:
459 ret = -1;
460 break;
461 }
462
463 return ret;
464}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
new file mode 100644
index 000000000000..b7cde7467d55
--- /dev/null
+++ b/tools/perf/util/machine.h
@@ -0,0 +1,148 @@
1#ifndef __PERF_MACHINE_H
2#define __PERF_MACHINE_H
3
4#include <sys/types.h>
5#include <linux/rbtree.h>
6#include "map.h"
7
8struct branch_stack;
9struct perf_evsel;
10struct perf_sample;
11struct symbol;
12struct thread;
13union perf_event;
14
15/* Native host kernel uses -1 as pid index in machine */
16#define HOST_KERNEL_ID (-1)
17#define DEFAULT_GUEST_KERNEL_ID (0)
18
19struct machine {
20 struct rb_node rb_node;
21 pid_t pid;
22 u16 id_hdr_size;
23 char *root_dir;
24 struct rb_root threads;
25 struct list_head dead_threads;
26 struct thread *last_match;
27 struct list_head user_dsos;
28 struct list_head kernel_dsos;
29 struct map_groups kmaps;
30 struct map *vmlinux_maps[MAP__NR_TYPES];
31};
32
33static inline
34struct map *machine__kernel_map(struct machine *machine, enum map_type type)
35{
36 return machine->vmlinux_maps[type];
37}
38
39struct thread *machine__find_thread(struct machine *machine, pid_t pid);
40
41int machine__process_comm_event(struct machine *machine, union perf_event *event);
42int machine__process_exit_event(struct machine *machine, union perf_event *event);
43int machine__process_fork_event(struct machine *machine, union perf_event *event);
44int machine__process_lost_event(struct machine *machine, union perf_event *event);
45int machine__process_mmap_event(struct machine *machine, union perf_event *event);
46int machine__process_event(struct machine *machine, union perf_event *event);
47
48typedef void (*machine__process_t)(struct machine *machine, void *data);
49
50void machines__process(struct rb_root *machines,
51 machine__process_t process, void *data);
52
53struct machine *machines__add(struct rb_root *machines, pid_t pid,
54 const char *root_dir);
55struct machine *machines__find_host(struct rb_root *machines);
56struct machine *machines__find(struct rb_root *machines, pid_t pid);
57struct machine *machines__findnew(struct rb_root *machines, pid_t pid);
58
59void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size);
60char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
61
62int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
63void machine__exit(struct machine *machine);
64void machine__delete(struct machine *machine);
65
66
67struct branch_info *machine__resolve_bstack(struct machine *machine,
68 struct thread *thread,
69 struct branch_stack *bs);
70int machine__resolve_callchain(struct machine *machine,
71 struct perf_evsel *evsel,
72 struct thread *thread,
73 struct perf_sample *sample,
74 struct symbol **parent);
75
76/*
77 * Default guest kernel is defined by parameter --guestkallsyms
78 * and --guestmodules
79 */
80static inline bool machine__is_default_guest(struct machine *machine)
81{
82 return machine ? machine->pid == DEFAULT_GUEST_KERNEL_ID : false;
83}
84
85static inline bool machine__is_host(struct machine *machine)
86{
87 return machine ? machine->pid == HOST_KERNEL_ID : false;
88}
89
90struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
91void machine__remove_thread(struct machine *machine, struct thread *th);
92
93size_t machine__fprintf(struct machine *machine, FILE *fp);
94
95static inline
96struct symbol *machine__find_kernel_symbol(struct machine *machine,
97 enum map_type type, u64 addr,
98 struct map **mapp,
99 symbol_filter_t filter)
100{
101 return map_groups__find_symbol(&machine->kmaps, type, addr,
102 mapp, filter);
103}
104
105static inline
106struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr,
107 struct map **mapp,
108 symbol_filter_t filter)
109{
110 return machine__find_kernel_symbol(machine, MAP__FUNCTION, addr,
111 mapp, filter);
112}
113
114static inline
115struct symbol *machine__find_kernel_function_by_name(struct machine *machine,
116 const char *name,
117 struct map **mapp,
118 symbol_filter_t filter)
119{
120 return map_groups__find_function_by_name(&machine->kmaps, name, mapp,
121 filter);
122}
123
124struct map *machine__new_module(struct machine *machine, u64 start,
125 const char *filename);
126
127int machine__load_kallsyms(struct machine *machine, const char *filename,
128 enum map_type type, symbol_filter_t filter);
129int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
130 symbol_filter_t filter);
131
132size_t machine__fprintf_dsos_buildid(struct machine *machine,
133 FILE *fp, bool with_hits);
134size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
135size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
136 FILE *fp, bool with_hits);
137
138void machine__destroy_kernel_maps(struct machine *machine);
139int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
140int machine__create_kernel_maps(struct machine *machine);
141
142int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
143int machines__create_guest_kernel_maps(struct rb_root *machines);
144void machines__destroy_guest_kernel_maps(struct rb_root *machines);
145
146size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
147
148#endif /* __PERF_MACHINE_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 6109fa4d14cd..0328d45c4f2a 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -10,6 +10,7 @@
10#include "thread.h" 10#include "thread.h"
11#include "strlist.h" 11#include "strlist.h"
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h"
13 14
14const char *map_type__name[MAP__NR_TYPES] = { 15const char *map_type__name[MAP__NR_TYPES] = {
15 [MAP__FUNCTION] = "Functions", 16 [MAP__FUNCTION] = "Functions",
@@ -23,7 +24,7 @@ static inline int is_anon_memory(const char *filename)
23 24
24static inline int is_no_dso_memory(const char *filename) 25static inline int is_no_dso_memory(const char *filename)
25{ 26{
26 return !strcmp(filename, "[stack]") || 27 return !strncmp(filename, "[stack", 6) ||
27 !strcmp(filename, "[heap]"); 28 !strcmp(filename, "[heap]");
28} 29}
29 30
@@ -589,182 +590,3 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
589 590
590 return NULL; 591 return NULL;
591} 592}
592
593int machine__init(struct machine *self, const char *root_dir, pid_t pid)
594{
595 map_groups__init(&self->kmaps);
596 RB_CLEAR_NODE(&self->rb_node);
597 INIT_LIST_HEAD(&self->user_dsos);
598 INIT_LIST_HEAD(&self->kernel_dsos);
599
600 self->threads = RB_ROOT;
601 INIT_LIST_HEAD(&self->dead_threads);
602 self->last_match = NULL;
603
604 self->kmaps.machine = self;
605 self->pid = pid;
606 self->root_dir = strdup(root_dir);
607 if (self->root_dir == NULL)
608 return -ENOMEM;
609
610 if (pid != HOST_KERNEL_ID) {
611 struct thread *thread = machine__findnew_thread(self, pid);
612 char comm[64];
613
614 if (thread == NULL)
615 return -ENOMEM;
616
617 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
618 thread__set_comm(thread, comm);
619 }
620
621 return 0;
622}
623
624static void dsos__delete(struct list_head *self)
625{
626 struct dso *pos, *n;
627
628 list_for_each_entry_safe(pos, n, self, node) {
629 list_del(&pos->node);
630 dso__delete(pos);
631 }
632}
633
634void machine__exit(struct machine *self)
635{
636 map_groups__exit(&self->kmaps);
637 dsos__delete(&self->user_dsos);
638 dsos__delete(&self->kernel_dsos);
639 free(self->root_dir);
640 self->root_dir = NULL;
641}
642
643void machine__delete(struct machine *self)
644{
645 machine__exit(self);
646 free(self);
647}
648
649struct machine *machines__add(struct rb_root *self, pid_t pid,
650 const char *root_dir)
651{
652 struct rb_node **p = &self->rb_node;
653 struct rb_node *parent = NULL;
654 struct machine *pos, *machine = malloc(sizeof(*machine));
655
656 if (!machine)
657 return NULL;
658
659 if (machine__init(machine, root_dir, pid) != 0) {
660 free(machine);
661 return NULL;
662 }
663
664 while (*p != NULL) {
665 parent = *p;
666 pos = rb_entry(parent, struct machine, rb_node);
667 if (pid < pos->pid)
668 p = &(*p)->rb_left;
669 else
670 p = &(*p)->rb_right;
671 }
672
673 rb_link_node(&machine->rb_node, parent, p);
674 rb_insert_color(&machine->rb_node, self);
675
676 return machine;
677}
678
679struct machine *machines__find(struct rb_root *self, pid_t pid)
680{
681 struct rb_node **p = &self->rb_node;
682 struct rb_node *parent = NULL;
683 struct machine *machine;
684 struct machine *default_machine = NULL;
685
686 while (*p != NULL) {
687 parent = *p;
688 machine = rb_entry(parent, struct machine, rb_node);
689 if (pid < machine->pid)
690 p = &(*p)->rb_left;
691 else if (pid > machine->pid)
692 p = &(*p)->rb_right;
693 else
694 return machine;
695 if (!machine->pid)
696 default_machine = machine;
697 }
698
699 return default_machine;
700}
701
702struct machine *machines__findnew(struct rb_root *self, pid_t pid)
703{
704 char path[PATH_MAX];
705 const char *root_dir = "";
706 struct machine *machine = machines__find(self, pid);
707
708 if (machine && (machine->pid == pid))
709 goto out;
710
711 if ((pid != HOST_KERNEL_ID) &&
712 (pid != DEFAULT_GUEST_KERNEL_ID) &&
713 (symbol_conf.guestmount)) {
714 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
715 if (access(path, R_OK)) {
716 static struct strlist *seen;
717
718 if (!seen)
719 seen = strlist__new(true, NULL);
720
721 if (!strlist__has_entry(seen, path)) {
722 pr_err("Can't access file %s\n", path);
723 strlist__add(seen, path);
724 }
725 machine = NULL;
726 goto out;
727 }
728 root_dir = path;
729 }
730
731 machine = machines__add(self, pid, root_dir);
732
733out:
734 return machine;
735}
736
737void machines__process(struct rb_root *self, machine__process_t process, void *data)
738{
739 struct rb_node *nd;
740
741 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
742 struct machine *pos = rb_entry(nd, struct machine, rb_node);
743 process(pos, data);
744 }
745}
746
747char *machine__mmap_name(struct machine *self, char *bf, size_t size)
748{
749 if (machine__is_host(self))
750 snprintf(bf, size, "[%s]", "kernel.kallsyms");
751 else if (machine__is_default_guest(self))
752 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
753 else
754 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", self->pid);
755
756 return bf;
757}
758
759void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
760{
761 struct rb_node *node;
762 struct machine *machine;
763
764 for (node = rb_first(machines); node; node = rb_next(node)) {
765 machine = rb_entry(node, struct machine, rb_node);
766 machine->id_hdr_size = id_hdr_size;
767 }
768
769 return;
770}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index d2250fc97e25..bcb39e2a6965 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -57,30 +57,6 @@ struct map_groups {
57 struct machine *machine; 57 struct machine *machine;
58}; 58};
59 59
60/* Native host kernel uses -1 as pid index in machine */
61#define HOST_KERNEL_ID (-1)
62#define DEFAULT_GUEST_KERNEL_ID (0)
63
64struct machine {
65 struct rb_node rb_node;
66 pid_t pid;
67 u16 id_hdr_size;
68 char *root_dir;
69 struct rb_root threads;
70 struct list_head dead_threads;
71 struct thread *last_match;
72 struct list_head user_dsos;
73 struct list_head kernel_dsos;
74 struct map_groups kmaps;
75 struct map *vmlinux_maps[MAP__NR_TYPES];
76};
77
78static inline
79struct map *machine__kernel_map(struct machine *self, enum map_type type)
80{
81 return self->vmlinux_maps[type];
82}
83
84static inline struct kmap *map__kmap(struct map *self) 60static inline struct kmap *map__kmap(struct map *self)
85{ 61{
86 return (struct kmap *)(self + 1); 62 return (struct kmap *)(self + 1);
@@ -143,44 +119,9 @@ int map_groups__clone(struct map_groups *mg,
143size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); 119size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp);
144size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); 120size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
145 121
146typedef void (*machine__process_t)(struct machine *self, void *data);
147
148void machines__process(struct rb_root *self, machine__process_t process, void *data);
149struct machine *machines__add(struct rb_root *self, pid_t pid,
150 const char *root_dir);
151struct machine *machines__find_host(struct rb_root *self);
152struct machine *machines__find(struct rb_root *self, pid_t pid);
153struct machine *machines__findnew(struct rb_root *self, pid_t pid);
154void machines__set_id_hdr_size(struct rb_root *self, u16 id_hdr_size);
155char *machine__mmap_name(struct machine *self, char *bf, size_t size);
156int machine__init(struct machine *self, const char *root_dir, pid_t pid);
157void machine__exit(struct machine *self);
158void machine__delete(struct machine *self);
159
160struct perf_evsel;
161struct perf_sample;
162int machine__resolve_callchain(struct machine *machine,
163 struct perf_evsel *evsel,
164 struct thread *thread,
165 struct perf_sample *sample,
166 struct symbol **parent);
167int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, 122int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
168 u64 addr); 123 u64 addr);
169 124
170/*
171 * Default guest kernel is defined by parameter --guestkallsyms
172 * and --guestmodules
173 */
174static inline bool machine__is_default_guest(struct machine *self)
175{
176 return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false;
177}
178
179static inline bool machine__is_host(struct machine *self)
180{
181 return self ? self->pid == HOST_KERNEL_ID : false;
182}
183
184static inline void map_groups__insert(struct map_groups *mg, struct map *map) 125static inline void map_groups__insert(struct map_groups *mg, struct map *map)
185{ 126{
186 maps__insert(&mg->maps[map->type], map); 127 maps__insert(&mg->maps[map->type], map);
@@ -209,29 +150,6 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
209 struct map **mapp, 150 struct map **mapp,
210 symbol_filter_t filter); 151 symbol_filter_t filter);
211 152
212
213struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
214void machine__remove_thread(struct machine *machine, struct thread *th);
215
216size_t machine__fprintf(struct machine *machine, FILE *fp);
217
218static inline
219struct symbol *machine__find_kernel_symbol(struct machine *self,
220 enum map_type type, u64 addr,
221 struct map **mapp,
222 symbol_filter_t filter)
223{
224 return map_groups__find_symbol(&self->kmaps, type, addr, mapp, filter);
225}
226
227static inline
228struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
229 struct map **mapp,
230 symbol_filter_t filter)
231{
232 return machine__find_kernel_symbol(self, MAP__FUNCTION, addr, mapp, filter);
233}
234
235static inline 153static inline
236struct symbol *map_groups__find_function_by_name(struct map_groups *mg, 154struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
237 const char *name, struct map **mapp, 155 const char *name, struct map **mapp,
@@ -240,22 +158,11 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
240 return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter); 158 return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter);
241} 159}
242 160
243static inline
244struct symbol *machine__find_kernel_function_by_name(struct machine *self,
245 const char *name,
246 struct map **mapp,
247 symbol_filter_t filter)
248{
249 return map_groups__find_function_by_name(&self->kmaps, name, mapp,
250 filter);
251}
252
253int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 161int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
254 int verbose, FILE *fp); 162 int verbose, FILE *fp);
255 163
256struct map *map_groups__find_by_name(struct map_groups *mg, 164struct map *map_groups__find_by_name(struct map_groups *mg,
257 enum map_type type, const char *name); 165 enum map_type type, const char *name);
258struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
259 166
260void map_groups__flush(struct map_groups *mg); 167void map_groups__flush(struct map_groups *mg);
261 168
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6b6d03e93c3d..2d8d53bec17e 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -722,6 +722,27 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
722 return 0; 722 return 0;
723} 723}
724 724
725/*
726 * Basic modifier sanity check to validate it contains only one
727 * instance of any modifier (apart from 'p') present.
728 */
729static int check_modifier(char *str)
730{
731 char *p = str;
732
733 /* The sizeof includes 0 byte as well. */
734 if (strlen(str) > (sizeof("ukhGHppp") - 1))
735 return -1;
736
737 while (*p) {
738 if (*p != 'p' && strchr(p + 1, *p))
739 return -1;
740 p++;
741 }
742
743 return 0;
744}
745
725int parse_events__modifier_event(struct list_head *list, char *str, bool add) 746int parse_events__modifier_event(struct list_head *list, char *str, bool add)
726{ 747{
727 struct perf_evsel *evsel; 748 struct perf_evsel *evsel;
@@ -730,6 +751,9 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
730 if (str == NULL) 751 if (str == NULL)
731 return 0; 752 return 0;
732 753
754 if (check_modifier(str))
755 return -EINVAL;
756
733 if (!add && get_event_modifier(&mod, str, NULL)) 757 if (!add && get_event_modifier(&mod, str, NULL))
734 return -EINVAL; 758 return -EINVAL;
735 759
@@ -827,8 +851,6 @@ int parse_events(struct perf_evlist *evlist, const char *str,
827 * Both call perf_evlist__delete in case of error, so we dont 851 * Both call perf_evlist__delete in case of error, so we dont
828 * need to bother. 852 * need to bother.
829 */ 853 */
830 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
831 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
832 return ret; 854 return ret;
833} 855}
834 856
@@ -836,7 +858,13 @@ int parse_events_option(const struct option *opt, const char *str,
836 int unset __maybe_unused) 858 int unset __maybe_unused)
837{ 859{
838 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 860 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
839 return parse_events(evlist, str, unset); 861 int ret = parse_events(evlist, str, unset);
862
863 if (ret) {
864 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
865 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
866 }
867 return ret;
840} 868}
841 869
842int parse_filter(const struct option *opt, const char *str, 870int parse_filter(const struct option *opt, const char *str,
@@ -1081,7 +1109,7 @@ void print_events(const char *event_glob, bool name_only)
1081 printf(" %-50s [%s]\n", 1109 printf(" %-50s [%s]\n",
1082 "cpu/t1=v1[,t2=v2,t3 ...]/modifier", 1110 "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
1083 event_type_descriptors[PERF_TYPE_RAW]); 1111 event_type_descriptors[PERF_TYPE_RAW]);
1084 printf(" (see 'perf list --help' on how to encode it)\n"); 1112 printf(" (see 'man perf-list' on how to encode it)\n");
1085 printf("\n"); 1113 printf("\n");
1086 1114
1087 printf(" %-50s [%s]\n", 1115 printf(" %-50s [%s]\n",
@@ -1142,6 +1170,24 @@ int parse_events__term_str(struct parse_events__term **term,
1142 config, str, 0); 1170 config, str, 0);
1143} 1171}
1144 1172
1173int parse_events__term_sym_hw(struct parse_events__term **term,
1174 char *config, unsigned idx)
1175{
1176 struct event_symbol *sym;
1177
1178 BUG_ON(idx >= PERF_COUNT_HW_MAX);
1179 sym = &event_symbols_hw[idx];
1180
1181 if (config)
1182 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR,
1183 PARSE_EVENTS__TERM_TYPE_USER, config,
1184 (char *) sym->symbol, 0);
1185 else
1186 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR,
1187 PARSE_EVENTS__TERM_TYPE_USER,
1188 (char *) "event", (char *) sym->symbol, 0);
1189}
1190
1145int parse_events__term_clone(struct parse_events__term **new, 1191int parse_events__term_clone(struct parse_events__term **new,
1146 struct parse_events__term *term) 1192 struct parse_events__term *term)
1147{ 1193{
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 2820c407adb2..b7af80b8bdda 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -76,6 +76,8 @@ int parse_events__term_num(struct parse_events__term **_term,
76 int type_term, char *config, u64 num); 76 int type_term, char *config, u64 num);
77int parse_events__term_str(struct parse_events__term **_term, 77int parse_events__term_str(struct parse_events__term **_term,
78 int type_term, char *config, char *str); 78 int type_term, char *config, char *str);
79int parse_events__term_sym_hw(struct parse_events__term **term,
80 char *config, unsigned idx);
79int parse_events__term_clone(struct parse_events__term **new, 81int parse_events__term_clone(struct parse_events__term **new,
80 struct parse_events__term *term); 82 struct parse_events__term *term);
81void parse_events__free_terms(struct list_head *terms); 83void parse_events__free_terms(struct list_head *terms);
@@ -97,7 +99,6 @@ void parse_events__set_leader(char *name, struct list_head *list);
97void parse_events_update_lists(struct list_head *list_event, 99void parse_events_update_lists(struct list_head *list_event,
98 struct list_head *list_all); 100 struct list_head *list_all);
99void parse_events_error(void *data, void *scanner, char const *msg); 101void parse_events_error(void *data, void *scanner, char const *msg);
100int parse_events__test(void);
101 102
102void print_events(const char *event_glob, bool name_only); 103void print_events(const char *event_glob, bool name_only);
103void print_events_type(u8 type); 104void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index c87efc12579d..e9d1134c2c68 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -81,7 +81,8 @@ num_dec [0-9]+
81num_hex 0x[a-fA-F0-9]+ 81num_hex 0x[a-fA-F0-9]+
82num_raw_hex [a-fA-F0-9]+ 82num_raw_hex [a-fA-F0-9]+
83name [a-zA-Z_*?][a-zA-Z0-9_*?]* 83name [a-zA-Z_*?][a-zA-Z0-9_*?]*
84modifier_event [ukhpGH]{1,8} 84name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]*
85modifier_event [ukhpGH]+
85modifier_bp [rwx]{1,3} 86modifier_bp [rwx]{1,3}
86 87
87%% 88%%
@@ -168,6 +169,7 @@ period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
168branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } 169branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
169, { return ','; } 170, { return ','; }
170"/" { BEGIN(INITIAL); return '/'; } 171"/" { BEGIN(INITIAL); return '/'; }
172{name_minus} { return str(yyscanner, PE_NAME); }
171} 173}
172 174
173mem: { BEGIN(mem); return PE_PREFIX_MEM; } 175mem: { BEGIN(mem); return PE_PREFIX_MEM; }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index cd88209e3c58..0f9914ae6bac 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -352,6 +352,15 @@ PE_NAME '=' PE_VALUE
352 $$ = term; 352 $$ = term;
353} 353}
354| 354|
355PE_NAME '=' PE_VALUE_SYM_HW
356{
357 struct parse_events__term *term;
358 int config = $3 & 255;
359
360 ABORT_ON(parse_events__term_sym_hw(&term, $1, config));
361 $$ = term;
362}
363|
355PE_NAME 364PE_NAME
356{ 365{
357 struct parse_events__term *term; 366 struct parse_events__term *term;
@@ -361,6 +370,15 @@ PE_NAME
361 $$ = term; 370 $$ = term;
362} 371}
363| 372|
373PE_VALUE_SYM_HW
374{
375 struct parse_events__term *term;
376 int config = $1 & 255;
377
378 ABORT_ON(parse_events__term_sym_hw(&term, NULL, config));
379 $$ = term;
380}
381|
364PE_TERM '=' PE_NAME 382PE_TERM '=' PE_NAME
365{ 383{
366 struct parse_events__term *term; 384 struct parse_events__term *term;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 8a2229da594f..9bdc60c6f138 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -22,7 +22,7 @@ static LIST_HEAD(pmus);
22 * Parse & process all the sysfs attributes located under 22 * Parse & process all the sysfs attributes located under
23 * the directory specified in 'dir' parameter. 23 * the directory specified in 'dir' parameter.
24 */ 24 */
25static int pmu_format_parse(char *dir, struct list_head *head) 25int perf_pmu__format_parse(char *dir, struct list_head *head)
26{ 26{
27 struct dirent *evt_ent; 27 struct dirent *evt_ent;
28 DIR *format_dir; 28 DIR *format_dir;
@@ -77,7 +77,7 @@ static int pmu_format(char *name, struct list_head *format)
77 if (stat(path, &st) < 0) 77 if (stat(path, &st) < 0)
78 return 0; /* no error if format does not exist */ 78 return 0; /* no error if format does not exist */
79 79
80 if (pmu_format_parse(path, format)) 80 if (perf_pmu__format_parse(path, format))
81 return -1; 81 return -1;
82 82
83 return 0; 83 return 0;
@@ -164,7 +164,7 @@ static int pmu_aliases(char *name, struct list_head *head)
164 "%s/bus/event_source/devices/%s/events", sysfs, name); 164 "%s/bus/event_source/devices/%s/events", sysfs, name);
165 165
166 if (stat(path, &st) < 0) 166 if (stat(path, &st) < 0)
167 return -1; 167 return 0; /* no error if 'events' does not exist */
168 168
169 if (pmu_aliases_parse(path, head)) 169 if (pmu_aliases_parse(path, head))
170 return -1; 170 return -1;
@@ -296,6 +296,9 @@ static struct perf_pmu *pmu_lookup(char *name)
296 if (pmu_format(name, &format)) 296 if (pmu_format(name, &format))
297 return NULL; 297 return NULL;
298 298
299 if (pmu_aliases(name, &aliases))
300 return NULL;
301
299 if (pmu_type(name, &type)) 302 if (pmu_type(name, &type))
300 return NULL; 303 return NULL;
301 304
@@ -305,8 +308,6 @@ static struct perf_pmu *pmu_lookup(char *name)
305 308
306 pmu->cpus = pmu_cpumask(name); 309 pmu->cpus = pmu_cpumask(name);
307 310
308 pmu_aliases(name, &aliases);
309
310 INIT_LIST_HEAD(&pmu->format); 311 INIT_LIST_HEAD(&pmu->format);
311 INIT_LIST_HEAD(&pmu->aliases); 312 INIT_LIST_HEAD(&pmu->aliases);
312 list_splice(&format, &pmu->format); 313 list_splice(&format, &pmu->format);
@@ -445,8 +446,9 @@ static int pmu_config_term(struct list_head *formats,
445 return 0; 446 return 0;
446} 447}
447 448
448static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, 449int perf_pmu__config_terms(struct list_head *formats,
449 struct list_head *head_terms) 450 struct perf_event_attr *attr,
451 struct list_head *head_terms)
450{ 452{
451 struct parse_events__term *term; 453 struct parse_events__term *term;
452 454
@@ -466,7 +468,7 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
466 struct list_head *head_terms) 468 struct list_head *head_terms)
467{ 469{
468 attr->type = pmu->type; 470 attr->type = pmu->type;
469 return pmu_config(&pmu->format, attr, head_terms); 471 return perf_pmu__config_terms(&pmu->format, attr, head_terms);
470} 472}
471 473
472static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, 474static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
@@ -550,177 +552,3 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
550 for (b = from; b <= to; b++) 552 for (b = from; b <= to; b++)
551 set_bit(b, bits); 553 set_bit(b, bits);
552} 554}
553
554/* Simulated format definitions. */
555static struct test_format {
556 const char *name;
557 const char *value;
558} test_formats[] = {
559 { "krava01", "config:0-1,62-63\n", },
560 { "krava02", "config:10-17\n", },
561 { "krava03", "config:5\n", },
562 { "krava11", "config1:0,2,4,6,8,20-28\n", },
563 { "krava12", "config1:63\n", },
564 { "krava13", "config1:45-47\n", },
565 { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
566 { "krava22", "config2:8,18,48,58\n", },
567 { "krava23", "config2:28-29,38\n", },
568};
569
570#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
571
572/* Simulated users input. */
573static struct parse_events__term test_terms[] = {
574 {
575 .config = (char *) "krava01",
576 .val.num = 15,
577 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
578 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
579 },
580 {
581 .config = (char *) "krava02",
582 .val.num = 170,
583 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
584 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
585 },
586 {
587 .config = (char *) "krava03",
588 .val.num = 1,
589 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
590 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
591 },
592 {
593 .config = (char *) "krava11",
594 .val.num = 27,
595 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
596 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
597 },
598 {
599 .config = (char *) "krava12",
600 .val.num = 1,
601 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
602 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
603 },
604 {
605 .config = (char *) "krava13",
606 .val.num = 2,
607 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
608 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
609 },
610 {
611 .config = (char *) "krava21",
612 .val.num = 119,
613 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
614 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
615 },
616 {
617 .config = (char *) "krava22",
618 .val.num = 11,
619 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
620 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
621 },
622 {
623 .config = (char *) "krava23",
624 .val.num = 2,
625 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
626 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
627 },
628};
629#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
630
631/*
632 * Prepare format directory data, exported by kernel
633 * at /sys/bus/event_source/devices/<dev>/format.
634 */
635static char *test_format_dir_get(void)
636{
637 static char dir[PATH_MAX];
638 unsigned int i;
639
640 snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
641 if (!mkdtemp(dir))
642 return NULL;
643
644 for (i = 0; i < TEST_FORMATS_CNT; i++) {
645 static char name[PATH_MAX];
646 struct test_format *format = &test_formats[i];
647 FILE *file;
648
649 snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
650
651 file = fopen(name, "w");
652 if (!file)
653 return NULL;
654
655 if (1 != fwrite(format->value, strlen(format->value), 1, file))
656 break;
657
658 fclose(file);
659 }
660
661 return dir;
662}
663
664/* Cleanup format directory. */
665static int test_format_dir_put(char *dir)
666{
667 char buf[PATH_MAX];
668 snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
669 if (system(buf))
670 return -1;
671
672 snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
673 return system(buf);
674}
675
676static struct list_head *test_terms_list(void)
677{
678 static LIST_HEAD(terms);
679 unsigned int i;
680
681 for (i = 0; i < TERMS_CNT; i++)
682 list_add_tail(&test_terms[i].list, &terms);
683
684 return &terms;
685}
686
687#undef TERMS_CNT
688
689int perf_pmu__test(void)
690{
691 char *format = test_format_dir_get();
692 LIST_HEAD(formats);
693 struct list_head *terms = test_terms_list();
694 int ret;
695
696 if (!format)
697 return -EINVAL;
698
699 do {
700 struct perf_event_attr attr;
701
702 memset(&attr, 0, sizeof(attr));
703
704 ret = pmu_format_parse(format, &formats);
705 if (ret)
706 break;
707
708 ret = pmu_config(&formats, &attr, terms);
709 if (ret)
710 break;
711
712 ret = -EINVAL;
713
714 if (attr.config != 0xc00000000002a823)
715 break;
716 if (attr.config1 != 0x8000400000000145)
717 break;
718 if (attr.config2 != 0x0400000020041d07)
719 break;
720
721 ret = 0;
722 } while (0);
723
724 test_format_dir_put(format);
725 return ret;
726}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index fdeb8ac7c5d2..a313ed76a49a 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -37,6 +37,9 @@ struct perf_pmu {
37struct perf_pmu *perf_pmu__find(char *name); 37struct perf_pmu *perf_pmu__find(char *name);
38int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 38int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
39 struct list_head *head_terms); 39 struct list_head *head_terms);
40int perf_pmu__config_terms(struct list_head *formats,
41 struct perf_event_attr *attr,
42 struct list_head *head_terms);
40int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); 43int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
41struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 44struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
42 struct list_head *head_terms); 45 struct list_head *head_terms);
@@ -46,6 +49,7 @@ void perf_pmu_error(struct list_head *list, char *name, char const *msg);
46int perf_pmu__new_format(struct list_head *list, char *name, 49int perf_pmu__new_format(struct list_head *list, char *name,
47 int config, unsigned long *bits); 50 int config, unsigned long *bits);
48void perf_pmu__set_format(unsigned long *bits, long from, long to); 51void perf_pmu__set_format(unsigned long *bits, long from, long to);
52int perf_pmu__format_parse(char *dir, struct list_head *head);
49 53
50struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 54struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
51 55
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c
index 13d36faf64eb..daa17aeb6c63 100644
--- a/tools/perf/util/pstack.c
+++ b/tools/perf/util/pstack.c
@@ -17,59 +17,59 @@ struct pstack {
17 17
18struct pstack *pstack__new(unsigned short max_nr_entries) 18struct pstack *pstack__new(unsigned short max_nr_entries)
19{ 19{
20 struct pstack *self = zalloc((sizeof(*self) + 20 struct pstack *pstack = zalloc((sizeof(*pstack) +
21 max_nr_entries * sizeof(void *))); 21 max_nr_entries * sizeof(void *)));
22 if (self != NULL) 22 if (pstack != NULL)
23 self->max_nr_entries = max_nr_entries; 23 pstack->max_nr_entries = max_nr_entries;
24 return self; 24 return pstack;
25} 25}
26 26
27void pstack__delete(struct pstack *self) 27void pstack__delete(struct pstack *pstack)
28{ 28{
29 free(self); 29 free(pstack);
30} 30}
31 31
32bool pstack__empty(const struct pstack *self) 32bool pstack__empty(const struct pstack *pstack)
33{ 33{
34 return self->top == 0; 34 return pstack->top == 0;
35} 35}
36 36
37void pstack__remove(struct pstack *self, void *key) 37void pstack__remove(struct pstack *pstack, void *key)
38{ 38{
39 unsigned short i = self->top, last_index = self->top - 1; 39 unsigned short i = pstack->top, last_index = pstack->top - 1;
40 40
41 while (i-- != 0) { 41 while (i-- != 0) {
42 if (self->entries[i] == key) { 42 if (pstack->entries[i] == key) {
43 if (i < last_index) 43 if (i < last_index)
44 memmove(self->entries + i, 44 memmove(pstack->entries + i,
45 self->entries + i + 1, 45 pstack->entries + i + 1,
46 (last_index - i) * sizeof(void *)); 46 (last_index - i) * sizeof(void *));
47 --self->top; 47 --pstack->top;
48 return; 48 return;
49 } 49 }
50 } 50 }
51 pr_err("%s: %p not on the pstack!\n", __func__, key); 51 pr_err("%s: %p not on the pstack!\n", __func__, key);
52} 52}
53 53
54void pstack__push(struct pstack *self, void *key) 54void pstack__push(struct pstack *pstack, void *key)
55{ 55{
56 if (self->top == self->max_nr_entries) { 56 if (pstack->top == pstack->max_nr_entries) {
57 pr_err("%s: top=%d, overflow!\n", __func__, self->top); 57 pr_err("%s: top=%d, overflow!\n", __func__, pstack->top);
58 return; 58 return;
59 } 59 }
60 self->entries[self->top++] = key; 60 pstack->entries[pstack->top++] = key;
61} 61}
62 62
63void *pstack__pop(struct pstack *self) 63void *pstack__pop(struct pstack *pstack)
64{ 64{
65 void *ret; 65 void *ret;
66 66
67 if (self->top == 0) { 67 if (pstack->top == 0) {
68 pr_err("%s: underflow!\n", __func__); 68 pr_err("%s: underflow!\n", __func__);
69 return NULL; 69 return NULL;
70 } 70 }
71 71
72 ret = self->entries[--self->top]; 72 ret = pstack->entries[--pstack->top];
73 self->entries[self->top] = NULL; 73 pstack->entries[pstack->top] = NULL;
74 return ret; 74 return ret;
75} 75}
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 9181bf212fb9..a2657fd96837 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -1015,6 +1015,8 @@ PyMODINIT_FUNC initperf(void)
1015 pyrf_cpu_map__setup_types() < 0) 1015 pyrf_cpu_map__setup_types() < 0)
1016 return; 1016 return;
1017 1017
1018 page_size = sysconf(_SC_PAGE_SIZE);
1019
1018 Py_INCREF(&pyrf_evlist__type); 1020 Py_INCREF(&pyrf_evlist__type);
1019 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type); 1021 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
1020 1022
diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c
index 0171fb611004..a16cdd2625ad 100644
--- a/tools/perf/util/rblist.c
+++ b/tools/perf/util/rblist.c
@@ -44,6 +44,7 @@ int rblist__add_node(struct rblist *rblist, const void *new_entry)
44void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node) 44void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
45{ 45{
46 rb_erase(rb_node, &rblist->entries); 46 rb_erase(rb_node, &rblist->entries);
47 --rblist->nr_entries;
47 rblist->node_delete(rblist, rb_node); 48 rblist->node_delete(rblist, rb_node);
48} 49}
49 50
@@ -87,8 +88,7 @@ void rblist__delete(struct rblist *rblist)
87 while (next) { 88 while (next) {
88 pos = next; 89 pos = next;
89 next = rb_next(pos); 90 next = rb_next(pos);
90 rb_erase(pos, &rblist->entries); 91 rblist__remove_node(rblist, pos);
91 rblist->node_delete(rblist, pos);
92 } 92 }
93 free(rblist); 93 free(rblist);
94 } 94 }
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 730c6630cba5..14683dfca2ee 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -32,7 +32,6 @@
32#include "../event.h" 32#include "../event.h"
33#include "../thread.h" 33#include "../thread.h"
34#include "../trace-event.h" 34#include "../trace-event.h"
35#include "../evsel.h"
36 35
37PyMODINIT_FUNC initperf_trace_context(void); 36PyMODINIT_FUNC initperf_trace_context(void);
38 37
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 8cdd23239c90..ce6f51162386 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1375,15 +1375,13 @@ int __perf_session__process_events(struct perf_session *session,
1375{ 1375{
1376 u64 head, page_offset, file_offset, file_pos, progress_next; 1376 u64 head, page_offset, file_offset, file_pos, progress_next;
1377 int err, mmap_prot, mmap_flags, map_idx = 0; 1377 int err, mmap_prot, mmap_flags, map_idx = 0;
1378 size_t page_size, mmap_size; 1378 size_t mmap_size;
1379 char *buf, *mmaps[8]; 1379 char *buf, *mmaps[8];
1380 union perf_event *event; 1380 union perf_event *event;
1381 uint32_t size; 1381 uint32_t size;
1382 1382
1383 perf_tool__fill_defaults(tool); 1383 perf_tool__fill_defaults(tool);
1384 1384
1385 page_size = sysconf(_SC_PAGESIZE);
1386
1387 page_offset = page_size * (data_offset / page_size); 1385 page_offset = page_size * (data_offset / page_size);
1388 file_offset = page_offset; 1386 file_offset = page_offset;
1389 head = data_offset - page_offset; 1387 head = data_offset - page_offset;
@@ -1460,6 +1458,7 @@ more:
1460 session->ordered_samples.next_flush = ULLONG_MAX; 1458 session->ordered_samples.next_flush = ULLONG_MAX;
1461 err = flush_sample_queue(session, tool); 1459 err = flush_sample_queue(session, tool);
1462out_err: 1460out_err:
1461 ui_progress__finish();
1463 perf_session__warn_about_errors(session, tool); 1462 perf_session__warn_about_errors(session, tool);
1464 perf_session_free_sample_buffers(session); 1463 perf_session_free_sample_buffers(session);
1465 return err; 1464 return err;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 0eae00ad5fe7..cea133a6bdf1 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -4,6 +4,7 @@
4#include "hist.h" 4#include "hist.h"
5#include "event.h" 5#include "event.h"
6#include "header.h" 6#include "header.h"
7#include "machine.h"
7#include "symbol.h" 8#include "symbol.h"
8#include "thread.h" 9#include "thread.h"
9#include <linux/rbtree.h> 10#include <linux/rbtree.h>
@@ -68,10 +69,6 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel
68 struct ip_callchain *chain, 69 struct ip_callchain *chain,
69 struct symbol **parent); 70 struct symbol **parent);
70 71
71struct branch_info *machine__resolve_bstack(struct machine *self,
72 struct thread *thread,
73 struct branch_stack *bs);
74
75bool perf_session__has_traces(struct perf_session *self, const char *msg); 72bool perf_session__has_traces(struct perf_session *self, const char *msg);
76 73
77void mem_bswap_64(void *src, int byte_size); 74void mem_bswap_64(void *src, int byte_size);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 5786f323b597..b4e8c3ba559d 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -52,6 +52,22 @@ struct he_stat {
52 u32 nr_events; 52 u32 nr_events;
53}; 53};
54 54
55struct hist_entry_diff {
56 bool computed;
57
58 /* PERF_HPP__DISPL */
59 int displacement;
60
61 /* PERF_HPP__DELTA */
62 double period_ratio_delta;
63
64 /* PERF_HPP__RATIO */
65 double period_ratio;
66
67 /* HISTC_WEIGHTED_DIFF */
68 s64 wdiff;
69};
70
55/** 71/**
56 * struct hist_entry - histogram entry 72 * struct hist_entry - histogram entry
57 * 73 *
@@ -61,12 +77,18 @@ struct he_stat {
61struct hist_entry { 77struct hist_entry {
62 struct rb_node rb_node_in; 78 struct rb_node rb_node_in;
63 struct rb_node rb_node; 79 struct rb_node rb_node;
80 union {
81 struct list_head node;
82 struct list_head head;
83 } pairs;
64 struct he_stat stat; 84 struct he_stat stat;
65 struct map_symbol ms; 85 struct map_symbol ms;
66 struct thread *thread; 86 struct thread *thread;
67 u64 ip; 87 u64 ip;
68 s32 cpu; 88 s32 cpu;
69 89
90 struct hist_entry_diff diff;
91
70 /* XXX These two should move to some tree widget lib */ 92 /* XXX These two should move to some tree widget lib */
71 u16 row_offset; 93 u16 row_offset;
72 u16 nr_rows; 94 u16 nr_rows;
@@ -78,15 +100,30 @@ struct hist_entry {
78 char *srcline; 100 char *srcline;
79 struct symbol *parent; 101 struct symbol *parent;
80 unsigned long position; 102 unsigned long position;
81 union { 103 struct rb_root sorted_chain;
82 struct hist_entry *pair;
83 struct rb_root sorted_chain;
84 };
85 struct branch_info *branch_info; 104 struct branch_info *branch_info;
86 struct hists *hists; 105 struct hists *hists;
87 struct callchain_root callchain[0]; 106 struct callchain_root callchain[0];
88}; 107};
89 108
109static inline bool hist_entry__has_pairs(struct hist_entry *he)
110{
111 return !list_empty(&he->pairs.node);
112}
113
114static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
115{
116 if (hist_entry__has_pairs(he))
117 return list_entry(he->pairs.node.next, struct hist_entry, pairs.node);
118 return NULL;
119}
120
121static inline void hist__entry_add_pair(struct hist_entry *he,
122 struct hist_entry *pair)
123{
124 list_add_tail(&he->pairs.head, &pair->pairs.node);
125}
126
90enum sort_type { 127enum sort_type {
91 SORT_PID, 128 SORT_PID,
92 SORT_COMM, 129 SORT_COMM,
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 32170590892d..346707df04b9 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -314,6 +314,24 @@ int strtailcmp(const char *s1, const char *s2)
314} 314}
315 315
316/** 316/**
317 * strxfrchar - Locate and replace character in @s
318 * @s: The string to be searched/changed.
319 * @from: Source character to be replaced.
320 * @to: Destination character.
321 *
322 * Return pointer to the changed string.
323 */
324char *strxfrchar(char *s, char from, char to)
325{
326 char *p = s;
327
328 while ((p = strchr(p, from)) != NULL)
329 *p++ = to;
330
331 return s;
332}
333
334/**
317 * rtrim - Removes trailing whitespace from @s. 335 * rtrim - Removes trailing whitespace from @s.
318 * @s: The string to be stripped. 336 * @s: The string to be stripped.
319 * 337 *
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e2e8c697cffe..295f8d4feedf 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -12,6 +12,7 @@
12#include "build-id.h" 12#include "build-id.h"
13#include "util.h" 13#include "util.h"
14#include "debug.h" 14#include "debug.h"
15#include "machine.h"
15#include "symbol.h" 16#include "symbol.h"
16#include "strlist.h" 17#include "strlist.h"
17 18
@@ -23,7 +24,6 @@
23#define KSYM_NAME_LEN 256 24#define KSYM_NAME_LEN 256
24#endif 25#endif
25 26
26static void dso_cache__free(struct rb_root *root);
27static int dso__load_kernel_sym(struct dso *dso, struct map *map, 27static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 28 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
@@ -56,39 +56,6 @@ static enum dso_binary_type binary_type_symtab[] = {
56 56
57#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 57#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
58 58
59static enum dso_binary_type binary_type_data[] = {
60 DSO_BINARY_TYPE__BUILD_ID_CACHE,
61 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
62 DSO_BINARY_TYPE__NOT_FOUND,
63};
64
65#define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data)
66
67int dso__name_len(const struct dso *dso)
68{
69 if (!dso)
70 return strlen("[unknown]");
71 if (verbose)
72 return dso->long_name_len;
73
74 return dso->short_name_len;
75}
76
77bool dso__loaded(const struct dso *dso, enum map_type type)
78{
79 return dso->loaded & (1 << type);
80}
81
82bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
83{
84 return dso->sorted_by_name & (1 << type);
85}
86
87static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
88{
89 dso->sorted_by_name |= (1 << type);
90}
91
92bool symbol_type__is_a(char symbol_type, enum map_type map_type) 59bool symbol_type__is_a(char symbol_type, enum map_type map_type)
93{ 60{
94 symbol_type = toupper(symbol_type); 61 symbol_type = toupper(symbol_type);
@@ -270,7 +237,7 @@ void symbol__delete(struct symbol *sym)
270 free(((void *)sym) - symbol_conf.priv_size); 237 free(((void *)sym) - symbol_conf.priv_size);
271} 238}
272 239
273static size_t symbol__fprintf(struct symbol *sym, FILE *fp) 240size_t symbol__fprintf(struct symbol *sym, FILE *fp)
274{ 241{
275 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 242 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
276 sym->start, sym->end, 243 sym->start, sym->end,
@@ -301,53 +268,7 @@ size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
301 return symbol__fprintf_symname_offs(sym, NULL, fp); 268 return symbol__fprintf_symname_offs(sym, NULL, fp);
302} 269}
303 270
304void dso__set_long_name(struct dso *dso, char *name) 271void symbols__delete(struct rb_root *symbols)
305{
306 if (name == NULL)
307 return;
308 dso->long_name = name;
309 dso->long_name_len = strlen(name);
310}
311
312static void dso__set_short_name(struct dso *dso, const char *name)
313{
314 if (name == NULL)
315 return;
316 dso->short_name = name;
317 dso->short_name_len = strlen(name);
318}
319
320static void dso__set_basename(struct dso *dso)
321{
322 dso__set_short_name(dso, basename(dso->long_name));
323}
324
325struct dso *dso__new(const char *name)
326{
327 struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
328
329 if (dso != NULL) {
330 int i;
331 strcpy(dso->name, name);
332 dso__set_long_name(dso, dso->name);
333 dso__set_short_name(dso, dso->name);
334 for (i = 0; i < MAP__NR_TYPES; ++i)
335 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
336 dso->cache = RB_ROOT;
337 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
338 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
339 dso->loaded = 0;
340 dso->sorted_by_name = 0;
341 dso->has_build_id = 0;
342 dso->kernel = DSO_TYPE_USER;
343 dso->needs_swap = DSO_SWAP__UNSET;
344 INIT_LIST_HEAD(&dso->node);
345 }
346
347 return dso;
348}
349
350static void symbols__delete(struct rb_root *symbols)
351{ 272{
352 struct symbol *pos; 273 struct symbol *pos;
353 struct rb_node *next = rb_first(symbols); 274 struct rb_node *next = rb_first(symbols);
@@ -360,25 +281,6 @@ static void symbols__delete(struct rb_root *symbols)
360 } 281 }
361} 282}
362 283
363void dso__delete(struct dso *dso)
364{
365 int i;
366 for (i = 0; i < MAP__NR_TYPES; ++i)
367 symbols__delete(&dso->symbols[i]);
368 if (dso->sname_alloc)
369 free((char *)dso->short_name);
370 if (dso->lname_alloc)
371 free(dso->long_name);
372 dso_cache__free(&dso->cache);
373 free(dso);
374}
375
376void dso__set_build_id(struct dso *dso, void *build_id)
377{
378 memcpy(dso->build_id, build_id, sizeof(dso->build_id));
379 dso->has_build_id = 1;
380}
381
382void symbols__insert(struct rb_root *symbols, struct symbol *sym) 284void symbols__insert(struct rb_root *symbols, struct symbol *sym)
383{ 285{
384 struct rb_node **p = &symbols->rb_node; 286 struct rb_node **p = &symbols->rb_node;
@@ -504,29 +406,6 @@ void dso__sort_by_name(struct dso *dso, enum map_type type)
504 &dso->symbols[type]); 406 &dso->symbols[type]);
505} 407}
506 408
507int build_id__sprintf(const u8 *build_id, int len, char *bf)
508{
509 char *bid = bf;
510 const u8 *raw = build_id;
511 int i;
512
513 for (i = 0; i < len; ++i) {
514 sprintf(bid, "%02x", *raw);
515 ++raw;
516 bid += 2;
517 }
518
519 return raw - build_id;
520}
521
522size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
523{
524 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
525
526 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
527 return fprintf(fp, "%s", sbuild_id);
528}
529
530size_t dso__fprintf_symbols_by_name(struct dso *dso, 409size_t dso__fprintf_symbols_by_name(struct dso *dso,
531 enum map_type type, FILE *fp) 410 enum map_type type, FILE *fp)
532{ 411{
@@ -542,25 +421,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
542 return ret; 421 return ret;
543} 422}
544 423
545size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
546{
547 struct rb_node *nd;
548 size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
549
550 if (dso->short_name != dso->long_name)
551 ret += fprintf(fp, "%s, ", dso->long_name);
552 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
553 dso->loaded ? "" : "NOT ");
554 ret += dso__fprintf_buildid(dso, fp);
555 ret += fprintf(fp, ")\n");
556 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
557 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
558 ret += symbol__fprintf(pos, fp);
559 }
560
561 return ret;
562}
563
564int kallsyms__parse(const char *filename, void *arg, 424int kallsyms__parse(const char *filename, void *arg,
565 int (*process_symbol)(void *arg, const char *name, 425 int (*process_symbol)(void *arg, const char *name,
566 char type, u64 start)) 426 char type, u64 start))
@@ -892,136 +752,6 @@ out_failure:
892 return -1; 752 return -1;
893} 753}
894 754
895bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
896{
897 return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
898}
899
900bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
901{
902 bool have_build_id = false;
903 struct dso *pos;
904
905 list_for_each_entry(pos, head, node) {
906 if (with_hits && !pos->hit)
907 continue;
908 if (pos->has_build_id) {
909 have_build_id = true;
910 continue;
911 }
912 if (filename__read_build_id(pos->long_name, pos->build_id,
913 sizeof(pos->build_id)) > 0) {
914 have_build_id = true;
915 pos->has_build_id = true;
916 }
917 }
918
919 return have_build_id;
920}
921
922char dso__symtab_origin(const struct dso *dso)
923{
924 static const char origin[] = {
925 [DSO_BINARY_TYPE__KALLSYMS] = 'k',
926 [DSO_BINARY_TYPE__VMLINUX] = 'v',
927 [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
928 [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
929 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
930 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
931 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
932 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
933 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
934 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
935 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
936 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
937 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
938 };
939
940 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
941 return '!';
942 return origin[dso->symtab_type];
943}
944
945int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
946 char *root_dir, char *file, size_t size)
947{
948 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
949 int ret = 0;
950
951 switch (type) {
952 case DSO_BINARY_TYPE__DEBUGLINK: {
953 char *debuglink;
954
955 strncpy(file, dso->long_name, size);
956 debuglink = file + dso->long_name_len;
957 while (debuglink != file && *debuglink != '/')
958 debuglink--;
959 if (*debuglink == '/')
960 debuglink++;
961 filename__read_debuglink(dso->long_name, debuglink,
962 size - (debuglink - file));
963 }
964 break;
965 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
966 /* skip the locally configured cache if a symfs is given */
967 if (symbol_conf.symfs[0] ||
968 (dso__build_id_filename(dso, file, size) == NULL))
969 ret = -1;
970 break;
971
972 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
973 snprintf(file, size, "%s/usr/lib/debug%s.debug",
974 symbol_conf.symfs, dso->long_name);
975 break;
976
977 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
978 snprintf(file, size, "%s/usr/lib/debug%s",
979 symbol_conf.symfs, dso->long_name);
980 break;
981
982 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
983 if (!dso->has_build_id) {
984 ret = -1;
985 break;
986 }
987
988 build_id__sprintf(dso->build_id,
989 sizeof(dso->build_id),
990 build_id_hex);
991 snprintf(file, size,
992 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
993 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
994 break;
995
996 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
997 snprintf(file, size, "%s%s",
998 symbol_conf.symfs, dso->long_name);
999 break;
1000
1001 case DSO_BINARY_TYPE__GUEST_KMODULE:
1002 snprintf(file, size, "%s%s%s", symbol_conf.symfs,
1003 root_dir, dso->long_name);
1004 break;
1005
1006 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1007 snprintf(file, size, "%s%s", symbol_conf.symfs,
1008 dso->long_name);
1009 break;
1010
1011 default:
1012 case DSO_BINARY_TYPE__KALLSYMS:
1013 case DSO_BINARY_TYPE__VMLINUX:
1014 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
1015 case DSO_BINARY_TYPE__GUEST_VMLINUX:
1016 case DSO_BINARY_TYPE__JAVA_JIT:
1017 case DSO_BINARY_TYPE__NOT_FOUND:
1018 ret = -1;
1019 break;
1020 }
1021
1022 return ret;
1023}
1024
1025int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 755int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1026{ 756{
1027 char *name; 757 char *name;
@@ -1157,27 +887,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
1157 return NULL; 887 return NULL;
1158} 888}
1159 889
1160static int dso__kernel_module_get_build_id(struct dso *dso,
1161 const char *root_dir)
1162{
1163 char filename[PATH_MAX];
1164 /*
1165 * kernel module short names are of the form "[module]" and
1166 * we need just "module" here.
1167 */
1168 const char *name = dso->short_name + 1;
1169
1170 snprintf(filename, sizeof(filename),
1171 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1172 root_dir, (int)strlen(name) - 1, name);
1173
1174 if (sysfs__read_build_id(filename, dso->build_id,
1175 sizeof(dso->build_id)) == 0)
1176 dso->has_build_id = true;
1177
1178 return 0;
1179}
1180
1181static int map_groups__set_modules_path_dir(struct map_groups *mg, 890static int map_groups__set_modules_path_dir(struct map_groups *mg,
1182 const char *dir_name) 891 const char *dir_name)
1183{ 892{
@@ -1591,50 +1300,6 @@ out_try_fixup:
1591 return err; 1300 return err;
1592} 1301}
1593 1302
1594void dsos__add(struct list_head *head, struct dso *dso)
1595{
1596 list_add_tail(&dso->node, head);
1597}
1598
1599struct dso *dsos__find(struct list_head *head, const char *name)
1600{
1601 struct dso *pos;
1602
1603 list_for_each_entry(pos, head, node)
1604 if (strcmp(pos->long_name, name) == 0)
1605 return pos;
1606 return NULL;
1607}
1608
1609struct dso *__dsos__findnew(struct list_head *head, const char *name)
1610{
1611 struct dso *dso = dsos__find(head, name);
1612
1613 if (!dso) {
1614 dso = dso__new(name);
1615 if (dso != NULL) {
1616 dsos__add(head, dso);
1617 dso__set_basename(dso);
1618 }
1619 }
1620
1621 return dso;
1622}
1623
1624size_t __dsos__fprintf(struct list_head *head, FILE *fp)
1625{
1626 struct dso *pos;
1627 size_t ret = 0;
1628
1629 list_for_each_entry(pos, head, node) {
1630 int i;
1631 for (i = 0; i < MAP__NR_TYPES; ++i)
1632 ret += dso__fprintf(pos, i, fp);
1633 }
1634
1635 return ret;
1636}
1637
1638size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) 1303size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
1639{ 1304{
1640 struct rb_node *nd; 1305 struct rb_node *nd;
@@ -1649,21 +1314,6 @@ size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
1649 return ret; 1314 return ret;
1650} 1315}
1651 1316
1652static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1653 bool with_hits)
1654{
1655 struct dso *pos;
1656 size_t ret = 0;
1657
1658 list_for_each_entry(pos, head, node) {
1659 if (with_hits && !pos->hit)
1660 continue;
1661 ret += dso__fprintf_buildid(pos, fp);
1662 ret += fprintf(fp, " %s\n", pos->long_name);
1663 }
1664 return ret;
1665}
1666
1667size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 1317size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
1668 bool with_hits) 1318 bool with_hits)
1669{ 1319{
@@ -1684,39 +1334,6 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
1684 return ret; 1334 return ret;
1685} 1335}
1686 1336
1687static struct dso*
1688dso__kernel_findnew(struct machine *machine, const char *name,
1689 const char *short_name, int dso_type)
1690{
1691 /*
1692 * The kernel dso could be created by build_id processing.
1693 */
1694 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
1695
1696 /*
1697 * We need to run this in all cases, since during the build_id
1698 * processing we had no idea this was the kernel dso.
1699 */
1700 if (dso != NULL) {
1701 dso__set_short_name(dso, short_name);
1702 dso->kernel = dso_type;
1703 }
1704
1705 return dso;
1706}
1707
1708void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
1709{
1710 char path[PATH_MAX];
1711
1712 if (machine__is_default_guest(machine))
1713 return;
1714 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
1715 if (sysfs__read_build_id(path, dso->build_id,
1716 sizeof(dso->build_id)) == 0)
1717 dso->has_build_id = true;
1718}
1719
1720static struct dso *machine__get_kernel(struct machine *machine) 1337static struct dso *machine__get_kernel(struct machine *machine)
1721{ 1338{
1722 const char *vmlinux_name = NULL; 1339 const char *vmlinux_name = NULL;
@@ -2065,49 +1682,6 @@ int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
2065 return machine__create_kernel_maps(machine); 1682 return machine__create_kernel_maps(machine);
2066} 1683}
2067 1684
2068static int hex(char ch)
2069{
2070 if ((ch >= '0') && (ch <= '9'))
2071 return ch - '0';
2072 if ((ch >= 'a') && (ch <= 'f'))
2073 return ch - 'a' + 10;
2074 if ((ch >= 'A') && (ch <= 'F'))
2075 return ch - 'A' + 10;
2076 return -1;
2077}
2078
2079/*
2080 * While we find nice hex chars, build a long_val.
2081 * Return number of chars processed.
2082 */
2083int hex2u64(const char *ptr, u64 *long_val)
2084{
2085 const char *p = ptr;
2086 *long_val = 0;
2087
2088 while (*p) {
2089 const int hex_val = hex(*p);
2090
2091 if (hex_val < 0)
2092 break;
2093
2094 *long_val = (*long_val << 4) | hex_val;
2095 p++;
2096 }
2097
2098 return p - ptr;
2099}
2100
2101char *strxfrchar(char *s, char from, char to)
2102{
2103 char *p = s;
2104
2105 while ((p = strchr(p, from)) != NULL)
2106 *p++ = to;
2107
2108 return s;
2109}
2110
2111int machines__create_guest_kernel_maps(struct rb_root *machines) 1685int machines__create_guest_kernel_maps(struct rb_root *machines)
2112{ 1686{
2113 int ret = 0; 1687 int ret = 0;
@@ -2202,229 +1776,3 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
2202 1776
2203 return ret; 1777 return ret;
2204} 1778}
2205
2206struct map *dso__new_map(const char *name)
2207{
2208 struct map *map = NULL;
2209 struct dso *dso = dso__new(name);
2210
2211 if (dso)
2212 map = map__new2(0, dso, MAP__FUNCTION);
2213
2214 return map;
2215}
2216
2217static int open_dso(struct dso *dso, struct machine *machine)
2218{
2219 char *root_dir = (char *) "";
2220 char *name;
2221 int fd;
2222
2223 name = malloc(PATH_MAX);
2224 if (!name)
2225 return -ENOMEM;
2226
2227 if (machine)
2228 root_dir = machine->root_dir;
2229
2230 if (dso__binary_type_file(dso, dso->data_type,
2231 root_dir, name, PATH_MAX)) {
2232 free(name);
2233 return -EINVAL;
2234 }
2235
2236 fd = open(name, O_RDONLY);
2237 free(name);
2238 return fd;
2239}
2240
2241int dso__data_fd(struct dso *dso, struct machine *machine)
2242{
2243 int i = 0;
2244
2245 if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
2246 return open_dso(dso, machine);
2247
2248 do {
2249 int fd;
2250
2251 dso->data_type = binary_type_data[i++];
2252
2253 fd = open_dso(dso, machine);
2254 if (fd >= 0)
2255 return fd;
2256
2257 } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
2258
2259 return -EINVAL;
2260}
2261
2262static void
2263dso_cache__free(struct rb_root *root)
2264{
2265 struct rb_node *next = rb_first(root);
2266
2267 while (next) {
2268 struct dso_cache *cache;
2269
2270 cache = rb_entry(next, struct dso_cache, rb_node);
2271 next = rb_next(&cache->rb_node);
2272 rb_erase(&cache->rb_node, root);
2273 free(cache);
2274 }
2275}
2276
2277static struct dso_cache*
2278dso_cache__find(struct rb_root *root, u64 offset)
2279{
2280 struct rb_node **p = &root->rb_node;
2281 struct rb_node *parent = NULL;
2282 struct dso_cache *cache;
2283
2284 while (*p != NULL) {
2285 u64 end;
2286
2287 parent = *p;
2288 cache = rb_entry(parent, struct dso_cache, rb_node);
2289 end = cache->offset + DSO__DATA_CACHE_SIZE;
2290
2291 if (offset < cache->offset)
2292 p = &(*p)->rb_left;
2293 else if (offset >= end)
2294 p = &(*p)->rb_right;
2295 else
2296 return cache;
2297 }
2298 return NULL;
2299}
2300
2301static void
2302dso_cache__insert(struct rb_root *root, struct dso_cache *new)
2303{
2304 struct rb_node **p = &root->rb_node;
2305 struct rb_node *parent = NULL;
2306 struct dso_cache *cache;
2307 u64 offset = new->offset;
2308
2309 while (*p != NULL) {
2310 u64 end;
2311
2312 parent = *p;
2313 cache = rb_entry(parent, struct dso_cache, rb_node);
2314 end = cache->offset + DSO__DATA_CACHE_SIZE;
2315
2316 if (offset < cache->offset)
2317 p = &(*p)->rb_left;
2318 else if (offset >= end)
2319 p = &(*p)->rb_right;
2320 }
2321
2322 rb_link_node(&new->rb_node, parent, p);
2323 rb_insert_color(&new->rb_node, root);
2324}
2325
2326static ssize_t
2327dso_cache__memcpy(struct dso_cache *cache, u64 offset,
2328 u8 *data, u64 size)
2329{
2330 u64 cache_offset = offset - cache->offset;
2331 u64 cache_size = min(cache->size - cache_offset, size);
2332
2333 memcpy(data, cache->data + cache_offset, cache_size);
2334 return cache_size;
2335}
2336
2337static ssize_t
2338dso_cache__read(struct dso *dso, struct machine *machine,
2339 u64 offset, u8 *data, ssize_t size)
2340{
2341 struct dso_cache *cache;
2342 ssize_t ret;
2343 int fd;
2344
2345 fd = dso__data_fd(dso, machine);
2346 if (fd < 0)
2347 return -1;
2348
2349 do {
2350 u64 cache_offset;
2351
2352 ret = -ENOMEM;
2353
2354 cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
2355 if (!cache)
2356 break;
2357
2358 cache_offset = offset & DSO__DATA_CACHE_MASK;
2359 ret = -EINVAL;
2360
2361 if (-1 == lseek(fd, cache_offset, SEEK_SET))
2362 break;
2363
2364 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
2365 if (ret <= 0)
2366 break;
2367
2368 cache->offset = cache_offset;
2369 cache->size = ret;
2370 dso_cache__insert(&dso->cache, cache);
2371
2372 ret = dso_cache__memcpy(cache, offset, data, size);
2373
2374 } while (0);
2375
2376 if (ret <= 0)
2377 free(cache);
2378
2379 close(fd);
2380 return ret;
2381}
2382
2383static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
2384 u64 offset, u8 *data, ssize_t size)
2385{
2386 struct dso_cache *cache;
2387
2388 cache = dso_cache__find(&dso->cache, offset);
2389 if (cache)
2390 return dso_cache__memcpy(cache, offset, data, size);
2391 else
2392 return dso_cache__read(dso, machine, offset, data, size);
2393}
2394
2395ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
2396 u64 offset, u8 *data, ssize_t size)
2397{
2398 ssize_t r = 0;
2399 u8 *p = data;
2400
2401 do {
2402 ssize_t ret;
2403
2404 ret = dso_cache_read(dso, machine, offset, p, size);
2405 if (ret < 0)
2406 return ret;
2407
2408 /* Reached EOF, return what we have. */
2409 if (!ret)
2410 break;
2411
2412 BUG_ON(ret > size);
2413
2414 r += ret;
2415 p += ret;
2416 offset += ret;
2417 size -= ret;
2418
2419 } while (size);
2420
2421 return r;
2422}
2423
2424ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
2425 struct machine *machine, u64 addr,
2426 u8 *data, ssize_t size)
2427{
2428 u64 offset = map->map_ip(map, addr);
2429 return dso__data_read_offset(dso, machine, offset, data, size);
2430}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8b6ef7fac745..de68f98b236d 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -11,6 +11,7 @@
11#include <stdio.h> 11#include <stdio.h>
12#include <byteswap.h> 12#include <byteswap.h>
13#include <libgen.h> 13#include <libgen.h>
14#include "build-id.h"
14 15
15#ifdef LIBELF_SUPPORT 16#ifdef LIBELF_SUPPORT
16#include <libelf.h> 17#include <libelf.h>
@@ -18,6 +19,8 @@
18#include <elf.h> 19#include <elf.h>
19#endif 20#endif
20 21
22#include "dso.h"
23
21#ifdef HAVE_CPLUS_DEMANGLE 24#ifdef HAVE_CPLUS_DEMANGLE
22extern char *cplus_demangle(const char *, int); 25extern char *cplus_demangle(const char *, int);
23 26
@@ -39,9 +42,6 @@ static inline char *bfd_demangle(void __maybe_unused *v,
39#endif 42#endif
40#endif 43#endif
41 44
42int hex2u64(const char *ptr, u64 *val);
43char *strxfrchar(char *s, char from, char to);
44
45/* 45/*
46 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; 46 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
47 * for newer versions we can use mmap to reduce memory usage: 47 * for newer versions we can use mmap to reduce memory usage:
@@ -57,8 +57,6 @@ char *strxfrchar(char *s, char from, char to);
57#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 57#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
58#endif 58#endif
59 59
60#define BUILD_ID_SIZE 20
61
62/** struct symbol - symtab entry 60/** struct symbol - symtab entry
63 * 61 *
64 * @ignore - resolvable but tools ignore it (e.g. idle routines) 62 * @ignore - resolvable but tools ignore it (e.g. idle routines)
@@ -74,6 +72,7 @@ struct symbol {
74}; 72};
75 73
76void symbol__delete(struct symbol *sym); 74void symbol__delete(struct symbol *sym);
75void symbols__delete(struct rb_root *symbols);
77 76
78static inline size_t symbol__size(const struct symbol *sym) 77static inline size_t symbol__size(const struct symbol *sym)
79{ 78{
@@ -164,70 +163,6 @@ struct addr_location {
164 s32 cpu; 163 s32 cpu;
165}; 164};
166 165
167enum dso_binary_type {
168 DSO_BINARY_TYPE__KALLSYMS = 0,
169 DSO_BINARY_TYPE__GUEST_KALLSYMS,
170 DSO_BINARY_TYPE__VMLINUX,
171 DSO_BINARY_TYPE__GUEST_VMLINUX,
172 DSO_BINARY_TYPE__JAVA_JIT,
173 DSO_BINARY_TYPE__DEBUGLINK,
174 DSO_BINARY_TYPE__BUILD_ID_CACHE,
175 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
176 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
177 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
178 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
179 DSO_BINARY_TYPE__GUEST_KMODULE,
180 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
181 DSO_BINARY_TYPE__NOT_FOUND,
182};
183
184enum dso_kernel_type {
185 DSO_TYPE_USER = 0,
186 DSO_TYPE_KERNEL,
187 DSO_TYPE_GUEST_KERNEL
188};
189
190enum dso_swap_type {
191 DSO_SWAP__UNSET,
192 DSO_SWAP__NO,
193 DSO_SWAP__YES,
194};
195
196#define DSO__DATA_CACHE_SIZE 4096
197#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
198
199struct dso_cache {
200 struct rb_node rb_node;
201 u64 offset;
202 u64 size;
203 char data[0];
204};
205
206struct dso {
207 struct list_head node;
208 struct rb_root symbols[MAP__NR_TYPES];
209 struct rb_root symbol_names[MAP__NR_TYPES];
210 struct rb_root cache;
211 enum dso_kernel_type kernel;
212 enum dso_swap_type needs_swap;
213 enum dso_binary_type symtab_type;
214 enum dso_binary_type data_type;
215 u8 adjust_symbols:1;
216 u8 has_build_id:1;
217 u8 hit:1;
218 u8 annotate_warned:1;
219 u8 sname_alloc:1;
220 u8 lname_alloc:1;
221 u8 sorted_by_name;
222 u8 loaded;
223 u8 build_id[BUILD_ID_SIZE];
224 const char *short_name;
225 char *long_name;
226 u16 long_name_len;
227 u16 short_name_len;
228 char name[0];
229};
230
231struct symsrc { 166struct symsrc {
232 char *name; 167 char *name;
233 int fd; 168 int fd;
@@ -258,47 +193,6 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
258bool symsrc__has_symtab(struct symsrc *ss); 193bool symsrc__has_symtab(struct symsrc *ss);
259bool symsrc__possibly_runtime(struct symsrc *ss); 194bool symsrc__possibly_runtime(struct symsrc *ss);
260 195
261#define DSO__SWAP(dso, type, val) \
262({ \
263 type ____r = val; \
264 BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \
265 if (dso->needs_swap == DSO_SWAP__YES) { \
266 switch (sizeof(____r)) { \
267 case 2: \
268 ____r = bswap_16(val); \
269 break; \
270 case 4: \
271 ____r = bswap_32(val); \
272 break; \
273 case 8: \
274 ____r = bswap_64(val); \
275 break; \
276 default: \
277 BUG_ON(1); \
278 } \
279 } \
280 ____r; \
281})
282
283struct dso *dso__new(const char *name);
284void dso__delete(struct dso *dso);
285
286int dso__name_len(const struct dso *dso);
287
288bool dso__loaded(const struct dso *dso, enum map_type type);
289bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
290
291static inline void dso__set_loaded(struct dso *dso, enum map_type type)
292{
293 dso->loaded |= (1 << type);
294}
295
296void dso__sort_by_name(struct dso *dso, enum map_type type);
297
298void dsos__add(struct list_head *head, struct dso *dso);
299struct dso *dsos__find(struct list_head *head, const char *name);
300struct dso *__dsos__findnew(struct list_head *head, const char *name);
301
302int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); 196int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
303int dso__load_vmlinux(struct dso *dso, struct map *map, 197int dso__load_vmlinux(struct dso *dso, struct map *map,
304 const char *vmlinux, symbol_filter_t filter); 198 const char *vmlinux, symbol_filter_t filter);
@@ -306,30 +200,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
306 symbol_filter_t filter); 200 symbol_filter_t filter);
307int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, 201int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
308 symbol_filter_t filter); 202 symbol_filter_t filter);
309int machine__load_kallsyms(struct machine *machine, const char *filename, 203
310 enum map_type type, symbol_filter_t filter);
311int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
312 symbol_filter_t filter);
313
314size_t __dsos__fprintf(struct list_head *head, FILE *fp);
315
316size_t machine__fprintf_dsos_buildid(struct machine *machine,
317 FILE *fp, bool with_hits);
318size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
319size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
320 FILE *fp, bool with_hits);
321size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
322size_t dso__fprintf_symbols_by_name(struct dso *dso,
323 enum map_type type, FILE *fp);
324size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
325
326char dso__symtab_origin(const struct dso *dso);
327void dso__set_long_name(struct dso *dso, char *name);
328void dso__set_build_id(struct dso *dso, void *build_id);
329bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
330void dso__read_running_kernel_build_id(struct dso *dso,
331 struct machine *machine);
332struct map *dso__new_map(const char *name);
333struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, 204struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
334 u64 addr); 205 u64 addr);
335struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 206struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
@@ -337,22 +208,12 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
337 208
338int filename__read_build_id(const char *filename, void *bf, size_t size); 209int filename__read_build_id(const char *filename, void *bf, size_t size);
339int sysfs__read_build_id(const char *filename, void *bf, size_t size); 210int sysfs__read_build_id(const char *filename, void *bf, size_t size);
340bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
341int build_id__sprintf(const u8 *build_id, int len, char *bf);
342int kallsyms__parse(const char *filename, void *arg, 211int kallsyms__parse(const char *filename, void *arg,
343 int (*process_symbol)(void *arg, const char *name, 212 int (*process_symbol)(void *arg, const char *name,
344 char type, u64 start)); 213 char type, u64 start));
345int filename__read_debuglink(const char *filename, char *debuglink, 214int filename__read_debuglink(const char *filename, char *debuglink,
346 size_t size); 215 size_t size);
347 216
348void machine__destroy_kernel_maps(struct machine *machine);
349int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
350int machine__create_kernel_maps(struct machine *machine);
351
352int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
353int machines__create_guest_kernel_maps(struct rb_root *machines);
354void machines__destroy_guest_kernel_maps(struct rb_root *machines);
355
356int symbol__init(void); 217int symbol__init(void);
357void symbol__exit(void); 218void symbol__exit(void);
358void symbol__elf_init(void); 219void symbol__elf_init(void);
@@ -360,20 +221,9 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
360size_t symbol__fprintf_symname_offs(const struct symbol *sym, 221size_t symbol__fprintf_symname_offs(const struct symbol *sym,
361 const struct addr_location *al, FILE *fp); 222 const struct addr_location *al, FILE *fp);
362size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); 223size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
224size_t symbol__fprintf(struct symbol *sym, FILE *fp);
363bool symbol_type__is_a(char symbol_type, enum map_type map_type); 225bool symbol_type__is_a(char symbol_type, enum map_type map_type);
364 226
365size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
366
367int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
368 char *root_dir, char *file, size_t size);
369
370int dso__data_fd(struct dso *dso, struct machine *machine);
371ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
372 u64 offset, u8 *data, ssize_t size);
373ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
374 struct machine *machine, u64 addr,
375 u8 *data, ssize_t size);
376int dso__test_data(void);
377int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 227int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
378 struct symsrc *runtime_ss, symbol_filter_t filter, 228 struct symsrc *runtime_ss, symbol_filter_t filter,
379 int kmodule); 229 int kmodule);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 8b3e5939afb6..df59623ac763 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,7 +7,7 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10static struct thread *thread__new(pid_t pid) 10struct thread *thread__new(pid_t pid)
11{ 11{
12 struct thread *self = zalloc(sizeof(*self)); 12 struct thread *self = zalloc(sizeof(*self));
13 13
@@ -60,45 +60,6 @@ static size_t thread__fprintf(struct thread *self, FILE *fp)
60 map_groups__fprintf(&self->mg, verbose, fp); 60 map_groups__fprintf(&self->mg, verbose, fp);
61} 61}
62 62
63struct thread *machine__findnew_thread(struct machine *self, pid_t pid)
64{
65 struct rb_node **p = &self->threads.rb_node;
66 struct rb_node *parent = NULL;
67 struct thread *th;
68
69 /*
70 * Font-end cache - PID lookups come in blocks,
71 * so most of the time we dont have to look up
72 * the full rbtree:
73 */
74 if (self->last_match && self->last_match->pid == pid)
75 return self->last_match;
76
77 while (*p != NULL) {
78 parent = *p;
79 th = rb_entry(parent, struct thread, rb_node);
80
81 if (th->pid == pid) {
82 self->last_match = th;
83 return th;
84 }
85
86 if (pid < th->pid)
87 p = &(*p)->rb_left;
88 else
89 p = &(*p)->rb_right;
90 }
91
92 th = thread__new(pid);
93 if (th != NULL) {
94 rb_link_node(&th->rb_node, parent, p);
95 rb_insert_color(&th->rb_node, &self->threads);
96 self->last_match = th;
97 }
98
99 return th;
100}
101
102void thread__insert_map(struct thread *self, struct map *map) 63void thread__insert_map(struct thread *self, struct map *map)
103{ 64{
104 map_groups__fixup_overlappings(&self->mg, map, verbose, stderr); 65 map_groups__fixup_overlappings(&self->mg, map, verbose, stderr);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index f66610b7bacf..f2fa17caa7d5 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <unistd.h> 5#include <unistd.h>
6#include <sys/types.h>
6#include "symbol.h" 7#include "symbol.h"
7 8
8struct thread { 9struct thread {
@@ -22,6 +23,7 @@ struct thread {
22 23
23struct machine; 24struct machine;
24 25
26struct thread *thread__new(pid_t pid);
25void thread__delete(struct thread *self); 27void thread__delete(struct thread *self);
26 28
27int thread__set_comm(struct thread *self, const char *comm); 29int thread__set_comm(struct thread *self, const char *comm);
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 719ed74a8565..3741572696af 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -47,8 +47,6 @@ int file_bigendian;
47int host_bigendian; 47int host_bigendian;
48static int long_size; 48static int long_size;
49 49
50static unsigned long page_size;
51
52static ssize_t calc_data_size; 50static ssize_t calc_data_size;
53static bool repipe; 51static bool repipe;
54 52
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 99664598bc1a..5906e8426cc7 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -10,6 +10,8 @@
10/* 10/*
11 * XXX We need to find a better place for these things... 11 * XXX We need to find a better place for these things...
12 */ 12 */
13unsigned int page_size;
14
13bool perf_host = true; 15bool perf_host = true;
14bool perf_guest = false; 16bool perf_guest = false;
15 17
@@ -164,6 +166,39 @@ size_t hex_width(u64 v)
164 return n; 166 return n;
165} 167}
166 168
169static int hex(char ch)
170{
171 if ((ch >= '0') && (ch <= '9'))
172 return ch - '0';
173 if ((ch >= 'a') && (ch <= 'f'))
174 return ch - 'a' + 10;
175 if ((ch >= 'A') && (ch <= 'F'))
176 return ch - 'A' + 10;
177 return -1;
178}
179
180/*
181 * While we find nice hex chars, build a long_val.
182 * Return number of chars processed.
183 */
184int hex2u64(const char *ptr, u64 *long_val)
185{
186 const char *p = ptr;
187 *long_val = 0;
188
189 while (*p) {
190 const int hex_val = hex(*p);
191
192 if (hex_val < 0)
193 break;
194
195 *long_val = (*long_val << 4) | hex_val;
196 p++;
197 }
198
199 return p - ptr;
200}
201
167/* Obtain a backtrace and print it to stdout. */ 202/* Obtain a backtrace and print it to stdout. */
168#ifdef BACKTRACE_SUPPORT 203#ifdef BACKTRACE_SUPPORT
169void dump_stack(void) 204void dump_stack(void)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 70fa70b535b2..c2330918110c 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -198,6 +198,10 @@ static inline int has_extension(const char *filename, const char *ext)
198#undef tolower 198#undef tolower
199#undef toupper 199#undef toupper
200 200
201#ifndef NSEC_PER_MSEC
202#define NSEC_PER_MSEC 1000000L
203#endif
204
201extern unsigned char sane_ctype[256]; 205extern unsigned char sane_ctype[256];
202#define GIT_SPACE 0x01 206#define GIT_SPACE 0x01
203#define GIT_DIGIT 0x02 207#define GIT_DIGIT 0x02
@@ -236,6 +240,7 @@ void argv_free(char **argv);
236bool strglobmatch(const char *str, const char *pat); 240bool strglobmatch(const char *str, const char *pat);
237bool strlazymatch(const char *str, const char *pat); 241bool strlazymatch(const char *str, const char *pat);
238int strtailcmp(const char *s1, const char *s2); 242int strtailcmp(const char *s1, const char *s2);
243char *strxfrchar(char *s, char from, char to);
239unsigned long convert_unit(unsigned long value, char *unit); 244unsigned long convert_unit(unsigned long value, char *unit);
240int readn(int fd, void *buf, size_t size); 245int readn(int fd, void *buf, size_t size);
241 246
@@ -258,9 +263,12 @@ bool is_power_of_2(unsigned long n)
258} 263}
259 264
260size_t hex_width(u64 v); 265size_t hex_width(u64 v);
266int hex2u64(const char *ptr, u64 *val);
261 267
262char *rtrim(char *s); 268char *rtrim(char *s);
263 269
264void dump_stack(void); 270void dump_stack(void);
265 271
272extern unsigned int page_size;
273
266#endif 274#endif