aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-31 16:34:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-31 16:34:04 -0400
commitf187e9fd68577cdd5f914659b6f7f11124e40485 (patch)
treead0e7422359724f7c7ffaaaa80dd3a7281f02a83 /tools
parentadb3b1f3fc1c6edb501808ebf80a81e81c52eb73 (diff)
parent8ebfdf2babcda5a3b06cc67523bca1f9aed46009 (diff)
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates and fixes from Ingo Molnar: "It's mostly fixes, but there's also two late items: - preliminary GTK GUI support for perf report - PMU raw event format descriptors in sysfs, to be parsed by tooling The raw event format in sysfs is a new ABI. For example for the 'CPU' PMU we have: aldebaran:~> ll /sys/bus/event_source/devices/cpu/format/* -r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/any -r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/cmask -r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/edge -r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/event -r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/inv -r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/offcore_rsp -r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/pc -r--r--r--. 1 root root 4096 Mar 31 10:29 /sys/bus/event_source/devices/cpu/format/umask those lists of fields contain a specific format: aldebaran:~> cat /sys/bus/event_source/devices/cpu/format/offcore_rsp config1:0-63 So, those who wish to specify raw events can now use the following event format: -e cpu/cmask=1,event=2,umask=3 Most people will not want to specify any events (let alone raw events), they'll just use whatever default event the tools use. But for more obscure PMU events that have no cross-architecture generic events the above syntax is more usable and a bit more structured than specifying hex numbers." * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (41 commits) perf tools: Remove auto-generated bison/flex files perf annotate: Fix off by one symbol hist size allocation and hit accounting perf tools: Add missing ref-cycles event back to event parser perf annotate: addr2line wants addresses in same format as objdump perf probe: Finder fails to resolve function name to address tracing: Fix ent_size in trace output perf symbols: Handle NULL dso in dso__name_len perf symbols: Do not include libgen.h perf tools: Fix bug in raw sample parsing perf tools: Fix display of first level of callchains perf tools: Switch module.h into export.h perf: Move mmap page data_head offset assertion out of header perf: Fix mmap_page capabilities and docs perf diff: Fix to work with new hists design perf tools: Fix modifier to be applied on correct events perf tools: Fix various casting issues for 32 bits perf tools: Simplify event_read_id exit path tracing: Fix ftrace stack trace entries tracing: Move the tracing_on/off() declarations into CONFIG_TRACING perf report: Add a simple GTK2-based 'perf report' browser ...
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-report.txt5
-rw-r--r--tools/perf/Makefile66
-rw-r--r--tools/perf/builtin-diff.c60
-rw-r--r--tools/perf/builtin-report.c40
-rw-r--r--tools/perf/builtin-stat.c2
-rw-r--r--tools/perf/builtin-test.c174
-rw-r--r--tools/perf/config/feature-tests.mak15
-rw-r--r--tools/perf/util/annotate.c8
-rw-r--r--tools/perf/util/cache.h12
-rw-r--r--tools/perf/util/evlist.c6
-rw-r--r--tools/perf/util/evsel.c10
-rw-r--r--tools/perf/util/evsel.h5
-rw-r--r--tools/perf/util/gtk/browser.c189
-rw-r--r--tools/perf/util/gtk/gtk.h8
-rw-r--r--tools/perf/util/header.c2
-rw-r--r--tools/perf/util/hist.c200
-rw-r--r--tools/perf/util/hist.h19
-rw-r--r--tools/perf/util/include/linux/export.h (renamed from tools/perf/util/include/linux/module.h)0
-rw-r--r--tools/perf/util/parse-events.c603
-rw-r--r--tools/perf/util/parse-events.h49
-rw-r--r--tools/perf/util/parse-events.l127
-rw-r--r--tools/perf/util/parse-events.y229
-rw-r--r--tools/perf/util/pmu.c469
-rw-r--r--tools/perf/util/pmu.h41
-rw-r--r--tools/perf/util/pmu.l43
-rw-r--r--tools/perf/util/pmu.y93
-rw-r--r--tools/perf/util/probe-finder.c4
-rw-r--r--tools/perf/util/session.c1
-rw-r--r--tools/perf/util/symbol.c3
-rw-r--r--tools/perf/util/trace-event-parse.c10
-rw-r--r--tools/perf/util/ui/browser.h2
-rw-r--r--tools/perf/util/ui/browsers/hists.c14
-rw-r--r--tools/perf/util/ui/keysyms.h2
-rw-r--r--tools/perf/util/ui/util.c82
34 files changed, 2134 insertions, 459 deletions
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 87feeee8b90c..2d89f02719b5 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -48,6 +48,9 @@ OPTIONS
48 Only consider these symbols. CSV that understands 48 Only consider these symbols. CSV that understands
49 file://filename entries. 49 file://filename entries.
50 50
51--symbol-filter=::
52 Only show symbols that match (partially) with this filter.
53
51-U:: 54-U::
52--hide-unresolved:: 55--hide-unresolved::
53 Only display entries resolved to a symbol. 56 Only display entries resolved to a symbol.
@@ -110,6 +113,8 @@ OPTIONS
110 requires a tty, if one is not present, as when piping to other 113 requires a tty, if one is not present, as when piping to other
111 commands, the stdio interface is used. 114 commands, the stdio interface is used.
112 115
116--gtk:: Use the GTK2 interface.
117
113-k:: 118-k::
114--vmlinux=<file>:: 119--vmlinux=<file>::
115 vmlinux pathname 120 vmlinux pathname
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 74fd7f89208a..820371f10d1b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -182,7 +182,7 @@ endif
182 182
183### --- END CONFIGURATION SECTION --- 183### --- END CONFIGURATION SECTION ---
184 184
185BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 185BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
186BASIC_LDFLAGS = 186BASIC_LDFLAGS =
187 187
188# Guard against environment variables 188# Guard against environment variables
@@ -234,6 +234,25 @@ endif
234 234
235export PERL_PATH 235export PERL_PATH
236 236
237FLEX = $(CROSS_COMPILE)flex
238BISON= $(CROSS_COMPILE)bison
239
240event-parser:
241 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c
242 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
243
244$(OUTPUT)util/parse-events-flex.c: event-parser
245$(OUTPUT)util/parse-events-bison.c: event-parser
246
247pmu-parser:
248 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c
249 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
250
251$(OUTPUT)util/pmu-flex.c: pmu-parser
252$(OUTPUT)util/pmu-bison.c: pmu-parser
253
254$(OUTPUT)util/parse-events.o: event-parser pmu-parser
255
237LIB_FILE=$(OUTPUT)libperf.a 256LIB_FILE=$(OUTPUT)libperf.a
238 257
239LIB_H += ../../include/linux/perf_event.h 258LIB_H += ../../include/linux/perf_event.h
@@ -249,7 +268,7 @@ LIB_H += util/include/linux/const.h
249LIB_H += util/include/linux/ctype.h 268LIB_H += util/include/linux/ctype.h
250LIB_H += util/include/linux/kernel.h 269LIB_H += util/include/linux/kernel.h
251LIB_H += util/include/linux/list.h 270LIB_H += util/include/linux/list.h
252LIB_H += util/include/linux/module.h 271LIB_H += util/include/linux/export.h
253LIB_H += util/include/linux/poison.h 272LIB_H += util/include/linux/poison.h
254LIB_H += util/include/linux/prefetch.h 273LIB_H += util/include/linux/prefetch.h
255LIB_H += util/include/linux/rbtree.h 274LIB_H += util/include/linux/rbtree.h
@@ -276,6 +295,7 @@ LIB_H += util/build-id.h
276LIB_H += util/debug.h 295LIB_H += util/debug.h
277LIB_H += util/debugfs.h 296LIB_H += util/debugfs.h
278LIB_H += util/sysfs.h 297LIB_H += util/sysfs.h
298LIB_H += util/pmu.h
279LIB_H += util/event.h 299LIB_H += util/event.h
280LIB_H += util/evsel.h 300LIB_H += util/evsel.h
281LIB_H += util/evlist.h 301LIB_H += util/evlist.h
@@ -323,6 +343,7 @@ LIB_OBJS += $(OUTPUT)util/config.o
323LIB_OBJS += $(OUTPUT)util/ctype.o 343LIB_OBJS += $(OUTPUT)util/ctype.o
324LIB_OBJS += $(OUTPUT)util/debugfs.o 344LIB_OBJS += $(OUTPUT)util/debugfs.o
325LIB_OBJS += $(OUTPUT)util/sysfs.o 345LIB_OBJS += $(OUTPUT)util/sysfs.o
346LIB_OBJS += $(OUTPUT)util/pmu.o
326LIB_OBJS += $(OUTPUT)util/environment.o 347LIB_OBJS += $(OUTPUT)util/environment.o
327LIB_OBJS += $(OUTPUT)util/event.o 348LIB_OBJS += $(OUTPUT)util/event.o
328LIB_OBJS += $(OUTPUT)util/evlist.o 349LIB_OBJS += $(OUTPUT)util/evlist.o
@@ -359,6 +380,10 @@ LIB_OBJS += $(OUTPUT)util/session.o
359LIB_OBJS += $(OUTPUT)util/thread.o 380LIB_OBJS += $(OUTPUT)util/thread.o
360LIB_OBJS += $(OUTPUT)util/thread_map.o 381LIB_OBJS += $(OUTPUT)util/thread_map.o
361LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 382LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
383LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
384LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
385LIB_OBJS += $(OUTPUT)util/pmu-flex.o
386LIB_OBJS += $(OUTPUT)util/pmu-bison.o
362LIB_OBJS += $(OUTPUT)util/trace-event-read.o 387LIB_OBJS += $(OUTPUT)util/trace-event-read.o
363LIB_OBJS += $(OUTPUT)util/trace-event-info.o 388LIB_OBJS += $(OUTPUT)util/trace-event-info.o
364LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o 389LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -501,6 +526,20 @@ else
501 endif 526 endif
502endif 527endif
503 528
529ifdef NO_GTK2
530 BASIC_CFLAGS += -DNO_GTK2
531else
532 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0)
533 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y)
534 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
535 BASIC_CFLAGS += -DNO_GTK2_SUPPORT
536 else
537 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
538 EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
539 LIB_OBJS += $(OUTPUT)util/gtk/browser.o
540 endif
541endif
542
504ifdef NO_LIBPERL 543ifdef NO_LIBPERL
505 BASIC_CFLAGS += -DNO_LIBPERL 544 BASIC_CFLAGS += -DNO_LIBPERL
506else 545else
@@ -647,6 +686,8 @@ ifndef V
647 QUIET_LINK = @echo ' ' LINK $@; 686 QUIET_LINK = @echo ' ' LINK $@;
648 QUIET_MKDIR = @echo ' ' MKDIR $@; 687 QUIET_MKDIR = @echo ' ' MKDIR $@;
649 QUIET_GEN = @echo ' ' GEN $@; 688 QUIET_GEN = @echo ' ' GEN $@;
689 QUIET_FLEX = @echo ' ' FLEX $@;
690 QUIET_BISON = @echo ' ' BISON $@;
650endif 691endif
651endif 692endif
652 693
@@ -727,12 +768,28 @@ $(OUTPUT)perf.o perf.spec \
727 $(SCRIPTS) \ 768 $(SCRIPTS) \
728 : $(OUTPUT)PERF-VERSION-FILE 769 : $(OUTPUT)PERF-VERSION-FILE
729 770
771.SUFFIXES:
772.SUFFIXES: .o .c .S .s
773
774# These two need to be here so that when O= is not used they take precedence
775# over the general rule for .o
776
777$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
778 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
779
780$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
781 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
782
730$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 783$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
731 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 784 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
785$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
786 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
732$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS 787$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
733 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< 788 $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $<
734$(OUTPUT)%.o: %.S 789$(OUTPUT)%.o: %.S
735 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 790 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
791$(OUTPUT)%.s: %.S
792 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
736 793
737$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS 794$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
738 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 795 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
@@ -795,6 +852,8 @@ help:
795 @echo ' html - make html documentation' 852 @echo ' html - make html documentation'
796 @echo ' info - make GNU info documentation (access with info <foo>)' 853 @echo ' info - make GNU info documentation (access with info <foo>)'
797 @echo ' pdf - make pdf documentation' 854 @echo ' pdf - make pdf documentation'
855 @echo ' event-parser - make event parser code'
856 @echo ' pmu-parser - make pmu format parser code'
798 @echo ' TAGS - use etags to make tag information for source browsing' 857 @echo ' TAGS - use etags to make tag information for source browsing'
799 @echo ' tags - use ctags to make tag information for source browsing' 858 @echo ' tags - use ctags to make tag information for source browsing'
800 @echo ' cscope - use cscope to make interactive browsing database' 859 @echo ' cscope - use cscope to make interactive browsing database'
@@ -931,6 +990,7 @@ clean:
931 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 990 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
932 $(MAKE) -C Documentation/ clean 991 $(MAKE) -C Documentation/ clean
933 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS 992 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
993 $(RM) $(OUTPUT)util/*-{bison,flex}*
934 $(python-clean) 994 $(python-clean)
935 995
936.PHONY: all install clean strip 996.PHONY: all install clean strip
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 4f19513d7dda..d29d350fb2b7 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -24,6 +24,11 @@ static char diff__default_sort_order[] = "dso,symbol";
24static bool force; 24static bool force;
25static bool show_displacement; 25static bool show_displacement;
26 26
27struct perf_diff {
28 struct perf_tool tool;
29 struct perf_session *session;
30};
31
27static int hists__add_entry(struct hists *self, 32static int hists__add_entry(struct hists *self,
28 struct addr_location *al, u64 period) 33 struct addr_location *al, u64 period)
29{ 34{
@@ -32,12 +37,14 @@ static int hists__add_entry(struct hists *self,
32 return -ENOMEM; 37 return -ENOMEM;
33} 38}
34 39
35static int diff__process_sample_event(struct perf_tool *tool __used, 40static int diff__process_sample_event(struct perf_tool *tool,
36 union perf_event *event, 41 union perf_event *event,
37 struct perf_sample *sample, 42 struct perf_sample *sample,
38 struct perf_evsel *evsel __used, 43 struct perf_evsel *evsel __used,
39 struct machine *machine) 44 struct machine *machine)
40{ 45{
46 struct perf_diff *_diff = container_of(tool, struct perf_diff, tool);
47 struct perf_session *session = _diff->session;
41 struct addr_location al; 48 struct addr_location al;
42 49
43 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { 50 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
@@ -49,24 +56,26 @@ static int diff__process_sample_event(struct perf_tool *tool __used,
49 if (al.filtered || al.sym == NULL) 56 if (al.filtered || al.sym == NULL)
50 return 0; 57 return 0;
51 58
52 if (hists__add_entry(&evsel->hists, &al, sample->period)) { 59 if (hists__add_entry(&session->hists, &al, sample->period)) {
53 pr_warning("problem incrementing symbol period, skipping event\n"); 60 pr_warning("problem incrementing symbol period, skipping event\n");
54 return -1; 61 return -1;
55 } 62 }
56 63
57 evsel->hists.stats.total_period += sample->period; 64 session->hists.stats.total_period += sample->period;
58 return 0; 65 return 0;
59} 66}
60 67
61static struct perf_tool perf_diff = { 68static struct perf_diff diff = {
62 .sample = diff__process_sample_event, 69 .tool = {
63 .mmap = perf_event__process_mmap, 70 .sample = diff__process_sample_event,
64 .comm = perf_event__process_comm, 71 .mmap = perf_event__process_mmap,
65 .exit = perf_event__process_task, 72 .comm = perf_event__process_comm,
66 .fork = perf_event__process_task, 73 .exit = perf_event__process_task,
67 .lost = perf_event__process_lost, 74 .fork = perf_event__process_task,
68 .ordered_samples = true, 75 .lost = perf_event__process_lost,
69 .ordering_requires_timestamps = true, 76 .ordered_samples = true,
77 .ordering_requires_timestamps = true,
78 },
70}; 79};
71 80
72static void perf_session__insert_hist_entry_by_name(struct rb_root *root, 81static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@@ -107,12 +116,6 @@ static void hists__resort_entries(struct hists *self)
107 self->entries = tmp; 116 self->entries = tmp;
108} 117}
109 118
110static void hists__set_positions(struct hists *self)
111{
112 hists__output_resort(self);
113 hists__resort_entries(self);
114}
115
116static struct hist_entry *hists__find_entry(struct hists *self, 119static struct hist_entry *hists__find_entry(struct hists *self,
117 struct hist_entry *he) 120 struct hist_entry *he)
118{ 121{
@@ -146,30 +149,37 @@ static void hists__match(struct hists *older, struct hists *newer)
146static int __cmd_diff(void) 149static int __cmd_diff(void)
147{ 150{
148 int ret, i; 151 int ret, i;
152#define older (session[0])
153#define newer (session[1])
149 struct perf_session *session[2]; 154 struct perf_session *session[2];
150 155
151 session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff); 156 older = perf_session__new(input_old, O_RDONLY, force, false,
152 session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff); 157 &diff.tool);
158 newer = perf_session__new(input_new, O_RDONLY, force, false,
159 &diff.tool);
153 if (session[0] == NULL || session[1] == NULL) 160 if (session[0] == NULL || session[1] == NULL)
154 return -ENOMEM; 161 return -ENOMEM;
155 162
156 for (i = 0; i < 2; ++i) { 163 for (i = 0; i < 2; ++i) {
157 ret = perf_session__process_events(session[i], &perf_diff); 164 diff.session = session[i];
165 ret = perf_session__process_events(session[i], &diff.tool);
158 if (ret) 166 if (ret)
159 goto out_delete; 167 goto out_delete;
168 hists__output_resort(&session[i]->hists);
160 } 169 }
161 170
162 hists__output_resort(&session[1]->hists);
163 if (show_displacement) 171 if (show_displacement)
164 hists__set_positions(&session[0]->hists); 172 hists__resort_entries(&older->hists);
165 173
166 hists__match(&session[0]->hists, &session[1]->hists); 174 hists__match(&older->hists, &newer->hists);
167 hists__fprintf(&session[1]->hists, &session[0]->hists, 175 hists__fprintf(&newer->hists, &older->hists,
168 show_displacement, true, 0, 0, stdout); 176 show_displacement, true, 0, 0, stdout);
169out_delete: 177out_delete:
170 for (i = 0; i < 2; ++i) 178 for (i = 0; i < 2; ++i)
171 perf_session__delete(session[i]); 179 perf_session__delete(session[i]);
172 return ret; 180 return ret;
181#undef older
182#undef newer
173} 183}
174 184
175static const char * const diff_usage[] = { 185static const char * const diff_usage[] = {
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 8e91c6eba18a..2e317438980b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -40,7 +40,7 @@ struct perf_report {
40 struct perf_tool tool; 40 struct perf_tool tool;
41 struct perf_session *session; 41 struct perf_session *session;
42 char const *input_name; 42 char const *input_name;
43 bool force, use_tui, 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;
46 bool show_full_info; 46 bool show_full_info;
@@ -50,6 +50,7 @@ struct perf_report {
50 const char *pretty_printing_style; 50 const char *pretty_printing_style;
51 symbol_filter_t annotate_init; 51 symbol_filter_t annotate_init;
52 const char *cpu_list; 52 const char *cpu_list;
53 const char *symbol_filter_str;
53 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 54 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
54}; 55};
55 56
@@ -400,6 +401,9 @@ static int __cmd_report(struct perf_report *rep)
400 list_for_each_entry(pos, &session->evlist->entries, node) { 401 list_for_each_entry(pos, &session->evlist->entries, node) {
401 struct hists *hists = &pos->hists; 402 struct hists *hists = &pos->hists;
402 403
404 if (pos->idx == 0)
405 hists->symbol_filter_str = rep->symbol_filter_str;
406
403 hists__collapse_resort(hists); 407 hists__collapse_resort(hists);
404 hists__output_resort(hists); 408 hists__output_resort(hists);
405 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; 409 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
@@ -411,8 +415,13 @@ static int __cmd_report(struct perf_report *rep)
411 } 415 }
412 416
413 if (use_browser > 0) { 417 if (use_browser > 0) {
414 perf_evlist__tui_browse_hists(session->evlist, help, 418 if (use_browser == 1) {
415 NULL, NULL, 0); 419 perf_evlist__tui_browse_hists(session->evlist, help,
420 NULL, NULL, 0);
421 } else if (use_browser == 2) {
422 perf_evlist__gtk_browse_hists(session->evlist, help,
423 NULL, NULL, 0);
424 }
416 } else 425 } else
417 perf_evlist__tty_browse_hists(session->evlist, rep, help); 426 perf_evlist__tty_browse_hists(session->evlist, rep, help);
418 427
@@ -569,6 +578,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
569 OPT_STRING(0, "pretty", &report.pretty_printing_style, "key", 578 OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
570 "pretty printing style key: normal raw"), 579 "pretty printing style key: normal raw"),
571 OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"), 580 OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
581 OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
572 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 582 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
573 "Use the stdio interface"), 583 "Use the stdio interface"),
574 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 584 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
@@ -591,6 +601,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
591 "only consider symbols in these comms"), 601 "only consider symbols in these comms"),
592 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 602 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
593 "only consider these symbols"), 603 "only consider these symbols"),
604 OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
605 "only show symbols that (partially) match with this filter"),
594 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, 606 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
595 "width[,width...]", 607 "width[,width...]",
596 "don't try to adjust column width, use these fixed values"), 608 "don't try to adjust column width, use these fixed values"),
@@ -624,6 +636,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
624 use_browser = 0; 636 use_browser = 0;
625 else if (report.use_tui) 637 else if (report.use_tui)
626 use_browser = 1; 638 use_browser = 1;
639 else if (report.use_gtk)
640 use_browser = 2;
627 641
628 if (report.inverted_callchain) 642 if (report.inverted_callchain)
629 callchain_param.order = ORDER_CALLER; 643 callchain_param.order = ORDER_CALLER;
@@ -660,7 +674,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
660 } 674 }
661 675
662 if (strcmp(report.input_name, "-") != 0) { 676 if (strcmp(report.input_name, "-") != 0) {
663 setup_browser(true); 677 if (report.use_gtk)
678 perf_gtk_setup_browser(argc, argv, true);
679 else
680 setup_browser(true);
664 } else { 681 } else {
665 use_browser = 0; 682 use_browser = 0;
666 } 683 }
@@ -709,11 +726,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
709 } else 726 } else
710 symbol_conf.exclude_other = false; 727 symbol_conf.exclude_other = false;
711 728
712 /* 729 if (argc) {
713 * Any (unrecognized) arguments left? 730 /*
714 */ 731 * Special case: if there's an argument left then assume that
715 if (argc) 732 * it's a symbol filter:
716 usage_with_options(report_usage, options); 733 */
734 if (argc > 1)
735 usage_with_options(report_usage, options);
736
737 report.symbol_filter_str = argv[0];
738 }
717 739
718 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 740 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
719 741
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index ea40e4e8b227..c941bb640f49 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -296,7 +296,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
296 if (system_wide) 296 if (system_wide)
297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, 297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
298 group, group_fd); 298 group, group_fd);
299 if (!target_pid && !target_tid) { 299 if (!target_pid && !target_tid && (!group || evsel == first)) {
300 attr->disabled = 1; 300 attr->disabled = 1;
301 attr->enable_on_exec = 1; 301 attr->enable_on_exec = 1;
302 } 302 }
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 3e087ce8daa6..1c5b9801ac61 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -13,6 +13,7 @@
13#include "util/parse-events.h" 13#include "util/parse-events.h"
14#include "util/symbol.h" 14#include "util/symbol.h"
15#include "util/thread_map.h" 15#include "util/thread_map.h"
16#include "util/pmu.h"
16#include "../../include/linux/hw_breakpoint.h" 17#include "../../include/linux/hw_breakpoint.h"
17 18
18#include <sys/mman.h> 19#include <sys/mman.h>
@@ -650,7 +651,7 @@ static int test__checkevent_raw(struct perf_evlist *evlist)
650 651
651 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 652 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
652 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); 653 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
653 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); 654 TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
654 return 0; 655 return 0;
655} 656}
656 657
@@ -677,6 +678,24 @@ static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
677 return 0; 678 return 0;
678} 679}
679 680
681static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
682{
683 struct perf_evsel *evsel = list_entry(evlist->entries.next,
684 struct perf_evsel, node);
685
686 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
687 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
688 TEST_ASSERT_VAL("wrong config",
689 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
690 TEST_ASSERT_VAL("wrong period",
691 100000 == evsel->attr.sample_period);
692 TEST_ASSERT_VAL("wrong config1",
693 0 == evsel->attr.config1);
694 TEST_ASSERT_VAL("wrong config2",
695 1 == evsel->attr.config2);
696 return 0;
697}
698
680static int test__checkevent_symbolic_alias(struct perf_evlist *evlist) 699static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
681{ 700{
682 struct perf_evsel *evsel = list_entry(evlist->entries.next, 701 struct perf_evsel *evsel = list_entry(evlist->entries.next,
@@ -858,6 +877,115 @@ static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
858 return test__checkevent_genhw(evlist); 877 return test__checkevent_genhw(evlist);
859} 878}
860 879
880static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
881{
882 struct perf_evsel *evsel = list_entry(evlist->entries.next,
883 struct perf_evsel, node);
884
885 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
886 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
887 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
888 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
889
890 return test__checkevent_breakpoint(evlist);
891}
892
893static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
894{
895 struct perf_evsel *evsel = list_entry(evlist->entries.next,
896 struct perf_evsel, node);
897
898 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
899 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
900 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
901 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
902
903 return test__checkevent_breakpoint_x(evlist);
904}
905
906static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
907{
908 struct perf_evsel *evsel = list_entry(evlist->entries.next,
909 struct perf_evsel, node);
910
911 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
912 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
913 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
914 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
915
916 return test__checkevent_breakpoint_r(evlist);
917}
918
919static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
920{
921 struct perf_evsel *evsel = list_entry(evlist->entries.next,
922 struct perf_evsel, node);
923
924 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
925 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
926 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
927 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
928
929 return test__checkevent_breakpoint_w(evlist);
930}
931
932static int test__checkevent_pmu(struct perf_evlist *evlist)
933{
934
935 struct perf_evsel *evsel = list_entry(evlist->entries.next,
936 struct perf_evsel, node);
937
938 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
939 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
940 TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config);
941 TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1);
942 TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2);
943 TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period);
944
945 return 0;
946}
947
948static int test__checkevent_list(struct perf_evlist *evlist)
949{
950 struct perf_evsel *evsel;
951
952 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
953
954 /* r1 */
955 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
956 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
957 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
958 TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
959 TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
960 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
961 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
962 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
963 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
964
965 /* syscalls:sys_enter_open:k */
966 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
967 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
968 TEST_ASSERT_VAL("wrong sample_type",
969 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
970 evsel->attr.sample_type);
971 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
972 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
973 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
974 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
975 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
976
977 /* 1:1:hp */
978 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
979 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
980 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
981 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
982 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
983 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
984 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
985
986 return 0;
987}
988
861static struct test__event_st { 989static struct test__event_st {
862 const char *name; 990 const char *name;
863 __u32 type; 991 __u32 type;
@@ -872,7 +1000,7 @@ static struct test__event_st {
872 .check = test__checkevent_tracepoint_multi, 1000 .check = test__checkevent_tracepoint_multi,
873 }, 1001 },
874 { 1002 {
875 .name = "r1", 1003 .name = "r1a",
876 .check = test__checkevent_raw, 1004 .check = test__checkevent_raw,
877 }, 1005 },
878 { 1006 {
@@ -884,6 +1012,10 @@ static struct test__event_st {
884 .check = test__checkevent_symbolic_name, 1012 .check = test__checkevent_symbolic_name,
885 }, 1013 },
886 { 1014 {
1015 .name = "cycles/period=100000,config2/",
1016 .check = test__checkevent_symbolic_name_config,
1017 },
1018 {
887 .name = "faults", 1019 .name = "faults",
888 .check = test__checkevent_symbolic_alias, 1020 .check = test__checkevent_symbolic_alias,
889 }, 1021 },
@@ -916,7 +1048,7 @@ static struct test__event_st {
916 .check = test__checkevent_tracepoint_multi_modifier, 1048 .check = test__checkevent_tracepoint_multi_modifier,
917 }, 1049 },
918 { 1050 {
919 .name = "r1:kp", 1051 .name = "r1a:kp",
920 .check = test__checkevent_raw_modifier, 1052 .check = test__checkevent_raw_modifier,
921 }, 1053 },
922 { 1054 {
@@ -935,6 +1067,30 @@ static struct test__event_st {
935 .name = "L1-dcache-load-miss:kp", 1067 .name = "L1-dcache-load-miss:kp",
936 .check = test__checkevent_genhw_modifier, 1068 .check = test__checkevent_genhw_modifier,
937 }, 1069 },
1070 {
1071 .name = "mem:0:u",
1072 .check = test__checkevent_breakpoint_modifier,
1073 },
1074 {
1075 .name = "mem:0:x:k",
1076 .check = test__checkevent_breakpoint_x_modifier,
1077 },
1078 {
1079 .name = "mem:0:r:hp",
1080 .check = test__checkevent_breakpoint_r_modifier,
1081 },
1082 {
1083 .name = "mem:0:w:up",
1084 .check = test__checkevent_breakpoint_w_modifier,
1085 },
1086 {
1087 .name = "cpu/config=10,config1,config2=3,period=1000/u",
1088 .check = test__checkevent_pmu,
1089 },
1090 {
1091 .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
1092 .check = test__checkevent_list,
1093 },
938}; 1094};
939 1095
940#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) 1096#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
@@ -960,10 +1116,9 @@ static int test__parse_events(void)
960 } 1116 }
961 1117
962 ret = e->check(evlist); 1118 ret = e->check(evlist);
1119 perf_evlist__delete(evlist);
963 if (ret) 1120 if (ret)
964 break; 1121 break;
965
966 perf_evlist__delete(evlist);
967 } 1122 }
968 1123
969 return ret; 1124 return ret;
@@ -1462,6 +1617,11 @@ static int test__rdpmc(void)
1462 1617
1463#endif 1618#endif
1464 1619
1620static int test__perf_pmu(void)
1621{
1622 return perf_pmu__test();
1623}
1624
1465static struct test { 1625static struct test {
1466 const char *desc; 1626 const char *desc;
1467 int (*func)(void); 1627 int (*func)(void);
@@ -1497,6 +1657,10 @@ static struct test {
1497 .func = test__PERF_RECORD, 1657 .func = test__PERF_RECORD,
1498 }, 1658 },
1499 { 1659 {
1660 .desc = "Test perf pmu format parsing",
1661 .func = test__perf_pmu,
1662 },
1663 {
1500 .func = NULL, 1664 .func = NULL,
1501 }, 1665 },
1502}; 1666};
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index 6170fd2531b5..d9084e03ce56 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -65,6 +65,21 @@ int main(void)
65endef 65endef
66endif 66endif
67 67
68ifndef NO_GTK2
69define SOURCE_GTK2
70#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
71#include <gtk/gtk.h>
72#pragma GCC diagnostic error \"-Wstrict-prototypes\"
73
74int main(int argc, char *argv[])
75{
76 gtk_init(&argc, &argv);
77
78 return 0;
79}
80endef
81endif
82
68ifndef NO_LIBPERL 83ifndef NO_LIBPERL
69define SOURCE_PERL_EMBED 84define SOURCE_PERL_EMBED
70#include <EXTERN.h> 85#include <EXTERN.h>
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index e5a462f1d07c..199f69ec656f 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -28,8 +28,8 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
28int symbol__alloc_hist(struct symbol *sym) 28int symbol__alloc_hist(struct symbol *sym)
29{ 29{
30 struct annotation *notes = symbol__annotation(sym); 30 struct annotation *notes = symbol__annotation(sym);
31 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + 31 const size_t size = sym->end - sym->start + 1;
32 (sym->end - sym->start) * sizeof(u64)); 32 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
33 33
34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
35 if (notes->src == NULL) 35 if (notes->src == NULL)
@@ -64,7 +64,7 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
64 64
65 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 65 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
66 66
67 if (addr >= sym->end) 67 if (addr > sym->end)
68 return 0; 68 return 0;
69 69
70 offset = addr - sym->start; 70 offset = addr - sym->start;
@@ -408,7 +408,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
408 if (!notes->src->lines) 408 if (!notes->src->lines)
409 return -1; 409 return -1;
410 410
411 start = map->unmap_ip(map, sym->start); 411 start = map__rip_2objdump(map, sym->start);
412 412
413 for (i = 0; i < len; i++) { 413 for (i = 0; i < len; i++) {
414 char *path = NULL; 414 char *path = NULL;
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index fc5e5a09d5b9..8dd224df3e54 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -45,6 +45,18 @@ void setup_browser(bool fallback_to_pager);
45void exit_browser(bool wait_for_ok); 45void exit_browser(bool wait_for_ok);
46#endif 46#endif
47 47
48#ifdef NO_GTK2_SUPPORT
49static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager)
50{
51 if (fallback_to_pager)
52 setup_pager();
53}
54static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {}
55#else
56void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager);
57void perf_gtk_exit_browser(bool wait_for_ok);
58#endif
59
48char *alias_lookup(const char *alias); 60char *alias_lookup(const char *alias);
49int split_cmdline(char *cmdline, const char ***argv); 61int split_cmdline(char *cmdline, const char ***argv);
50 62
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 159263d17c2d..1986d8051bd1 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -51,13 +51,15 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
51void perf_evlist__config_attrs(struct perf_evlist *evlist, 51void perf_evlist__config_attrs(struct perf_evlist *evlist,
52 struct perf_record_opts *opts) 52 struct perf_record_opts *opts)
53{ 53{
54 struct perf_evsel *evsel; 54 struct perf_evsel *evsel, *first;
55 55
56 if (evlist->cpus->map[0] < 0) 56 if (evlist->cpus->map[0] < 0)
57 opts->no_inherit = true; 57 opts->no_inherit = true;
58 58
59 first = list_entry(evlist->entries.next, struct perf_evsel, node);
60
59 list_for_each_entry(evsel, &evlist->entries, node) { 61 list_for_each_entry(evsel, &evlist->entries, node) {
60 perf_evsel__config(evsel, opts); 62 perf_evsel__config(evsel, opts, first);
61 63
62 if (evlist->nr_entries > 1) 64 if (evlist->nr_entries > 1)
63 evsel->attr.sample_type |= PERF_SAMPLE_ID; 65 evsel->attr.sample_type |= PERF_SAMPLE_ID;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index f421f7cbc0d3..8c13dbcb84b9 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -34,7 +34,7 @@ int __perf_evsel__sample_size(u64 sample_type)
34 return size; 34 return size;
35} 35}
36 36
37static void hists__init(struct hists *hists) 37void hists__init(struct hists *hists)
38{ 38{
39 memset(hists, 0, sizeof(*hists)); 39 memset(hists, 0, sizeof(*hists));
40 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; 40 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
@@ -63,7 +63,8 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
63 return evsel; 63 return evsel;
64} 64}
65 65
66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) 66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
67 struct perf_evsel *first)
67{ 68{
68 struct perf_event_attr *attr = &evsel->attr; 69 struct perf_event_attr *attr = &evsel->attr;
69 int track = !evsel->idx; /* only the first counter needs these */ 70 int track = !evsel->idx; /* only the first counter needs these */
@@ -134,7 +135,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
134 attr->mmap = track; 135 attr->mmap = track;
135 attr->comm = track; 136 attr->comm = track;
136 137
137 if (!opts->target_pid && !opts->target_tid && !opts->system_wide) { 138 if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
139 (!opts->group || evsel == first)) {
138 attr->disabled = 1; 140 attr->disabled = 1;
139 attr->enable_on_exec = 1; 141 attr->enable_on_exec = 1;
140 } 142 }
@@ -578,6 +580,8 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
578 return -EFAULT; 580 return -EFAULT;
579 581
580 data->raw_data = (void *) pdata; 582 data->raw_data = (void *) pdata;
583
584 array = (void *)array + data->raw_size + sizeof(u32);
581 } 585 }
582 586
583 if (type & PERF_SAMPLE_BRANCH_STACK) { 587 if (type & PERF_SAMPLE_BRANCH_STACK) {
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 326b8e4d5035..3d6b3e4cb66b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -80,7 +80,8 @@ void perf_evsel__exit(struct perf_evsel *evsel);
80void perf_evsel__delete(struct perf_evsel *evsel); 80void perf_evsel__delete(struct perf_evsel *evsel);
81 81
82void perf_evsel__config(struct perf_evsel *evsel, 82void perf_evsel__config(struct perf_evsel *evsel,
83 struct perf_record_opts *opts); 83 struct perf_record_opts *opts,
84 struct perf_evsel *first);
84 85
85int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 86int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
86int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 87int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
@@ -169,4 +170,6 @@ static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
169 return __perf_evsel__sample_size(evsel->attr.sample_type); 170 return __perf_evsel__sample_size(evsel->attr.sample_type);
170} 171}
171 172
173void hists__init(struct hists *hists);
174
172#endif /* __PERF_EVSEL_H */ 175#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/util/gtk/browser.c
new file mode 100644
index 000000000000..258352a2356c
--- /dev/null
+++ b/tools/perf/util/gtk/browser.c
@@ -0,0 +1,189 @@
1#include "../evlist.h"
2#include "../cache.h"
3#include "../evsel.h"
4#include "../sort.h"
5#include "../hist.h"
6#include "gtk.h"
7
8#include <signal.h>
9
10#define MAX_COLUMNS 32
11
12void perf_gtk_setup_browser(int argc, const char *argv[],
13 bool fallback_to_pager __used)
14{
15 gtk_init(&argc, (char ***)&argv);
16}
17
18void perf_gtk_exit_browser(bool wait_for_ok __used)
19{
20 gtk_main_quit();
21}
22
23static void perf_gtk_signal(int sig)
24{
25 psignal(sig, "perf");
26 gtk_main_quit();
27}
28
29static void perf_gtk_resize_window(GtkWidget *window)
30{
31 GdkRectangle rect;
32 GdkScreen *screen;
33 int monitor;
34 int height;
35 int width;
36
37 screen = gtk_widget_get_screen(window);
38
39 monitor = gdk_screen_get_monitor_at_window(screen, window->window);
40
41 gdk_screen_get_monitor_geometry(screen, monitor, &rect);
42
43 width = rect.width * 3 / 4;
44 height = rect.height * 3 / 4;
45
46 gtk_window_resize(GTK_WINDOW(window), width, height);
47}
48
49static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists)
50{
51 GType col_types[MAX_COLUMNS];
52 GtkCellRenderer *renderer;
53 struct sort_entry *se;
54 GtkListStore *store;
55 struct rb_node *nd;
56 u64 total_period;
57 GtkWidget *view;
58 int col_idx;
59 int nr_cols;
60
61 nr_cols = 0;
62
63 /* The percentage column */
64 col_types[nr_cols++] = G_TYPE_STRING;
65
66 list_for_each_entry(se, &hist_entry__sort_list, list) {
67 if (se->elide)
68 continue;
69
70 col_types[nr_cols++] = G_TYPE_STRING;
71 }
72
73 store = gtk_list_store_newv(nr_cols, col_types);
74
75 view = gtk_tree_view_new();
76
77 renderer = gtk_cell_renderer_text_new();
78
79 col_idx = 0;
80
81 /* The percentage column */
82 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
83 -1, "Overhead (%)",
84 renderer, "text",
85 col_idx++, NULL);
86
87 list_for_each_entry(se, &hist_entry__sort_list, list) {
88 if (se->elide)
89 continue;
90
91 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
92 -1, se->se_header,
93 renderer, "text",
94 col_idx++, NULL);
95 }
96
97 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
98
99 g_object_unref(GTK_TREE_MODEL(store));
100
101 total_period = hists->stats.total_period;
102
103 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
104 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
105 GtkTreeIter iter;
106 double percent;
107 char s[512];
108
109 if (h->filtered)
110 continue;
111
112 gtk_list_store_append(store, &iter);
113
114 col_idx = 0;
115
116 percent = (h->period * 100.0) / total_period;
117
118 snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
119
120 gtk_list_store_set(store, &iter, col_idx++, s, -1);
121
122 list_for_each_entry(se, &hist_entry__sort_list, list) {
123 if (se->elide)
124 continue;
125
126 se->se_snprintf(h, s, ARRAY_SIZE(s),
127 hists__col_len(hists, se->se_width_idx));
128
129 gtk_list_store_set(store, &iter, col_idx++, s, -1);
130 }
131 }
132
133 gtk_container_add(GTK_CONTAINER(window), view);
134}
135
136int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
137 const char *help __used,
138 void (*timer) (void *arg)__used,
139 void *arg __used, int delay_secs __used)
140{
141 struct perf_evsel *pos;
142 GtkWidget *notebook;
143 GtkWidget *window;
144
145 signal(SIGSEGV, perf_gtk_signal);
146 signal(SIGFPE, perf_gtk_signal);
147 signal(SIGINT, perf_gtk_signal);
148 signal(SIGQUIT, perf_gtk_signal);
149 signal(SIGTERM, perf_gtk_signal);
150
151 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
152
153 gtk_window_set_title(GTK_WINDOW(window), "perf report");
154
155 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
156
157 notebook = gtk_notebook_new();
158
159 list_for_each_entry(pos, &evlist->entries, node) {
160 struct hists *hists = &pos->hists;
161 const char *evname = event_name(pos);
162 GtkWidget *scrolled_window;
163 GtkWidget *tab_label;
164
165 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
166
167 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
168 GTK_POLICY_AUTOMATIC,
169 GTK_POLICY_AUTOMATIC);
170
171 perf_gtk_show_hists(scrolled_window, hists);
172
173 tab_label = gtk_label_new(evname);
174
175 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
176 }
177
178 gtk_container_add(GTK_CONTAINER(window), notebook);
179
180 gtk_widget_show_all(window);
181
182 perf_gtk_resize_window(window);
183
184 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
185
186 gtk_main();
187
188 return 0;
189}
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/util/gtk/gtk.h
new file mode 100644
index 000000000000..75177ee04032
--- /dev/null
+++ b/tools/perf/util/gtk/gtk.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_GTK_H_
2#define _PERF_GTK_H_ 1
3
4#pragma GCC diagnostic ignored "-Wstrict-prototypes"
5#include <gtk/gtk.h>
6#pragma GCC diagnostic error "-Wstrict-prototypes"
7
8#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index fcd9cf3ea63e..4c7c2d73251f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1177,7 +1177,7 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1177 goto error; 1177 goto error;
1178 1178
1179 msz = sizeof(attr); 1179 msz = sizeof(attr);
1180 if (sz < (ssize_t)msz) 1180 if (sz < msz)
1181 msz = sz; 1181 msz = sz;
1182 1182
1183 for (i = 0 ; i < nre; i++) { 1183 for (i = 0 ; i < nre; i++) {
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 3dc99a9b71f5..2ec4b60aff6c 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -10,11 +10,14 @@ static bool hists__filter_entry_by_dso(struct hists *hists,
10 struct hist_entry *he); 10 struct hist_entry *he);
11static bool hists__filter_entry_by_thread(struct hists *hists, 11static bool hists__filter_entry_by_thread(struct hists *hists,
12 struct hist_entry *he); 12 struct hist_entry *he);
13static bool hists__filter_entry_by_symbol(struct hists *hists,
14 struct hist_entry *he);
13 15
14enum hist_filter { 16enum hist_filter {
15 HIST_FILTER__DSO, 17 HIST_FILTER__DSO,
16 HIST_FILTER__THREAD, 18 HIST_FILTER__THREAD,
17 HIST_FILTER__PARENT, 19 HIST_FILTER__PARENT,
20 HIST_FILTER__SYMBOL,
18}; 21};
19 22
20struct callchain_param callchain_param = { 23struct callchain_param callchain_param = {
@@ -420,6 +423,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
420{ 423{
421 hists__filter_entry_by_dso(hists, he); 424 hists__filter_entry_by_dso(hists, he);
422 hists__filter_entry_by_thread(hists, he); 425 hists__filter_entry_by_thread(hists, he);
426 hists__filter_entry_by_symbol(hists, he);
423} 427}
424 428
425static void __hists__collapse_resort(struct hists *hists, bool threaded) 429static void __hists__collapse_resort(struct hists *hists, bool threaded)
@@ -603,7 +607,7 @@ static void init_rem_hits(void)
603 rem_hits.ms.sym = rem_sq_bracket; 607 rem_hits.ms.sym = rem_sq_bracket;
604} 608}
605 609
606static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 610static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
607 u64 total_samples, int depth, 611 u64 total_samples, int depth,
608 int depth_mask, int left_margin) 612 int depth_mask, int left_margin)
609{ 613{
@@ -611,21 +615,16 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
611 struct callchain_node *child; 615 struct callchain_node *child;
612 struct callchain_list *chain; 616 struct callchain_list *chain;
613 int new_depth_mask = depth_mask; 617 int new_depth_mask = depth_mask;
614 u64 new_total;
615 u64 remaining; 618 u64 remaining;
616 size_t ret = 0; 619 size_t ret = 0;
617 int i; 620 int i;
618 uint entries_printed = 0; 621 uint entries_printed = 0;
619 622
620 if (callchain_param.mode == CHAIN_GRAPH_REL) 623 remaining = total_samples;
621 new_total = self->children_hit;
622 else
623 new_total = total_samples;
624
625 remaining = new_total;
626 624
627 node = rb_first(&self->rb_root); 625 node = rb_first(root);
628 while (node) { 626 while (node) {
627 u64 new_total;
629 u64 cumul; 628 u64 cumul;
630 629
631 child = rb_entry(node, struct callchain_node, rb_node); 630 child = rb_entry(node, struct callchain_node, rb_node);
@@ -653,11 +652,17 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
653 list_for_each_entry(chain, &child->val, list) { 652 list_for_each_entry(chain, &child->val, list) {
654 ret += ipchain__fprintf_graph(fp, chain, depth, 653 ret += ipchain__fprintf_graph(fp, chain, depth,
655 new_depth_mask, i++, 654 new_depth_mask, i++,
656 new_total, 655 total_samples,
657 cumul, 656 cumul,
658 left_margin); 657 left_margin);
659 } 658 }
660 ret += __callchain__fprintf_graph(fp, child, new_total, 659
660 if (callchain_param.mode == CHAIN_GRAPH_REL)
661 new_total = child->children_hit;
662 else
663 new_total = total_samples;
664
665 ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
661 depth + 1, 666 depth + 1,
662 new_depth_mask | (1 << depth), 667 new_depth_mask | (1 << depth),
663 left_margin); 668 left_margin);
@@ -667,61 +672,75 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
667 } 672 }
668 673
669 if (callchain_param.mode == CHAIN_GRAPH_REL && 674 if (callchain_param.mode == CHAIN_GRAPH_REL &&
670 remaining && remaining != new_total) { 675 remaining && remaining != total_samples) {
671 676
672 if (!rem_sq_bracket) 677 if (!rem_sq_bracket)
673 return ret; 678 return ret;
674 679
675 new_depth_mask &= ~(1 << (depth - 1)); 680 new_depth_mask &= ~(1 << (depth - 1));
676
677 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 681 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
678 new_depth_mask, 0, new_total, 682 new_depth_mask, 0, total_samples,
679 remaining, left_margin); 683 remaining, left_margin);
680 } 684 }
681 685
682 return ret; 686 return ret;
683} 687}
684 688
685static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 689static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
686 u64 total_samples, int left_margin) 690 u64 total_samples, int left_margin)
687{ 691{
692 struct callchain_node *cnode;
688 struct callchain_list *chain; 693 struct callchain_list *chain;
694 u32 entries_printed = 0;
689 bool printed = false; 695 bool printed = false;
696 struct rb_node *node;
690 int i = 0; 697 int i = 0;
691 int ret = 0; 698 int ret;
692 u32 entries_printed = 0;
693
694 list_for_each_entry(chain, &self->val, list) {
695 if (!i++ && sort__first_dimension == SORT_SYM)
696 continue;
697
698 if (!printed) {
699 ret += callchain__fprintf_left_margin(fp, left_margin);
700 ret += fprintf(fp, "|\n");
701 ret += callchain__fprintf_left_margin(fp, left_margin);
702 ret += fprintf(fp, "---");
703
704 left_margin += 3;
705 printed = true;
706 } else
707 ret += callchain__fprintf_left_margin(fp, left_margin);
708 699
709 if (chain->ms.sym) 700 /*
710 ret += fprintf(fp, " %s\n", chain->ms.sym->name); 701 * If have one single callchain root, don't bother printing
711 else 702 * its percentage (100 % in fractal mode and the same percentage
712 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 703 * than the hist in graph mode). This also avoid one level of column.
704 */
705 node = rb_first(root);
706 if (node && !rb_next(node)) {
707 cnode = rb_entry(node, struct callchain_node, rb_node);
708 list_for_each_entry(chain, &cnode->val, list) {
709 /*
710 * If we sort by symbol, the first entry is the same than
711 * the symbol. No need to print it otherwise it appears as
712 * displayed twice.
713 */
714 if (!i++ && sort__first_dimension == SORT_SYM)
715 continue;
716 if (!printed) {
717 ret += callchain__fprintf_left_margin(fp, left_margin);
718 ret += fprintf(fp, "|\n");
719 ret += callchain__fprintf_left_margin(fp, left_margin);
720 ret += fprintf(fp, "---");
721 left_margin += 3;
722 printed = true;
723 } else
724 ret += callchain__fprintf_left_margin(fp, left_margin);
725
726 if (chain->ms.sym)
727 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
728 else
729 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
713 730
714 if (++entries_printed == callchain_param.print_limit) 731 if (++entries_printed == callchain_param.print_limit)
715 break; 732 break;
733 }
734 root = &cnode->rb_root;
716 } 735 }
717 736
718 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); 737 return __callchain__fprintf_graph(fp, root, total_samples,
719 738 1, 1, left_margin);
720 return ret;
721} 739}
722 740
723static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self, 741static size_t __callchain__fprintf_flat(FILE *fp,
724 u64 total_samples) 742 struct callchain_node *self,
743 u64 total_samples)
725{ 744{
726 struct callchain_list *chain; 745 struct callchain_list *chain;
727 size_t ret = 0; 746 size_t ret = 0;
@@ -729,7 +748,7 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
729 if (!self) 748 if (!self)
730 return 0; 749 return 0;
731 750
732 ret += callchain__fprintf_flat(fp, self->parent, total_samples); 751 ret += __callchain__fprintf_flat(fp, self->parent, total_samples);
733 752
734 753
735 list_for_each_entry(chain, &self->val, list) { 754 list_for_each_entry(chain, &self->val, list) {
@@ -745,44 +764,58 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
745 return ret; 764 return ret;
746} 765}
747 766
748static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 767static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self,
749 u64 total_samples, int left_margin, 768 u64 total_samples)
750 FILE *fp)
751{ 769{
752 struct rb_node *rb_node;
753 struct callchain_node *chain;
754 size_t ret = 0; 770 size_t ret = 0;
755 u32 entries_printed = 0; 771 u32 entries_printed = 0;
772 struct rb_node *rb_node;
773 struct callchain_node *chain;
756 774
757 rb_node = rb_first(&he->sorted_chain); 775 rb_node = rb_first(self);
758 while (rb_node) { 776 while (rb_node) {
759 double percent; 777 double percent;
760 778
761 chain = rb_entry(rb_node, struct callchain_node, rb_node); 779 chain = rb_entry(rb_node, struct callchain_node, rb_node);
762 percent = chain->hit * 100.0 / total_samples; 780 percent = chain->hit * 100.0 / total_samples;
763 switch (callchain_param.mode) { 781
764 case CHAIN_FLAT: 782 ret = percent_color_fprintf(fp, " %6.2f%%\n", percent);
765 ret += percent_color_fprintf(fp, " %6.2f%%\n", 783 ret += __callchain__fprintf_flat(fp, chain, total_samples);
766 percent);
767 ret += callchain__fprintf_flat(fp, chain, total_samples);
768 break;
769 case CHAIN_GRAPH_ABS: /* Falldown */
770 case CHAIN_GRAPH_REL:
771 ret += callchain__fprintf_graph(fp, chain, total_samples,
772 left_margin);
773 case CHAIN_NONE:
774 default:
775 break;
776 }
777 ret += fprintf(fp, "\n"); 784 ret += fprintf(fp, "\n");
778 if (++entries_printed == callchain_param.print_limit) 785 if (++entries_printed == callchain_param.print_limit)
779 break; 786 break;
787
780 rb_node = rb_next(rb_node); 788 rb_node = rb_next(rb_node);
781 } 789 }
782 790
783 return ret; 791 return ret;
784} 792}
785 793
794static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
795 u64 total_samples, int left_margin,
796 FILE *fp)
797{
798 switch (callchain_param.mode) {
799 case CHAIN_GRAPH_REL:
800 return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
801 left_margin);
802 break;
803 case CHAIN_GRAPH_ABS:
804 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
805 left_margin);
806 break;
807 case CHAIN_FLAT:
808 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
809 break;
810 case CHAIN_NONE:
811 break;
812 default:
813 pr_err("Bad callchain mode\n");
814 }
815
816 return 0;
817}
818
786void hists__output_recalc_col_len(struct hists *hists, int max_rows) 819void hists__output_recalc_col_len(struct hists *hists, int max_rows)
787{ 820{
788 struct rb_node *next = rb_first(&hists->entries); 821 struct rb_node *next = rb_first(&hists->entries);
@@ -887,9 +920,9 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
887 diff = new_percent - old_percent; 920 diff = new_percent - old_percent;
888 921
889 if (fabs(diff) >= 0.01) 922 if (fabs(diff) >= 0.01)
890 ret += scnprintf(bf, sizeof(bf), "%+4.2F%%", diff); 923 scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
891 else 924 else
892 ret += scnprintf(bf, sizeof(bf), " "); 925 scnprintf(bf, sizeof(bf), " ");
893 926
894 if (sep) 927 if (sep)
895 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf); 928 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
@@ -898,9 +931,9 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
898 931
899 if (show_displacement) { 932 if (show_displacement) {
900 if (displacement) 933 if (displacement)
901 ret += scnprintf(bf, sizeof(bf), "%+4ld", displacement); 934 scnprintf(bf, sizeof(bf), "%+4ld", displacement);
902 else 935 else
903 ret += scnprintf(bf, sizeof(bf), " "); 936 scnprintf(bf, sizeof(bf), " ");
904 937
905 if (sep) 938 if (sep)
906 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf); 939 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
@@ -1247,6 +1280,37 @@ void hists__filter_by_thread(struct hists *hists)
1247 } 1280 }
1248} 1281}
1249 1282
1283static bool hists__filter_entry_by_symbol(struct hists *hists,
1284 struct hist_entry *he)
1285{
1286 if (hists->symbol_filter_str != NULL &&
1287 (!he->ms.sym || strstr(he->ms.sym->name,
1288 hists->symbol_filter_str) == NULL)) {
1289 he->filtered |= (1 << HIST_FILTER__SYMBOL);
1290 return true;
1291 }
1292
1293 return false;
1294}
1295
1296void hists__filter_by_symbol(struct hists *hists)
1297{
1298 struct rb_node *nd;
1299
1300 hists->nr_entries = hists->stats.total_period = 0;
1301 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1302 hists__reset_col_len(hists);
1303
1304 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1305 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1306
1307 if (hists__filter_entry_by_symbol(hists, h))
1308 continue;
1309
1310 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL);
1311 }
1312}
1313
1250int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) 1314int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
1251{ 1315{
1252 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); 1316 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 9413f3e31fea..2cae9df40e04 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -62,6 +62,7 @@ struct hists {
62 const struct thread *thread_filter; 62 const struct thread *thread_filter;
63 const struct dso *dso_filter; 63 const struct dso *dso_filter;
64 const char *uid_filter_str; 64 const char *uid_filter_str;
65 const char *symbol_filter_str;
65 pthread_mutex_t lock; 66 pthread_mutex_t lock;
66 struct events_stats stats; 67 struct events_stats stats;
67 u64 event_stream; 68 u64 event_stream;
@@ -107,6 +108,7 @@ int hist_entry__annotate(struct hist_entry *self, size_t privsize);
107 108
108void hists__filter_by_dso(struct hists *hists); 109void hists__filter_by_dso(struct hists *hists);
109void hists__filter_by_thread(struct hists *hists); 110void hists__filter_by_thread(struct hists *hists);
111void hists__filter_by_symbol(struct hists *hists);
110 112
111u16 hists__col_len(struct hists *self, enum hist_column col); 113u16 hists__col_len(struct hists *self, enum hist_column col);
112void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 114void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
@@ -145,6 +147,23 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
145 int refresh); 147 int refresh);
146#endif 148#endif
147 149
150#ifdef NO_GTK2_SUPPORT
151static inline
152int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __used,
153 const char *help __used,
154 void(*timer)(void *arg) __used,
155 void *arg __used,
156 int refresh __used)
157{
158 return 0;
159}
160
161#else
162int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
163 void(*timer)(void *arg), void *arg,
164 int refresh);
165#endif
166
148unsigned int hists__sort_list_width(struct hists *self); 167unsigned int hists__sort_list_width(struct hists *self);
149 168
150#endif /* __PERF_HIST_H */ 169#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/export.h
index b43e2dc21e04..b43e2dc21e04 100644
--- a/tools/perf/util/include/linux/module.h
+++ b/tools/perf/util/include/linux/export.h
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c7a6f6faf91e..5b3a0ef4e232 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,10 @@
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
13#include "debugfs.h" 13#include "debugfs.h"
14#include "parse-events-flex.h"
15#include "pmu.h"
16
17#define MAX_NAME_LEN 100
14 18
15struct event_symbol { 19struct event_symbol {
16 u8 type; 20 u8 type;
@@ -19,11 +23,8 @@ struct event_symbol {
19 const char *alias; 23 const char *alias;
20}; 24};
21 25
22enum event_result { 26int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
23 EVT_FAILED, 27 int *idx);
24 EVT_HANDLED,
25 EVT_HANDLED_ALL
26};
27 28
28#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 29#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
29#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 30#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -354,7 +355,24 @@ const char *__event_name(int type, u64 config)
354 return "unknown"; 355 return "unknown";
355} 356}
356 357
357static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size) 358static int add_event(struct list_head *list, int *idx,
359 struct perf_event_attr *attr, char *name)
360{
361 struct perf_evsel *evsel;
362
363 event_attr_init(attr);
364
365 evsel = perf_evsel__new(attr, (*idx)++);
366 if (!evsel)
367 return -ENOMEM;
368
369 list_add_tail(&evsel->node, list);
370
371 evsel->name = strdup(name);
372 return 0;
373}
374
375static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
358{ 376{
359 int i, j; 377 int i, j;
360 int n, longest = -1; 378 int n, longest = -1;
@@ -362,58 +380,57 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int
362 for (i = 0; i < size; i++) { 380 for (i = 0; i < size; i++) {
363 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { 381 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
364 n = strlen(names[i][j]); 382 n = strlen(names[i][j]);
365 if (n > longest && !strncasecmp(*str, names[i][j], n)) 383 if (n > longest && !strncasecmp(str, names[i][j], n))
366 longest = n; 384 longest = n;
367 } 385 }
368 if (longest > 0) { 386 if (longest > 0)
369 *str += longest;
370 return i; 387 return i;
371 }
372 } 388 }
373 389
374 return -1; 390 return -1;
375} 391}
376 392
377static enum event_result 393int parse_events_add_cache(struct list_head *list, int *idx,
378parse_generic_hw_event(const char **str, struct perf_event_attr *attr) 394 char *type, char *op_result1, char *op_result2)
379{ 395{
380 const char *s = *str; 396 struct perf_event_attr attr;
397 char name[MAX_NAME_LEN];
381 int cache_type = -1, cache_op = -1, cache_result = -1; 398 int cache_type = -1, cache_op = -1, cache_result = -1;
399 char *op_result[2] = { op_result1, op_result2 };
400 int i, n;
382 401
383 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
384 /* 402 /*
385 * No fallback - if we cannot get a clear cache type 403 * No fallback - if we cannot get a clear cache type
386 * then bail out: 404 * then bail out:
387 */ 405 */
406 cache_type = parse_aliases(type, hw_cache,
407 PERF_COUNT_HW_CACHE_MAX);
388 if (cache_type == -1) 408 if (cache_type == -1)
389 return EVT_FAILED; 409 return -EINVAL;
390 410
391 while ((cache_op == -1 || cache_result == -1) && *s == '-') { 411 n = snprintf(name, MAX_NAME_LEN, "%s", type);
392 ++s; 412
413 for (i = 0; (i < 2) && (op_result[i]); i++) {
414 char *str = op_result[i];
415
416 snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
393 417
394 if (cache_op == -1) { 418 if (cache_op == -1) {
395 cache_op = parse_aliases(&s, hw_cache_op, 419 cache_op = parse_aliases(str, hw_cache_op,
396 PERF_COUNT_HW_CACHE_OP_MAX); 420 PERF_COUNT_HW_CACHE_OP_MAX);
397 if (cache_op >= 0) { 421 if (cache_op >= 0) {
398 if (!is_cache_op_valid(cache_type, cache_op)) 422 if (!is_cache_op_valid(cache_type, cache_op))
399 return EVT_FAILED; 423 return -EINVAL;
400 continue; 424 continue;
401 } 425 }
402 } 426 }
403 427
404 if (cache_result == -1) { 428 if (cache_result == -1) {
405 cache_result = parse_aliases(&s, hw_cache_result, 429 cache_result = parse_aliases(str, hw_cache_result,
406 PERF_COUNT_HW_CACHE_RESULT_MAX); 430 PERF_COUNT_HW_CACHE_RESULT_MAX);
407 if (cache_result >= 0) 431 if (cache_result >= 0)
408 continue; 432 continue;
409 } 433 }
410
411 /*
412 * Can't parse this as a cache op or result, so back up
413 * to the '-'.
414 */
415 --s;
416 break;
417 } 434 }
418 435
419 /* 436 /*
@@ -428,20 +445,17 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
428 if (cache_result == -1) 445 if (cache_result == -1)
429 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; 446 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
430 447
431 attr->config = cache_type | (cache_op << 8) | (cache_result << 16); 448 memset(&attr, 0, sizeof(attr));
432 attr->type = PERF_TYPE_HW_CACHE; 449 attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
433 450 attr.type = PERF_TYPE_HW_CACHE;
434 *str = s; 451 return add_event(list, idx, &attr, name);
435 return EVT_HANDLED;
436} 452}
437 453
438static enum event_result 454static int add_tracepoint(struct list_head *list, int *idx,
439parse_single_tracepoint_event(char *sys_name, 455 char *sys_name, char *evt_name)
440 const char *evt_name,
441 unsigned int evt_length,
442 struct perf_event_attr *attr,
443 const char **strp)
444{ 456{
457 struct perf_event_attr attr;
458 char name[MAX_NAME_LEN];
445 char evt_path[MAXPATHLEN]; 459 char evt_path[MAXPATHLEN];
446 char id_buf[4]; 460 char id_buf[4];
447 u64 id; 461 u64 id;
@@ -452,130 +466,80 @@ parse_single_tracepoint_event(char *sys_name,
452 466
453 fd = open(evt_path, O_RDONLY); 467 fd = open(evt_path, O_RDONLY);
454 if (fd < 0) 468 if (fd < 0)
455 return EVT_FAILED; 469 return -1;
456 470
457 if (read(fd, id_buf, sizeof(id_buf)) < 0) { 471 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
458 close(fd); 472 close(fd);
459 return EVT_FAILED; 473 return -1;
460 } 474 }
461 475
462 close(fd); 476 close(fd);
463 id = atoll(id_buf); 477 id = atoll(id_buf);
464 attr->config = id;
465 attr->type = PERF_TYPE_TRACEPOINT;
466 *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
467
468 attr->sample_type |= PERF_SAMPLE_RAW;
469 attr->sample_type |= PERF_SAMPLE_TIME;
470 attr->sample_type |= PERF_SAMPLE_CPU;
471
472 attr->sample_period = 1;
473 478
479 memset(&attr, 0, sizeof(attr));
480 attr.config = id;
481 attr.type = PERF_TYPE_TRACEPOINT;
482 attr.sample_type |= PERF_SAMPLE_RAW;
483 attr.sample_type |= PERF_SAMPLE_TIME;
484 attr.sample_type |= PERF_SAMPLE_CPU;
485 attr.sample_period = 1;
474 486
475 return EVT_HANDLED; 487 snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
488 return add_event(list, idx, &attr, name);
476} 489}
477 490
478/* sys + ':' + event + ':' + flags*/ 491static int add_tracepoint_multi(struct list_head *list, int *idx,
479#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 492 char *sys_name, char *evt_name)
480static enum event_result
481parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
482 const char *evt_exp, char *flags)
483{ 493{
484 char evt_path[MAXPATHLEN]; 494 char evt_path[MAXPATHLEN];
485 struct dirent *evt_ent; 495 struct dirent *evt_ent;
486 DIR *evt_dir; 496 DIR *evt_dir;
497 int ret = 0;
487 498
488 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); 499 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
489 evt_dir = opendir(evt_path); 500 evt_dir = opendir(evt_path);
490
491 if (!evt_dir) { 501 if (!evt_dir) {
492 perror("Can't open event dir"); 502 perror("Can't open event dir");
493 return EVT_FAILED; 503 return -1;
494 } 504 }
495 505
496 while ((evt_ent = readdir(evt_dir))) { 506 while (!ret && (evt_ent = readdir(evt_dir))) {
497 char event_opt[MAX_EVOPT_LEN + 1];
498 int len;
499
500 if (!strcmp(evt_ent->d_name, ".") 507 if (!strcmp(evt_ent->d_name, ".")
501 || !strcmp(evt_ent->d_name, "..") 508 || !strcmp(evt_ent->d_name, "..")
502 || !strcmp(evt_ent->d_name, "enable") 509 || !strcmp(evt_ent->d_name, "enable")
503 || !strcmp(evt_ent->d_name, "filter")) 510 || !strcmp(evt_ent->d_name, "filter"))
504 continue; 511 continue;
505 512
506 if (!strglobmatch(evt_ent->d_name, evt_exp)) 513 if (!strglobmatch(evt_ent->d_name, evt_name))
507 continue; 514 continue;
508 515
509 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 516 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
510 evt_ent->d_name, flags ? ":" : "",
511 flags ?: "");
512 if (len < 0)
513 return EVT_FAILED;
514
515 if (parse_events(evlist, event_opt, 0))
516 return EVT_FAILED;
517 } 517 }
518 518
519 return EVT_HANDLED_ALL; 519 return ret;
520} 520}
521 521
522static enum event_result 522int parse_events_add_tracepoint(struct list_head *list, int *idx,
523parse_tracepoint_event(struct perf_evlist *evlist, const char **strp, 523 char *sys, char *event)
524 struct perf_event_attr *attr)
525{ 524{
526 const char *evt_name; 525 int ret;
527 char *flags = NULL, *comma_loc;
528 char sys_name[MAX_EVENT_LENGTH];
529 unsigned int sys_length, evt_length;
530
531 if (debugfs_valid_mountpoint(tracing_events_path))
532 return 0;
533
534 evt_name = strchr(*strp, ':');
535 if (!evt_name)
536 return EVT_FAILED;
537
538 sys_length = evt_name - *strp;
539 if (sys_length >= MAX_EVENT_LENGTH)
540 return 0;
541 526
542 strncpy(sys_name, *strp, sys_length); 527 ret = debugfs_valid_mountpoint(tracing_events_path);
543 sys_name[sys_length] = '\0'; 528 if (ret)
544 evt_name = evt_name + 1; 529 return ret;
545 530
546 comma_loc = strchr(evt_name, ','); 531 return strpbrk(event, "*?") ?
547 if (comma_loc) { 532 add_tracepoint_multi(list, idx, sys, event) :
548 /* take the event name up to the comma */ 533 add_tracepoint(list, idx, sys, event);
549 evt_name = strndup(evt_name, comma_loc - evt_name);
550 }
551 flags = strchr(evt_name, ':');
552 if (flags) {
553 /* split it out: */
554 evt_name = strndup(evt_name, flags - evt_name);
555 flags++;
556 }
557
558 evt_length = strlen(evt_name);
559 if (evt_length >= MAX_EVENT_LENGTH)
560 return EVT_FAILED;
561 if (strpbrk(evt_name, "*?")) {
562 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
563 return parse_multiple_tracepoint_event(evlist, sys_name,
564 evt_name, flags);
565 } else {
566 return parse_single_tracepoint_event(sys_name, evt_name,
567 evt_length, attr, strp);
568 }
569} 534}
570 535
571static enum event_result 536static int
572parse_breakpoint_type(const char *type, const char **strp, 537parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
573 struct perf_event_attr *attr)
574{ 538{
575 int i; 539 int i;
576 540
577 for (i = 0; i < 3; i++) { 541 for (i = 0; i < 3; i++) {
578 if (!type[i]) 542 if (!type || !type[i])
579 break; 543 break;
580 544
581 switch (type[i]) { 545 switch (type[i]) {
@@ -589,164 +553,146 @@ parse_breakpoint_type(const char *type, const char **strp,
589 attr->bp_type |= HW_BREAKPOINT_X; 553 attr->bp_type |= HW_BREAKPOINT_X;
590 break; 554 break;
591 default: 555 default:
592 return EVT_FAILED; 556 return -EINVAL;
593 } 557 }
594 } 558 }
559
595 if (!attr->bp_type) /* Default */ 560 if (!attr->bp_type) /* Default */
596 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; 561 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
597 562
598 *strp = type + i; 563 return 0;
599
600 return EVT_HANDLED;
601} 564}
602 565
603static enum event_result 566int parse_events_add_breakpoint(struct list_head *list, int *idx,
604parse_breakpoint_event(const char **strp, struct perf_event_attr *attr) 567 void *ptr, char *type)
605{ 568{
606 const char *target; 569 struct perf_event_attr attr;
607 const char *type; 570 char name[MAX_NAME_LEN];
608 char *endaddr;
609 u64 addr;
610 enum event_result err;
611
612 target = strchr(*strp, ':');
613 if (!target)
614 return EVT_FAILED;
615
616 if (strncmp(*strp, "mem", target - *strp) != 0)
617 return EVT_FAILED;
618
619 target++;
620
621 addr = strtoull(target, &endaddr, 0);
622 if (target == endaddr)
623 return EVT_FAILED;
624
625 attr->bp_addr = addr;
626 *strp = endaddr;
627 571
628 type = strchr(target, ':'); 572 memset(&attr, 0, sizeof(attr));
573 attr.bp_addr = (unsigned long) ptr;
629 574
630 /* If no type is defined, just rw as default */ 575 if (parse_breakpoint_type(type, &attr))
631 if (!type) { 576 return -EINVAL;
632 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
633 } else {
634 err = parse_breakpoint_type(++type, strp, attr);
635 if (err == EVT_FAILED)
636 return EVT_FAILED;
637 }
638 577
639 /* 578 /*
640 * We should find a nice way to override the access length 579 * We should find a nice way to override the access length
641 * Provide some defaults for now 580 * Provide some defaults for now
642 */ 581 */
643 if (attr->bp_type == HW_BREAKPOINT_X) 582 if (attr.bp_type == HW_BREAKPOINT_X)
644 attr->bp_len = sizeof(long); 583 attr.bp_len = sizeof(long);
645 else 584 else
646 attr->bp_len = HW_BREAKPOINT_LEN_4; 585 attr.bp_len = HW_BREAKPOINT_LEN_4;
647 586
648 attr->type = PERF_TYPE_BREAKPOINT; 587 attr.type = PERF_TYPE_BREAKPOINT;
649 588
650 return EVT_HANDLED; 589 snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
590 return add_event(list, idx, &attr, name);
651} 591}
652 592
653static int check_events(const char *str, unsigned int i) 593static int config_term(struct perf_event_attr *attr,
594 struct parse_events__term *term)
654{ 595{
655 int n; 596 switch (term->type) {
597 case PARSE_EVENTS__TERM_TYPE_CONFIG:
598 attr->config = term->val.num;
599 break;
600 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
601 attr->config1 = term->val.num;
602 break;
603 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
604 attr->config2 = term->val.num;
605 break;
606 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
607 attr->sample_period = term->val.num;
608 break;
609 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
610 /*
611 * TODO uncomment when the field is available
612 * attr->branch_sample_type = term->val.num;
613 */
614 break;
615 default:
616 return -EINVAL;
617 }
618 return 0;
619}
656 620
657 n = strlen(event_symbols[i].symbol); 621static int config_attr(struct perf_event_attr *attr,
658 if (!strncasecmp(str, event_symbols[i].symbol, n)) 622 struct list_head *head, int fail)
659 return n; 623{
624 struct parse_events__term *term;
660 625
661 n = strlen(event_symbols[i].alias); 626 list_for_each_entry(term, head, list)
662 if (n) { 627 if (config_term(attr, term) && fail)
663 if (!strncasecmp(str, event_symbols[i].alias, n)) 628 return -EINVAL;
664 return n;
665 }
666 629
667 return 0; 630 return 0;
668} 631}
669 632
670static enum event_result 633int parse_events_add_numeric(struct list_head *list, int *idx,
671parse_symbolic_event(const char **strp, struct perf_event_attr *attr) 634 unsigned long type, unsigned long config,
635 struct list_head *head_config)
672{ 636{
673 const char *str = *strp; 637 struct perf_event_attr attr;
674 unsigned int i; 638
675 int n; 639 memset(&attr, 0, sizeof(attr));
676 640 attr.type = type;
677 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 641 attr.config = config;
678 n = check_events(str, i); 642
679 if (n > 0) { 643 if (head_config &&
680 attr->type = event_symbols[i].type; 644 config_attr(&attr, head_config, 1))
681 attr->config = event_symbols[i].config; 645 return -EINVAL;
682 *strp = str + n; 646
683 return EVT_HANDLED; 647 return add_event(list, idx, &attr,
684 } 648 (char *) __event_name(type, config));
685 }
686 return EVT_FAILED;
687} 649}
688 650
689static enum event_result 651int parse_events_add_pmu(struct list_head *list, int *idx,
690parse_raw_event(const char **strp, struct perf_event_attr *attr) 652 char *name, struct list_head *head_config)
691{ 653{
692 const char *str = *strp; 654 struct perf_event_attr attr;
693 u64 config; 655 struct perf_pmu *pmu;
694 int n; 656
695 657 pmu = perf_pmu__find(name);
696 if (*str != 'r') 658 if (!pmu)
697 return EVT_FAILED; 659 return -EINVAL;
698 n = hex2u64(str + 1, &config); 660
699 if (n > 0) { 661 memset(&attr, 0, sizeof(attr));
700 const char *end = str + n + 1; 662
701 if (*end != '\0' && *end != ',' && *end != ':') 663 /*
702 return EVT_FAILED; 664 * Configure hardcoded terms first, no need to check
703 665 * return value when called with fail == 0 ;)
704 *strp = end; 666 */
705 attr->type = PERF_TYPE_RAW; 667 config_attr(&attr, head_config, 0);
706 attr->config = config; 668
707 return EVT_HANDLED; 669 if (perf_pmu__config(pmu, &attr, head_config))
708 } 670 return -EINVAL;
709 return EVT_FAILED; 671
672 return add_event(list, idx, &attr, (char *) "pmu");
710} 673}
711 674
712static enum event_result 675void parse_events_update_lists(struct list_head *list_event,
713parse_numeric_event(const char **strp, struct perf_event_attr *attr) 676 struct list_head *list_all)
714{ 677{
715 const char *str = *strp; 678 /*
716 char *endp; 679 * Called for single event definition. Update the
717 unsigned long type; 680 * 'all event' list, and reinit the 'signle event'
718 u64 config; 681 * list, for next event definition.
719 682 */
720 type = strtoul(str, &endp, 0); 683 list_splice_tail(list_event, list_all);
721 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') { 684 INIT_LIST_HEAD(list_event);
722 str = endp + 1;
723 config = strtoul(str, &endp, 0);
724 if (endp > str) {
725 attr->type = type;
726 attr->config = config;
727 *strp = endp;
728 return EVT_HANDLED;
729 }
730 }
731 return EVT_FAILED;
732} 685}
733 686
734static int 687int parse_events_modifier(struct list_head *list, char *str)
735parse_event_modifier(const char **strp, struct perf_event_attr *attr)
736{ 688{
737 const char *str = *strp; 689 struct perf_evsel *evsel;
738 int exclude = 0, exclude_GH = 0; 690 int exclude = 0, exclude_GH = 0;
739 int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0; 691 int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0;
740 692
741 if (!*str) 693 if (str == NULL)
742 return 0; 694 return 0;
743 695
744 if (*str == ',')
745 return 0;
746
747 if (*str++ != ':')
748 return -1;
749
750 while (*str) { 696 while (*str) {
751 if (*str == 'u') { 697 if (*str == 'u') {
752 if (!exclude) 698 if (!exclude)
@@ -775,111 +721,62 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
775 721
776 ++str; 722 ++str;
777 } 723 }
778 if (str < *strp + 2)
779 return -1;
780 724
781 *strp = str; 725 /*
726 * precise ip:
727 *
728 * 0 - SAMPLE_IP can have arbitrary skid
729 * 1 - SAMPLE_IP must have constant skid
730 * 2 - SAMPLE_IP requested to have 0 skid
731 * 3 - SAMPLE_IP must have 0 skid
732 *
733 * See also PERF_RECORD_MISC_EXACT_IP
734 */
735 if (precise > 3)
736 return -EINVAL;
782 737
783 attr->exclude_user = eu; 738 list_for_each_entry(evsel, list, node) {
784 attr->exclude_kernel = ek; 739 evsel->attr.exclude_user = eu;
785 attr->exclude_hv = eh; 740 evsel->attr.exclude_kernel = ek;
786 attr->precise_ip = precise; 741 evsel->attr.exclude_hv = eh;
787 attr->exclude_host = eH; 742 evsel->attr.precise_ip = precise;
788 attr->exclude_guest = eG; 743 evsel->attr.exclude_host = eH;
744 evsel->attr.exclude_guest = eG;
745 }
789 746
790 return 0; 747 return 0;
791} 748}
792 749
793/* 750int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
794 * Each event can have multiple symbolic names.
795 * Symbolic names are (almost) exactly matched.
796 */
797static enum event_result
798parse_event_symbols(struct perf_evlist *evlist, const char **str,
799 struct perf_event_attr *attr)
800{ 751{
801 enum event_result ret; 752 LIST_HEAD(list);
802 753 LIST_HEAD(list_tmp);
803 ret = parse_tracepoint_event(evlist, str, attr); 754 YY_BUFFER_STATE buffer;
804 if (ret != EVT_FAILED) 755 int ret, idx = evlist->nr_entries;
805 goto modifier;
806
807 ret = parse_raw_event(str, attr);
808 if (ret != EVT_FAILED)
809 goto modifier;
810 756
811 ret = parse_numeric_event(str, attr); 757 buffer = parse_events__scan_string(str);
812 if (ret != EVT_FAILED)
813 goto modifier;
814 758
815 ret = parse_symbolic_event(str, attr); 759 ret = parse_events_parse(&list, &list_tmp, &idx);
816 if (ret != EVT_FAILED)
817 goto modifier;
818 760
819 ret = parse_generic_hw_event(str, attr); 761 parse_events__flush_buffer(buffer);
820 if (ret != EVT_FAILED) 762 parse_events__delete_buffer(buffer);
821 goto modifier;
822 763
823 ret = parse_breakpoint_event(str, attr); 764 if (!ret) {
824 if (ret != EVT_FAILED) 765 int entries = idx - evlist->nr_entries;
825 goto modifier; 766 perf_evlist__splice_list_tail(evlist, &list, entries);
826 767 return 0;
827 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
828 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
829 return EVT_FAILED;
830
831modifier:
832 if (parse_event_modifier(str, attr) < 0) {
833 fprintf(stderr, "invalid event modifier: '%s'\n", *str);
834 fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
835
836 return EVT_FAILED;
837 } 768 }
838 769
770 /*
771 * There are 2 users - builtin-record and builtin-test objects.
772 * Both call perf_evlist__delete in case of error, so we dont
773 * need to bother.
774 */
775 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
776 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
839 return ret; 777 return ret;
840} 778}
841 779
842int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
843{
844 struct perf_event_attr attr;
845 enum event_result ret;
846 const char *ostr;
847
848 for (;;) {
849 ostr = str;
850 memset(&attr, 0, sizeof(attr));
851 event_attr_init(&attr);
852 ret = parse_event_symbols(evlist, &str, &attr);
853 if (ret == EVT_FAILED)
854 return -1;
855
856 if (!(*str == 0 || *str == ',' || isspace(*str)))
857 return -1;
858
859 if (ret != EVT_HANDLED_ALL) {
860 struct perf_evsel *evsel;
861 evsel = perf_evsel__new(&attr, evlist->nr_entries);
862 if (evsel == NULL)
863 return -1;
864 perf_evlist__add(evlist, evsel);
865
866 evsel->name = calloc(str - ostr + 1, 1);
867 if (!evsel->name)
868 return -1;
869 strncpy(evsel->name, ostr, str - ostr);
870 }
871
872 if (*str == 0)
873 break;
874 if (*str == ',')
875 ++str;
876 while (isspace(*str))
877 ++str;
878 }
879
880 return 0;
881}
882
883int parse_events_option(const struct option *opt, const char *str, 780int parse_events_option(const struct option *opt, const char *str,
884 int unset __used) 781 int unset __used)
885{ 782{
@@ -1052,8 +949,6 @@ int print_hwcache_events(const char *event_glob)
1052 return printed; 949 return printed;
1053} 950}
1054 951
1055#define MAX_NAME_LEN 100
1056
1057/* 952/*
1058 * Print the help text for the event symbols: 953 * Print the help text for the event symbols:
1059 */ 954 */
@@ -1102,8 +997,12 @@ void print_events(const char *event_glob)
1102 997
1103 printf("\n"); 998 printf("\n");
1104 printf(" %-50s [%s]\n", 999 printf(" %-50s [%s]\n",
1105 "rNNN (see 'perf list --help' on how to encode it)", 1000 "rNNN",
1106 event_type_descriptors[PERF_TYPE_RAW]); 1001 event_type_descriptors[PERF_TYPE_RAW]);
1002 printf(" %-50s [%s]\n",
1003 "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
1004 event_type_descriptors[PERF_TYPE_RAW]);
1005 printf(" (see 'perf list --help' on how to encode it)\n");
1107 printf("\n"); 1006 printf("\n");
1108 1007
1109 printf(" %-50s [%s]\n", 1008 printf(" %-50s [%s]\n",
@@ -1113,3 +1012,51 @@ void print_events(const char *event_glob)
1113 1012
1114 print_tracepoint_events(NULL, NULL); 1013 print_tracepoint_events(NULL, NULL);
1115} 1014}
1015
1016int parse_events__is_hardcoded_term(struct parse_events__term *term)
1017{
1018 return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX;
1019}
1020
1021int parse_events__new_term(struct parse_events__term **_term, int type,
1022 char *config, char *str, long num)
1023{
1024 struct parse_events__term *term;
1025
1026 term = zalloc(sizeof(*term));
1027 if (!term)
1028 return -ENOMEM;
1029
1030 INIT_LIST_HEAD(&term->list);
1031 term->type = type;
1032 term->config = config;
1033
1034 switch (type) {
1035 case PARSE_EVENTS__TERM_TYPE_CONFIG:
1036 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
1037 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
1038 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
1039 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
1040 case PARSE_EVENTS__TERM_TYPE_NUM:
1041 term->val.num = num;
1042 break;
1043 case PARSE_EVENTS__TERM_TYPE_STR:
1044 term->val.str = str;
1045 break;
1046 default:
1047 return -EINVAL;
1048 }
1049
1050 *_term = term;
1051 return 0;
1052}
1053
1054void parse_events__free_terms(struct list_head *terms)
1055{
1056 struct parse_events__term *term, *h;
1057
1058 list_for_each_entry_safe(term, h, terms, list)
1059 free(term);
1060
1061 free(terms);
1062}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 7e0cbe75d5f1..ca069f893381 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,55 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
33 33
34#define EVENTS_HELP_MAX (128*1024) 34#define EVENTS_HELP_MAX (128*1024)
35 35
36enum {
37 PARSE_EVENTS__TERM_TYPE_CONFIG,
38 PARSE_EVENTS__TERM_TYPE_CONFIG1,
39 PARSE_EVENTS__TERM_TYPE_CONFIG2,
40 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
41 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
42 PARSE_EVENTS__TERM_TYPE_NUM,
43 PARSE_EVENTS__TERM_TYPE_STR,
44
45 PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
46 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
47};
48
49struct parse_events__term {
50 char *config;
51 union {
52 char *str;
53 long num;
54 } val;
55 int type;
56
57 struct list_head list;
58};
59
60int parse_events__is_hardcoded_term(struct parse_events__term *term);
61int parse_events__new_term(struct parse_events__term **term, int type,
62 char *config, char *str, long num);
63void parse_events__free_terms(struct list_head *terms);
64int parse_events_modifier(struct list_head *list __used, char *str __used);
65int parse_events_add_tracepoint(struct list_head *list, int *idx,
66 char *sys, char *event);
67int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config,
68 unsigned long config1, unsigned long config2,
69 char *mod);
70int parse_events_add_numeric(struct list_head *list, int *idx,
71 unsigned long type, unsigned long config,
72 struct list_head *head_config);
73int parse_events_add_cache(struct list_head *list, int *idx,
74 char *type, char *op_result1, char *op_result2);
75int parse_events_add_breakpoint(struct list_head *list, int *idx,
76 void *ptr, char *type);
77int parse_events_add_pmu(struct list_head *list, int *idx,
78 char *pmu , struct list_head *head_config);
79void parse_events_update_lists(struct list_head *list_event,
80 struct list_head *list_all);
81void parse_events_error(struct list_head *list_all,
82 struct list_head *list_event,
83 int *idx, char const *msg);
84
36void print_events(const char *event_glob); 85void print_events(const char *event_glob);
37void print_events_type(u8 type); 86void print_events_type(u8 type);
38void print_tracepoint_events(const char *subsys_glob, const char *event_glob); 87void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
new file mode 100644
index 000000000000..05d766e3ecb5
--- /dev/null
+++ b/tools/perf/util/parse-events.l
@@ -0,0 +1,127 @@
1
2%option prefix="parse_events_"
3
4%{
5#include <errno.h>
6#include "../perf.h"
7#include "parse-events-bison.h"
8#include "parse-events.h"
9
10static int __value(char *str, int base, int token)
11{
12 long num;
13
14 errno = 0;
15 num = strtoul(str, NULL, base);
16 if (errno)
17 return PE_ERROR;
18
19 parse_events_lval.num = num;
20 return token;
21}
22
23static int value(int base)
24{
25 return __value(parse_events_text, base, PE_VALUE);
26}
27
28static int raw(void)
29{
30 return __value(parse_events_text + 1, 16, PE_RAW);
31}
32
33static int str(int token)
34{
35 parse_events_lval.str = strdup(parse_events_text);
36 return token;
37}
38
39static int sym(int type, int config)
40{
41 parse_events_lval.num = (type << 16) + config;
42 return PE_VALUE_SYM;
43}
44
45static int term(int type)
46{
47 parse_events_lval.num = type;
48 return PE_TERM;
49}
50
51%}
52
53num_dec [0-9]+
54num_hex 0x[a-fA-F0-9]+
55num_raw_hex [a-fA-F0-9]+
56name [a-zA-Z_*?][a-zA-Z0-9_*?]*
57modifier_event [ukhp]{1,5}
58modifier_bp [rwx]
59
60%%
61cpu-cycles|cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
62stalled-cycles-frontend|idle-cycles-frontend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
63stalled-cycles-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
64instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
65cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
66cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
67branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
68branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
69bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
70ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
71cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
72task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
73page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
74minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
75major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
76context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
77cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
78alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
79emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
80
81L1-dcache|l1-d|l1d|L1-data |
82L1-icache|l1-i|l1i|L1-instruction |
83LLC|L2 |
84dTLB|d-tlb|Data-TLB |
85iTLB|i-tlb|Instruction-TLB |
86branch|branches|bpu|btb|bpc |
87node { return str(PE_NAME_CACHE_TYPE); }
88
89load|loads|read |
90store|stores|write |
91prefetch|prefetches |
92speculative-read|speculative-load |
93refs|Reference|ops|access |
94misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
95
96 /*
97 * These are event config hardcoded term names to be specified
98 * within xxx/.../ syntax. So far we dont clash with other names,
99 * so we can put them here directly. In case the we have a conflict
100 * in future, this needs to go into '//' condition block.
101 */
102config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
103config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
104config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
105period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
106branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
107
108mem: { return PE_PREFIX_MEM; }
109r{num_raw_hex} { return raw(); }
110{num_dec} { return value(10); }
111{num_hex} { return value(16); }
112
113{modifier_event} { return str(PE_MODIFIER_EVENT); }
114{modifier_bp} { return str(PE_MODIFIER_BP); }
115{name} { return str(PE_NAME); }
116"/" { return '/'; }
117- { return '-'; }
118, { return ','; }
119: { return ':'; }
120= { return '='; }
121
122%%
123
124int parse_events_wrap(void)
125{
126 return 1;
127}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
new file mode 100644
index 000000000000..d9637da7333c
--- /dev/null
+++ b/tools/perf/util/parse-events.y
@@ -0,0 +1,229 @@
1
2%name-prefix "parse_events_"
3%parse-param {struct list_head *list_all}
4%parse-param {struct list_head *list_event}
5%parse-param {int *idx}
6
7%{
8
9#define YYDEBUG 1
10
11#include <linux/compiler.h>
12#include <linux/list.h>
13#include "types.h"
14#include "util.h"
15#include "parse-events.h"
16
17extern int parse_events_lex (void);
18
19#define ABORT_ON(val) \
20do { \
21 if (val) \
22 YYABORT; \
23} while (0)
24
25%}
26
27%token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM
28%token PE_NAME
29%token PE_MODIFIER_EVENT PE_MODIFIER_BP
30%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
31%token PE_PREFIX_MEM PE_PREFIX_RAW
32%token PE_ERROR
33%type <num> PE_VALUE
34%type <num> PE_VALUE_SYM
35%type <num> PE_RAW
36%type <num> PE_TERM
37%type <str> PE_NAME
38%type <str> PE_NAME_CACHE_TYPE
39%type <str> PE_NAME_CACHE_OP_RESULT
40%type <str> PE_MODIFIER_EVENT
41%type <str> PE_MODIFIER_BP
42%type <head> event_config
43%type <term> event_term
44
45%union
46{
47 char *str;
48 unsigned long num;
49 struct list_head *head;
50 struct parse_events__term *term;
51}
52%%
53
54events:
55events ',' event | event
56
57event:
58event_def PE_MODIFIER_EVENT
59{
60 /*
61 * Apply modifier on all events added by single event definition
62 * (there could be more events added for multiple tracepoint
63 * definitions via '*?'.
64 */
65 ABORT_ON(parse_events_modifier(list_event, $2));
66 parse_events_update_lists(list_event, list_all);
67}
68|
69event_def
70{
71 parse_events_update_lists(list_event, list_all);
72}
73
74event_def: event_pmu |
75 event_legacy_symbol |
76 event_legacy_cache sep_dc |
77 event_legacy_mem |
78 event_legacy_tracepoint sep_dc |
79 event_legacy_numeric sep_dc |
80 event_legacy_raw sep_dc
81
82event_pmu:
83PE_NAME '/' event_config '/'
84{
85 ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
86 parse_events__free_terms($3);
87}
88
89event_legacy_symbol:
90PE_VALUE_SYM '/' event_config '/'
91{
92 int type = $1 >> 16;
93 int config = $1 & 255;
94
95 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
96 parse_events__free_terms($3);
97}
98|
99PE_VALUE_SYM sep_slash_dc
100{
101 int type = $1 >> 16;
102 int config = $1 & 255;
103
104 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
105}
106
107event_legacy_cache:
108PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
109{
110 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
111}
112|
113PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
114{
115 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
116}
117|
118PE_NAME_CACHE_TYPE
119{
120 ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL));
121}
122
123event_legacy_mem:
124PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
125{
126 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
127}
128|
129PE_PREFIX_MEM PE_VALUE sep_dc
130{
131 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
132}
133
134event_legacy_tracepoint:
135PE_NAME ':' PE_NAME
136{
137 ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
138}
139
140event_legacy_numeric:
141PE_VALUE ':' PE_VALUE
142{
143 ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
144}
145
146event_legacy_raw:
147PE_RAW
148{
149 ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
150}
151
152event_config:
153event_config ',' event_term
154{
155 struct list_head *head = $1;
156 struct parse_events__term *term = $3;
157
158 ABORT_ON(!head);
159 list_add_tail(&term->list, head);
160 $$ = $1;
161}
162|
163event_term
164{
165 struct list_head *head = malloc(sizeof(*head));
166 struct parse_events__term *term = $1;
167
168 ABORT_ON(!head);
169 INIT_LIST_HEAD(head);
170 list_add_tail(&term->list, head);
171 $$ = head;
172}
173
174event_term:
175PE_NAME '=' PE_NAME
176{
177 struct parse_events__term *term;
178
179 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
180 $1, $3, 0));
181 $$ = term;
182}
183|
184PE_NAME '=' PE_VALUE
185{
186 struct parse_events__term *term;
187
188 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
189 $1, NULL, $3));
190 $$ = term;
191}
192|
193PE_NAME
194{
195 struct parse_events__term *term;
196
197 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
198 $1, NULL, 1));
199 $$ = term;
200}
201|
202PE_TERM '=' PE_VALUE
203{
204 struct parse_events__term *term;
205
206 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3));
207 $$ = term;
208}
209|
210PE_TERM
211{
212 struct parse_events__term *term;
213
214 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1));
215 $$ = term;
216}
217
218sep_dc: ':' |
219
220sep_slash_dc: '/' | ':' |
221
222%%
223
224void parse_events_error(struct list_head *list_all __used,
225 struct list_head *list_event __used,
226 int *idx __used,
227 char const *msg __used)
228{
229}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
new file mode 100644
index 000000000000..cb08a118e811
--- /dev/null
+++ b/tools/perf/util/pmu.c
@@ -0,0 +1,469 @@
1
2#include <linux/list.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <unistd.h>
6#include <stdio.h>
7#include <dirent.h>
8#include "sysfs.h"
9#include "util.h"
10#include "pmu.h"
11#include "parse-events.h"
12
13int perf_pmu_parse(struct list_head *list, char *name);
14extern FILE *perf_pmu_in;
15
16static LIST_HEAD(pmus);
17
18/*
19 * Parse & process all the sysfs attributes located under
20 * the directory specified in 'dir' parameter.
21 */
22static int pmu_format_parse(char *dir, struct list_head *head)
23{
24 struct dirent *evt_ent;
25 DIR *format_dir;
26 int ret = 0;
27
28 format_dir = opendir(dir);
29 if (!format_dir)
30 return -EINVAL;
31
32 while (!ret && (evt_ent = readdir(format_dir))) {
33 char path[PATH_MAX];
34 char *name = evt_ent->d_name;
35 FILE *file;
36
37 if (!strcmp(name, ".") || !strcmp(name, ".."))
38 continue;
39
40 snprintf(path, PATH_MAX, "%s/%s", dir, name);
41
42 ret = -EINVAL;
43 file = fopen(path, "r");
44 if (!file)
45 break;
46
47 perf_pmu_in = file;
48 ret = perf_pmu_parse(head, name);
49 fclose(file);
50 }
51
52 closedir(format_dir);
53 return ret;
54}
55
56/*
57 * Reading/parsing the default pmu format definition, which should be
58 * located at:
59 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
60 */
61static int pmu_format(char *name, struct list_head *format)
62{
63 struct stat st;
64 char path[PATH_MAX];
65 const char *sysfs;
66
67 sysfs = sysfs_find_mountpoint();
68 if (!sysfs)
69 return -1;
70
71 snprintf(path, PATH_MAX,
72 "%s/bus/event_source/devices/%s/format", sysfs, name);
73
74 if (stat(path, &st) < 0)
75 return -1;
76
77 if (pmu_format_parse(path, format))
78 return -1;
79
80 return 0;
81}
82
83/*
84 * Reading/parsing the default pmu type value, which should be
85 * located at:
86 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
87 */
88static int pmu_type(char *name, __u32 *type)
89{
90 struct stat st;
91 char path[PATH_MAX];
92 const char *sysfs;
93 FILE *file;
94 int ret = 0;
95
96 sysfs = sysfs_find_mountpoint();
97 if (!sysfs)
98 return -1;
99
100 snprintf(path, PATH_MAX,
101 "%s/bus/event_source/devices/%s/type", sysfs, name);
102
103 if (stat(path, &st) < 0)
104 return -1;
105
106 file = fopen(path, "r");
107 if (!file)
108 return -EINVAL;
109
110 if (1 != fscanf(file, "%u", type))
111 ret = -1;
112
113 fclose(file);
114 return ret;
115}
116
117static struct perf_pmu *pmu_lookup(char *name)
118{
119 struct perf_pmu *pmu;
120 LIST_HEAD(format);
121 __u32 type;
122
123 /*
124 * The pmu data we store & need consists of the pmu
125 * type value and format definitions. Load both right
126 * now.
127 */
128 if (pmu_format(name, &format))
129 return NULL;
130
131 if (pmu_type(name, &type))
132 return NULL;
133
134 pmu = zalloc(sizeof(*pmu));
135 if (!pmu)
136 return NULL;
137
138 INIT_LIST_HEAD(&pmu->format);
139 list_splice(&format, &pmu->format);
140 pmu->name = strdup(name);
141 pmu->type = type;
142 return pmu;
143}
144
145static struct perf_pmu *pmu_find(char *name)
146{
147 struct perf_pmu *pmu;
148
149 list_for_each_entry(pmu, &pmus, list)
150 if (!strcmp(pmu->name, name))
151 return pmu;
152
153 return NULL;
154}
155
156struct perf_pmu *perf_pmu__find(char *name)
157{
158 struct perf_pmu *pmu;
159
160 /*
161 * Once PMU is loaded it stays in the list,
162 * so we keep us from multiple reading/parsing
163 * the pmu format definitions.
164 */
165 pmu = pmu_find(name);
166 if (pmu)
167 return pmu;
168
169 return pmu_lookup(name);
170}
171
172static struct perf_pmu__format*
173pmu_find_format(struct list_head *formats, char *name)
174{
175 struct perf_pmu__format *format;
176
177 list_for_each_entry(format, formats, list)
178 if (!strcmp(format->name, name))
179 return format;
180
181 return NULL;
182}
183
184/*
185 * Returns value based on the format definition (format parameter)
186 * and unformated value (value parameter).
187 *
188 * TODO maybe optimize a little ;)
189 */
190static __u64 pmu_format_value(unsigned long *format, __u64 value)
191{
192 unsigned long fbit, vbit;
193 __u64 v = 0;
194
195 for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
196
197 if (!test_bit(fbit, format))
198 continue;
199
200 if (!(value & (1llu << vbit++)))
201 continue;
202
203 v |= (1llu << fbit);
204 }
205
206 return v;
207}
208
209/*
210 * Setup one of config[12] attr members based on the
211 * user input data - temr parameter.
212 */
213static int pmu_config_term(struct list_head *formats,
214 struct perf_event_attr *attr,
215 struct parse_events__term *term)
216{
217 struct perf_pmu__format *format;
218 __u64 *vp;
219
220 /*
221 * Support only for hardcoded and numnerial terms.
222 * Hardcoded terms should be already in, so nothing
223 * to be done for them.
224 */
225 if (parse_events__is_hardcoded_term(term))
226 return 0;
227
228 if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
229 return -EINVAL;
230
231 format = pmu_find_format(formats, term->config);
232 if (!format)
233 return -EINVAL;
234
235 switch (format->value) {
236 case PERF_PMU_FORMAT_VALUE_CONFIG:
237 vp = &attr->config;
238 break;
239 case PERF_PMU_FORMAT_VALUE_CONFIG1:
240 vp = &attr->config1;
241 break;
242 case PERF_PMU_FORMAT_VALUE_CONFIG2:
243 vp = &attr->config2;
244 break;
245 default:
246 return -EINVAL;
247 }
248
249 *vp |= pmu_format_value(format->bits, term->val.num);
250 return 0;
251}
252
253static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
254 struct list_head *head_terms)
255{
256 struct parse_events__term *term, *h;
257
258 list_for_each_entry_safe(term, h, head_terms, list)
259 if (pmu_config_term(formats, attr, term))
260 return -EINVAL;
261
262 return 0;
263}
264
265/*
266 * Configures event's 'attr' parameter based on the:
267 * 1) users input - specified in terms parameter
268 * 2) pmu format definitions - specified by pmu parameter
269 */
270int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
271 struct list_head *head_terms)
272{
273 attr->type = pmu->type;
274 return pmu_config(&pmu->format, attr, head_terms);
275}
276
277int perf_pmu__new_format(struct list_head *list, char *name,
278 int config, unsigned long *bits)
279{
280 struct perf_pmu__format *format;
281
282 format = zalloc(sizeof(*format));
283 if (!format)
284 return -ENOMEM;
285
286 format->name = strdup(name);
287 format->value = config;
288 memcpy(format->bits, bits, sizeof(format->bits));
289
290 list_add_tail(&format->list, list);
291 return 0;
292}
293
294void perf_pmu__set_format(unsigned long *bits, long from, long to)
295{
296 long b;
297
298 if (!to)
299 to = from;
300
301 memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
302 for (b = from; b <= to; b++)
303 set_bit(b, bits);
304}
305
306/* Simulated format definitions. */
307static struct test_format {
308 const char *name;
309 const char *value;
310} test_formats[] = {
311 { "krava01", "config:0-1,62-63\n", },
312 { "krava02", "config:10-17\n", },
313 { "krava03", "config:5\n", },
314 { "krava11", "config1:0,2,4,6,8,20-28\n", },
315 { "krava12", "config1:63\n", },
316 { "krava13", "config1:45-47\n", },
317 { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
318 { "krava22", "config2:8,18,48,58\n", },
319 { "krava23", "config2:28-29,38\n", },
320};
321
322#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
323
324/* Simulated users input. */
325static struct parse_events__term test_terms[] = {
326 {
327 .config = (char *) "krava01",
328 .val.num = 15,
329 .type = PARSE_EVENTS__TERM_TYPE_NUM,
330 },
331 {
332 .config = (char *) "krava02",
333 .val.num = 170,
334 .type = PARSE_EVENTS__TERM_TYPE_NUM,
335 },
336 {
337 .config = (char *) "krava03",
338 .val.num = 1,
339 .type = PARSE_EVENTS__TERM_TYPE_NUM,
340 },
341 {
342 .config = (char *) "krava11",
343 .val.num = 27,
344 .type = PARSE_EVENTS__TERM_TYPE_NUM,
345 },
346 {
347 .config = (char *) "krava12",
348 .val.num = 1,
349 .type = PARSE_EVENTS__TERM_TYPE_NUM,
350 },
351 {
352 .config = (char *) "krava13",
353 .val.num = 2,
354 .type = PARSE_EVENTS__TERM_TYPE_NUM,
355 },
356 {
357 .config = (char *) "krava21",
358 .val.num = 119,
359 .type = PARSE_EVENTS__TERM_TYPE_NUM,
360 },
361 {
362 .config = (char *) "krava22",
363 .val.num = 11,
364 .type = PARSE_EVENTS__TERM_TYPE_NUM,
365 },
366 {
367 .config = (char *) "krava23",
368 .val.num = 2,
369 .type = PARSE_EVENTS__TERM_TYPE_NUM,
370 },
371};
372#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
373
374/*
375 * Prepare format directory data, exported by kernel
376 * at /sys/bus/event_source/devices/<dev>/format.
377 */
378static char *test_format_dir_get(void)
379{
380 static char dir[PATH_MAX];
381 unsigned int i;
382
383 snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
384 if (!mkdtemp(dir))
385 return NULL;
386
387 for (i = 0; i < TEST_FORMATS_CNT; i++) {
388 static char name[PATH_MAX];
389 struct test_format *format = &test_formats[i];
390 FILE *file;
391
392 snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
393
394 file = fopen(name, "w");
395 if (!file)
396 return NULL;
397
398 if (1 != fwrite(format->value, strlen(format->value), 1, file))
399 break;
400
401 fclose(file);
402 }
403
404 return dir;
405}
406
407/* Cleanup format directory. */
408static int test_format_dir_put(char *dir)
409{
410 char buf[PATH_MAX];
411 snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
412 if (system(buf))
413 return -1;
414
415 snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
416 return system(buf);
417}
418
419static struct list_head *test_terms_list(void)
420{
421 static LIST_HEAD(terms);
422 unsigned int i;
423
424 for (i = 0; i < TERMS_CNT; i++)
425 list_add_tail(&test_terms[i].list, &terms);
426
427 return &terms;
428}
429
430#undef TERMS_CNT
431
432int perf_pmu__test(void)
433{
434 char *format = test_format_dir_get();
435 LIST_HEAD(formats);
436 struct list_head *terms = test_terms_list();
437 int ret;
438
439 if (!format)
440 return -EINVAL;
441
442 do {
443 struct perf_event_attr attr;
444
445 memset(&attr, 0, sizeof(attr));
446
447 ret = pmu_format_parse(format, &formats);
448 if (ret)
449 break;
450
451 ret = pmu_config(&formats, &attr, terms);
452 if (ret)
453 break;
454
455 ret = -EINVAL;
456
457 if (attr.config != 0xc00000000002a823)
458 break;
459 if (attr.config1 != 0x8000400000000145)
460 break;
461 if (attr.config2 != 0x0400000020041d07)
462 break;
463
464 ret = 0;
465 } while (0);
466
467 test_format_dir_put(format);
468 return ret;
469}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
new file mode 100644
index 000000000000..68c0db965e1f
--- /dev/null
+++ b/tools/perf/util/pmu.h
@@ -0,0 +1,41 @@
1#ifndef __PMU_H
2#define __PMU_H
3
4#include <linux/bitops.h>
5#include "../../../include/linux/perf_event.h"
6
7enum {
8 PERF_PMU_FORMAT_VALUE_CONFIG,
9 PERF_PMU_FORMAT_VALUE_CONFIG1,
10 PERF_PMU_FORMAT_VALUE_CONFIG2,
11};
12
13#define PERF_PMU_FORMAT_BITS 64
14
15struct perf_pmu__format {
16 char *name;
17 int value;
18 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
19 struct list_head list;
20};
21
22struct perf_pmu {
23 char *name;
24 __u32 type;
25 struct list_head format;
26 struct list_head list;
27};
28
29struct perf_pmu *perf_pmu__find(char *name);
30int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
31 struct list_head *head_terms);
32
33int perf_pmu_wrap(void);
34void perf_pmu_error(struct list_head *list, char *name, char const *msg);
35
36int perf_pmu__new_format(struct list_head *list, char *name,
37 int config, unsigned long *bits);
38void perf_pmu__set_format(unsigned long *bits, long from, long to);
39
40int perf_pmu__test(void);
41#endif /* __PMU_H */
diff --git a/tools/perf/util/pmu.l b/tools/perf/util/pmu.l
new file mode 100644
index 000000000000..a15d9fbd7c0e
--- /dev/null
+++ b/tools/perf/util/pmu.l
@@ -0,0 +1,43 @@
1%option prefix="perf_pmu_"
2
3%{
4#include <stdlib.h>
5#include <linux/bitops.h>
6#include "pmu.h"
7#include "pmu-bison.h"
8
9static int value(int base)
10{
11 long num;
12
13 errno = 0;
14 num = strtoul(perf_pmu_text, NULL, base);
15 if (errno)
16 return PP_ERROR;
17
18 perf_pmu_lval.num = num;
19 return PP_VALUE;
20}
21
22%}
23
24num_dec [0-9]+
25
26%%
27
28{num_dec} { return value(10); }
29config { return PP_CONFIG; }
30config1 { return PP_CONFIG1; }
31config2 { return PP_CONFIG2; }
32- { return '-'; }
33: { return ':'; }
34, { return ','; }
35. { ; }
36\n { ; }
37
38%%
39
40int perf_pmu_wrap(void)
41{
42 return 1;
43}
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
new file mode 100644
index 000000000000..20ea77e93169
--- /dev/null
+++ b/tools/perf/util/pmu.y
@@ -0,0 +1,93 @@
1
2%name-prefix "perf_pmu_"
3%parse-param {struct list_head *format}
4%parse-param {char *name}
5
6%{
7
8#include <linux/compiler.h>
9#include <linux/list.h>
10#include <linux/bitmap.h>
11#include <string.h>
12#include "pmu.h"
13
14extern int perf_pmu_lex (void);
15
16#define ABORT_ON(val) \
17do { \
18 if (val) \
19 YYABORT; \
20} while (0)
21
22%}
23
24%token PP_CONFIG PP_CONFIG1 PP_CONFIG2
25%token PP_VALUE PP_ERROR
26%type <num> PP_VALUE
27%type <bits> bit_term
28%type <bits> bits
29
30%union
31{
32 unsigned long num;
33 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
34}
35
36%%
37
38format:
39format format_term
40|
41format_term
42
43format_term:
44PP_CONFIG ':' bits
45{
46 ABORT_ON(perf_pmu__new_format(format, name,
47 PERF_PMU_FORMAT_VALUE_CONFIG,
48 $3));
49}
50|
51PP_CONFIG1 ':' bits
52{
53 ABORT_ON(perf_pmu__new_format(format, name,
54 PERF_PMU_FORMAT_VALUE_CONFIG1,
55 $3));
56}
57|
58PP_CONFIG2 ':' bits
59{
60 ABORT_ON(perf_pmu__new_format(format, name,
61 PERF_PMU_FORMAT_VALUE_CONFIG2,
62 $3));
63}
64
65bits:
66bits ',' bit_term
67{
68 bitmap_or($$, $1, $3, 64);
69}
70|
71bit_term
72{
73 memcpy($$, $1, sizeof($1));
74}
75
76bit_term:
77PP_VALUE '-' PP_VALUE
78{
79 perf_pmu__set_format($$, $1, $3);
80}
81|
82PP_VALUE
83{
84 perf_pmu__set_format($$, $1, 0);
85}
86
87%%
88
89void perf_pmu_error(struct list_head *list __used,
90 char *name __used,
91 char const *msg __used)
92{
93}
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 2cc162d3b78c..d448984ed789 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -972,10 +972,12 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
972 struct dwarf_callback_param *param = data; 972 struct dwarf_callback_param *param = data;
973 struct probe_finder *pf = param->data; 973 struct probe_finder *pf = param->data;
974 struct perf_probe_point *pp = &pf->pev->point; 974 struct perf_probe_point *pp = &pf->pev->point;
975 Dwarf_Attribute attr;
975 976
976 /* Check tag and diename */ 977 /* Check tag and diename */
977 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 978 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
978 !die_compare_name(sp_die, pp->function)) 979 !die_compare_name(sp_die, pp->function) ||
980 dwarf_attr(sp_die, DW_AT_declaration, &attr))
979 return DWARF_CB_OK; 981 return DWARF_CB_OK;
980 982
981 /* Check declared file */ 983 /* Check declared file */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 002ebbf59f48..9412e3b05f68 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -140,6 +140,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
140 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 140 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
141 INIT_LIST_HEAD(&self->ordered_samples.to_free); 141 INIT_LIST_HEAD(&self->ordered_samples.to_free);
142 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 142 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
143 hists__init(&self->hists);
143 144
144 if (mode == O_RDONLY) { 145 if (mode == O_RDONLY) {
145 if (perf_session__open(self, force) < 0) 146 if (perf_session__open(self, force) < 0)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 5dd83c3e2c0c..c0a028c3ebaf 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,6 +1,5 @@
1#include <dirent.h> 1#include <dirent.h>
2#include <errno.h> 2#include <errno.h>
3#include <libgen.h>
4#include <stdlib.h> 3#include <stdlib.h>
5#include <stdio.h> 4#include <stdio.h>
6#include <string.h> 5#include <string.h>
@@ -51,6 +50,8 @@ struct symbol_conf symbol_conf = {
51 50
52int dso__name_len(const struct dso *dso) 51int dso__name_len(const struct dso *dso)
53{ 52{
53 if (!dso)
54 return strlen("[unknown]");
54 if (verbose) 55 if (verbose)
55 return dso->long_name_len; 56 return dso->long_name_len;
56 57
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index a4088ced1e64..dfd1bd8371a4 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -722,7 +722,7 @@ static char *event_read_name(void)
722static int event_read_id(void) 722static int event_read_id(void)
723{ 723{
724 char *token; 724 char *token;
725 int id; 725 int id = -1;
726 726
727 if (read_expected_item(EVENT_ITEM, "ID") < 0) 727 if (read_expected_item(EVENT_ITEM, "ID") < 0)
728 return -1; 728 return -1;
@@ -731,15 +731,13 @@ static int event_read_id(void)
731 return -1; 731 return -1;
732 732
733 if (read_expect_type(EVENT_ITEM, &token) < 0) 733 if (read_expect_type(EVENT_ITEM, &token) < 0)
734 goto fail; 734 goto free;
735 735
736 id = strtoul(token, NULL, 0); 736 id = strtoul(token, NULL, 0);
737 free_token(token);
738 return id;
739 737
740 fail: 738 free:
741 free_token(token); 739 free_token(token);
742 return -1; 740 return id;
743} 741}
744 742
745static int field_is_string(struct format_field *field) 743static int field_is_string(struct format_field *field)
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index 84d761b730c1..6ee82f60feaf 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -49,6 +49,8 @@ int ui_browser__warning(struct ui_browser *browser, int timeout,
49 const char *format, ...); 49 const char *format, ...);
50int ui_browser__help_window(struct ui_browser *browser, const char *text); 50int ui_browser__help_window(struct ui_browser *browser, const char *text);
51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); 51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
52int ui_browser__input_window(const char *title, const char *text, char *input,
53 const char *exit_msg, int delay_sec);
52 54
53void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); 55void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
54unsigned int ui_browser__argv_refresh(struct ui_browser *browser); 56unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index fa530fcc764a..d7a1c4afe28b 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -879,6 +879,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
879 char *options[16]; 879 char *options[16];
880 int nr_options = 0; 880 int nr_options = 0;
881 int key = -1; 881 int key = -1;
882 char buf[64];
882 883
883 if (browser == NULL) 884 if (browser == NULL)
884 return -1; 885 return -1;
@@ -933,6 +934,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
933 goto zoom_dso; 934 goto zoom_dso;
934 case 't': 935 case 't':
935 goto zoom_thread; 936 goto zoom_thread;
937 case 's':
938 if (ui_browser__input_window("Symbol to show",
939 "Please enter the name of symbol you want to see",
940 buf, "ENTER: OK, ESC: Cancel",
941 delay_secs * 2) == K_ENTER) {
942 self->symbol_filter_str = *buf ? buf : NULL;
943 hists__filter_by_symbol(self);
944 hist_browser__reset(browser);
945 }
946 continue;
936 case K_F1: 947 case K_F1:
937 case 'h': 948 case 'h':
938 case '?': 949 case '?':
@@ -950,7 +961,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
950 "C Collapse all callchains\n" 961 "C Collapse all callchains\n"
951 "E Expand all callchains\n" 962 "E Expand all callchains\n"
952 "d Zoom into current DSO\n" 963 "d Zoom into current DSO\n"
953 "t Zoom into current Thread"); 964 "t Zoom into current Thread\n"
965 "s Filter symbol by name");
954 continue; 966 continue;
955 case K_ENTER: 967 case K_ENTER:
956 case K_RIGHT: 968 case K_RIGHT:
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h
index 3458b1985761..809eca5707fa 100644
--- a/tools/perf/util/ui/keysyms.h
+++ b/tools/perf/util/ui/keysyms.h
@@ -16,6 +16,8 @@
16#define K_TAB '\t' 16#define K_TAB '\t'
17#define K_UNTAB SL_KEY_UNTAB 17#define K_UNTAB SL_KEY_UNTAB
18#define K_UP SL_KEY_UP 18#define K_UP SL_KEY_UP
19#define K_BKSPC 0x7f
20#define K_DEL SL_KEY_DELETE
19 21
20/* Not really keys */ 22/* Not really keys */
21#define K_TIMER -1 23#define K_TIMER -1
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index 45daa7c41dad..ad4374a16bb0 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -69,6 +69,88 @@ int ui__popup_menu(int argc, char * const argv[])
69 return popup_menu__run(&menu); 69 return popup_menu__run(&menu);
70} 70}
71 71
72int ui_browser__input_window(const char *title, const char *text, char *input,
73 const char *exit_msg, int delay_secs)
74{
75 int x, y, len, key;
76 int max_len = 60, nr_lines = 0;
77 static char buf[50];
78 const char *t;
79
80 t = text;
81 while (1) {
82 const char *sep = strchr(t, '\n');
83
84 if (sep == NULL)
85 sep = strchr(t, '\0');
86 len = sep - t;
87 if (max_len < len)
88 max_len = len;
89 ++nr_lines;
90 if (*sep == '\0')
91 break;
92 t = sep + 1;
93 }
94
95 max_len += 2;
96 nr_lines += 8;
97 y = SLtt_Screen_Rows / 2 - nr_lines / 2;
98 x = SLtt_Screen_Cols / 2 - max_len / 2;
99
100 SLsmg_set_color(0);
101 SLsmg_draw_box(y, x++, nr_lines, max_len);
102 if (title) {
103 SLsmg_gotorc(y, x + 1);
104 SLsmg_write_string((char *)title);
105 }
106 SLsmg_gotorc(++y, x);
107 nr_lines -= 7;
108 max_len -= 2;
109 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
110 nr_lines, max_len, 1);
111 y += nr_lines;
112 len = 5;
113 while (len--) {
114 SLsmg_gotorc(y + len - 1, x);
115 SLsmg_write_nstring((char *)" ", max_len);
116 }
117 SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
118
119 SLsmg_gotorc(y + 3, x);
120 SLsmg_write_nstring((char *)exit_msg, max_len);
121 SLsmg_refresh();
122
123 x += 2;
124 len = 0;
125 key = ui__getch(delay_secs);
126 while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
127 if (key == K_BKSPC) {
128 if (len == 0)
129 goto next_key;
130 SLsmg_gotorc(y, x + --len);
131 SLsmg_write_char(' ');
132 } else {
133 buf[len] = key;
134 SLsmg_gotorc(y, x + len++);
135 SLsmg_write_char(key);
136 }
137 SLsmg_refresh();
138
139 /* XXX more graceful overflow handling needed */
140 if (len == sizeof(buf) - 1) {
141 ui_helpline__push("maximum size of symbol name reached!");
142 key = K_ENTER;
143 break;
144 }
145next_key:
146 key = ui__getch(delay_secs);
147 }
148
149 buf[len] = '\0';
150 strncpy(input, buf, len+1);
151 return key;
152}
153
72int ui__question_window(const char *title, const char *text, 154int ui__question_window(const char *title, const char *text,
73 const char *exit_msg, int delay_secs) 155 const char *exit_msg, int delay_secs)
74{ 156{