aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-07-04 16:13:55 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-07-04 16:13:55 -0400
commit404c3bc30cb1361e1b3533643326ab472d24a618 (patch)
tree156cc9032c8aee17167d926c5bdae009ba8f36d2 /tools/perf
parent6795a524f0b049ceb5417d5036ab5e233345b900 (diff)
parent6887a4131da3adaab011613776d865f4bcfb5678 (diff)
Merge commit 'v3.5-rc5' into next
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-evlist.txt8
-rw-r--r--tools/perf/Documentation/perf-probe.txt19
-rw-r--r--tools/perf/Documentation/perf-record.txt2
-rw-r--r--tools/perf/Documentation/perfconfig.example9
-rw-r--r--tools/perf/MANIFEST2
-rw-r--r--tools/perf/Makefile142
-rw-r--r--tools/perf/builtin-annotate.c2
-rw-r--r--tools/perf/builtin-buildid-list.c6
-rw-r--r--tools/perf/builtin-evlist.c103
-rw-r--r--tools/perf/builtin-inject.c5
-rw-r--r--tools/perf/builtin-kmem.c6
-rw-r--r--tools/perf/builtin-lock.c26
-rw-r--r--tools/perf/builtin-probe.c86
-rw-r--r--tools/perf/builtin-record.c81
-rw-r--r--tools/perf/builtin-report.c56
-rw-r--r--tools/perf/builtin-sched.c42
-rw-r--r--tools/perf/builtin-script.c2
-rw-r--r--tools/perf/builtin-stat.c140
-rw-r--r--tools/perf/builtin-test.c535
-rw-r--r--tools/perf/builtin-top.c81
-rw-r--r--tools/perf/design.txt7
-rw-r--r--tools/perf/perf.h10
-rw-r--r--tools/perf/ui/browser.c (renamed from tools/perf/util/ui/browser.c)298
-rw-r--r--tools/perf/ui/browser.h (renamed from tools/perf/util/ui/browser.h)10
-rw-r--r--tools/perf/ui/browsers/annotate.c951
-rw-r--r--tools/perf/ui/browsers/hists.c (renamed from tools/perf/util/ui/browsers/hists.c)360
-rw-r--r--tools/perf/ui/browsers/map.c (renamed from tools/perf/util/ui/browsers/map.c)6
-rw-r--r--tools/perf/ui/browsers/map.h (renamed from tools/perf/util/ui/browsers/map.h)0
-rw-r--r--tools/perf/ui/gtk/browser.c (renamed from tools/perf/util/gtk/browser.c)31
-rw-r--r--tools/perf/ui/gtk/gtk.h (renamed from tools/perf/util/gtk/gtk.h)0
-rw-r--r--tools/perf/ui/gtk/setup.c12
-rw-r--r--tools/perf/ui/helpline.c (renamed from tools/perf/util/ui/helpline.c)0
-rw-r--r--tools/perf/ui/helpline.h (renamed from tools/perf/util/ui/helpline.h)0
-rw-r--r--tools/perf/ui/keysyms.h (renamed from tools/perf/util/ui/keysyms.h)0
-rw-r--r--tools/perf/ui/libslang.h (renamed from tools/perf/util/ui/libslang.h)0
-rw-r--r--tools/perf/ui/progress.c (renamed from tools/perf/util/ui/progress.c)0
-rw-r--r--tools/perf/ui/progress.h (renamed from tools/perf/util/ui/progress.h)0
-rw-r--r--tools/perf/ui/setup.c46
-rw-r--r--tools/perf/ui/tui/setup.c (renamed from tools/perf/util/ui/setup.c)77
-rw-r--r--tools/perf/ui/ui.h (renamed from tools/perf/util/ui/ui.h)0
-rw-r--r--tools/perf/ui/util.c (renamed from tools/perf/util/ui/util.c)0
-rw-r--r--tools/perf/ui/util.h (renamed from tools/perf/util/ui/util.h)0
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN2
-rw-r--r--tools/perf/util/annotate.c599
-rw-r--r--tools/perf/util/annotate.h67
-rw-r--r--tools/perf/util/build-id.c2
-rw-r--r--tools/perf/util/cache.h24
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/config.c2
-rw-r--r--tools/perf/util/debug.c1
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/evlist.c33
-rw-r--r--tools/perf/util/evlist.h8
-rw-r--r--tools/perf/util/evsel.c140
-rw-r--r--tools/perf/util/evsel.h3
-rw-r--r--tools/perf/util/header.c77
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/hist.c9
-rw-r--r--tools/perf/util/hist.h4
-rw-r--r--tools/perf/util/include/linux/bitops.h2
-rw-r--r--tools/perf/util/pager.c4
-rw-r--r--tools/perf/util/parse-events-test.c625
-rw-r--r--tools/perf/util/parse-events.c141
-rw-r--r--tools/perf/util/parse-events.h43
-rw-r--r--tools/perf/util/parse-events.l28
-rw-r--r--tools/perf/util/parse-events.y93
-rw-r--r--tools/perf/util/pmu.c74
-rw-r--r--tools/perf/util/probe-event.c418
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c16
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c16
-rw-r--r--tools/perf/util/session.c203
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/symbol.c57
-rw-r--r--tools/perf/util/symbol.h36
-rw-r--r--tools/perf/util/target.c142
-rw-r--r--tools/perf/util/target.h65
-rw-r--r--tools/perf/util/thread_map.c21
-rw-r--r--tools/perf/util/thread_map.h2
-rw-r--r--tools/perf/util/top.c19
-rw-r--r--tools/perf/util/top.h6
-rw-r--r--tools/perf/util/trace-event-info.c4
-rw-r--r--tools/perf/util/trace-event-parse.c3142
-rw-r--r--tools/perf/util/trace-event-read.c44
-rw-r--r--tools/perf/util/trace-event.h269
-rw-r--r--tools/perf/util/types.h5
-rw-r--r--tools/perf/util/ui/browsers/annotate.c433
-rw-r--r--tools/perf/util/usage.c38
-rw-r--r--tools/perf/util/util.c10
-rw-r--r--tools/perf/util/util.h5
91 files changed, 4819 insertions, 5295 deletions
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 0507ec7bad71..15217345c2fa 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -20,6 +20,14 @@ OPTIONS
20--input=:: 20--input=::
21 Input file name. (default: perf.data unless stdin is a fifo) 21 Input file name. (default: perf.data unless stdin is a fifo)
22 22
23-F::
24--freq=::
25 Show just the sample frequency used for each event.
26
27-v::
28--verbose=::
29 Show all fields.
30
23SEE ALSO 31SEE ALSO
24-------- 32--------
25linkperf:perf-record[1], linkperf:perf-list[1], 33linkperf:perf-record[1], linkperf:perf-list[1],
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 2780d9ce48bf..b715cb71592b 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -77,7 +77,8 @@ OPTIONS
77 77
78-F:: 78-F::
79--funcs:: 79--funcs::
80 Show available functions in given module or kernel. 80 Show available functions in given module or kernel. With -x/--exec,
81 can also list functions in a user space executable / shared library.
81 82
82--filter=FILTER:: 83--filter=FILTER::
83 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob 84 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
@@ -98,6 +99,15 @@ OPTIONS
98--max-probes:: 99--max-probes::
99 Set the maximum number of probe points for an event. Default is 128. 100 Set the maximum number of probe points for an event. Default is 128.
100 101
102-x::
103--exec=PATH::
104 Specify path to the executable or shared library file for user
105 space tracing. Can also be used with --funcs option.
106
107In absence of -m/-x options, perf probe checks if the first argument after
108the options is an absolute path name. If its an absolute path, perf probe
109uses it as a target module/target user space binary to probe.
110
101PROBE SYNTAX 111PROBE SYNTAX
102------------ 112------------
103Probe points are defined by following syntax. 113Probe points are defined by following syntax.
@@ -182,6 +192,13 @@ Delete all probes on schedule().
182 192
183 ./perf probe --del='schedule*' 193 ./perf probe --del='schedule*'
184 194
195Add probes at zfree() function on /bin/zsh
196
197 ./perf probe -x /bin/zsh zfree or ./perf probe /bin/zsh zfree
198
199Add probes at malloc() function on libc
200
201 ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc
185 202
186SEE ALSO 203SEE ALSO
187-------- 204--------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index a1386b2fff00..b38a1f9ad460 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -168,7 +168,7 @@ following filters are defined:
168 - any: any type of branches 168 - any: any type of branches
169 - any_call: any function call or system call 169 - any_call: any function call or system call
170 - any_ret: any function return or system call return 170 - any_ret: any function return or system call return
171 - any_ind: any indirect branch 171 - ind_call: any indirect branch
172 - u: only when the branch target is at the user level 172 - u: only when the branch target is at the user level
173 - k: only when the branch target is in the kernel 173 - k: only when the branch target is in the kernel
174 - hv: only when the target is at the hypervisor level 174 - hv: only when the target is at the hypervisor level
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
index d1448668f4d4..767ea2436e1c 100644
--- a/tools/perf/Documentation/perfconfig.example
+++ b/tools/perf/Documentation/perfconfig.example
@@ -6,6 +6,7 @@
6 normal = black, lightgray 6 normal = black, lightgray
7 selected = lightgray, magenta 7 selected = lightgray, magenta
8 code = blue, lightgray 8 code = blue, lightgray
9 addr = magenta, lightgray
9 10
10[tui] 11[tui]
11 12
@@ -18,3 +19,11 @@
18 19
19 # Default, disable using /dev/null 20 # Default, disable using /dev/null
20 dir = /root/.debug 21 dir = /root/.debug
22
23[annotate]
24
25 # Defaults
26 hide_src_code = false
27 use_offset = true
28 jump_arrows = true
29 show_nr_jumps = false
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 5476bc0a1eac..b4b572e8c100 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,4 +1,6 @@
1tools/perf 1tools/perf
2tools/scripts
3tools/lib/traceevent
2include/linux/const.h 4include/linux/const.h
3include/linux/perf_event.h 5include/linux/perf_event.h
4include/linux/rbtree.h 6include/linux/rbtree.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 03059e75665a..0eee64cfe9a0 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1,18 +1,10 @@
1ifeq ("$(origin O)", "command line") 1include ../scripts/Makefile.include
2 OUTPUT := $(O)/
3endif
4 2
5# The default target of this Makefile is... 3# The default target of this Makefile is...
6all: 4all:
7 5
8include config/utilities.mak 6include config/utilities.mak
9 7
10ifneq ($(OUTPUT),)
11# check that the output directory actually exists
12OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
13$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
14endif
15
16# Define V to have a more verbose compile. 8# Define V to have a more verbose compile.
17# 9#
18# Define O to save output files in a separate directory. 10# Define O to save output files in a separate directory.
@@ -84,39 +76,20 @@ ifneq ($(WERROR),0)
84 CFLAGS_WERROR := -Werror 76 CFLAGS_WERROR := -Werror
85endif 77endif
86 78
87#
88# Include saner warnings here, which can catch bugs:
89#
90
91EXTRA_WARNINGS := -Wformat
92EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
93EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
94EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
95EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
96EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
97EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
98EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
99EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
100EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
101EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
102EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
103EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
104EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
105EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
106EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes
107EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs
108EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
109EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
110EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
111
112ifeq ("$(origin DEBUG)", "command line") 79ifeq ("$(origin DEBUG)", "command line")
113 PERF_DEBUG = $(DEBUG) 80 PERF_DEBUG = $(DEBUG)
114endif 81endif
115ifndef PERF_DEBUG 82ifndef PERF_DEBUG
116 CFLAGS_OPTIMIZE = -O6 83 CFLAGS_OPTIMIZE = -O6 -D_FORTIFY_SOURCE=2
84endif
85
86ifdef PARSER_DEBUG
87 PARSER_DEBUG_BISON := -t
88 PARSER_DEBUG_FLEX := -d
89 PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
117endif 90endif
118 91
119CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 92CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
120EXTLIBS = -lpthread -lrt -lelf -lm 93EXTLIBS = -lpthread -lrt -lelf -lm
121ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 94ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
122ALL_LDFLAGS = $(LDFLAGS) 95ALL_LDFLAGS = $(LDFLAGS)
@@ -182,7 +155,7 @@ endif
182 155
183### --- END CONFIGURATION SECTION --- 156### --- END CONFIGURATION SECTION ---
184 157
185BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 158BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
186BASIC_LDFLAGS = 159BASIC_LDFLAGS =
187 160
188# Guard against environment variables 161# Guard against environment variables
@@ -211,6 +184,17 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
211 184
212SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) 185SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
213 186
187TRACE_EVENT_DIR = ../lib/traceevent/
188
189ifeq ("$(origin O)", "command line")
190 TE_PATH=$(OUTPUT)/
191else
192 TE_PATH=$(TRACE_EVENT_DIR)/
193endif
194
195LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
196TE_LIB := -L$(TE_PATH) -ltraceevent
197
214# 198#
215# Single 'perf' binary right now: 199# Single 'perf' binary right now:
216# 200#
@@ -234,14 +218,14 @@ endif
234 218
235export PERL_PATH 219export PERL_PATH
236 220
237FLEX = $(CROSS_COMPILE)flex 221FLEX = flex
238BISON= $(CROSS_COMPILE)bison 222BISON= bison
239 223
240$(OUTPUT)util/parse-events-flex.c: util/parse-events.l 224$(OUTPUT)util/parse-events-flex.c: util/parse-events.l
241 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c 225 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
242 226
243$(OUTPUT)util/parse-events-bison.c: util/parse-events.y 227$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
244 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c 228 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c
245 229
246$(OUTPUT)util/pmu-flex.c: util/pmu.l 230$(OUTPUT)util/pmu-flex.c: util/pmu.l
247 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c 231 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
@@ -333,6 +317,8 @@ LIB_H += util/cpumap.h
333LIB_H += util/top.h 317LIB_H += util/top.h
334LIB_H += $(ARCH_INCLUDE) 318LIB_H += $(ARCH_INCLUDE)
335LIB_H += util/cgroup.h 319LIB_H += util/cgroup.h
320LIB_H += $(TRACE_EVENT_DIR)event-parse.h
321LIB_H += util/target.h
336 322
337LIB_OBJS += $(OUTPUT)util/abspath.o 323LIB_OBJS += $(OUTPUT)util/abspath.o
338LIB_OBJS += $(OUTPUT)util/alias.o 324LIB_OBJS += $(OUTPUT)util/alias.o
@@ -352,6 +338,7 @@ LIB_OBJS += $(OUTPUT)util/help.o
352LIB_OBJS += $(OUTPUT)util/levenshtein.o 338LIB_OBJS += $(OUTPUT)util/levenshtein.o
353LIB_OBJS += $(OUTPUT)util/parse-options.o 339LIB_OBJS += $(OUTPUT)util/parse-options.o
354LIB_OBJS += $(OUTPUT)util/parse-events.o 340LIB_OBJS += $(OUTPUT)util/parse-events.o
341LIB_OBJS += $(OUTPUT)util/parse-events-test.o
355LIB_OBJS += $(OUTPUT)util/path.o 342LIB_OBJS += $(OUTPUT)util/path.o
356LIB_OBJS += $(OUTPUT)util/rbtree.o 343LIB_OBJS += $(OUTPUT)util/rbtree.o
357LIB_OBJS += $(OUTPUT)util/bitmap.o 344LIB_OBJS += $(OUTPUT)util/bitmap.o
@@ -394,6 +381,7 @@ LIB_OBJS += $(OUTPUT)util/util.o
394LIB_OBJS += $(OUTPUT)util/xyarray.o 381LIB_OBJS += $(OUTPUT)util/xyarray.o
395LIB_OBJS += $(OUTPUT)util/cpumap.o 382LIB_OBJS += $(OUTPUT)util/cpumap.o
396LIB_OBJS += $(OUTPUT)util/cgroup.o 383LIB_OBJS += $(OUTPUT)util/cgroup.o
384LIB_OBJS += $(OUTPUT)util/target.o
397 385
398BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 386BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
399 387
@@ -429,7 +417,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
429BUILTIN_OBJS += $(OUTPUT)builtin-test.o 417BUILTIN_OBJS += $(OUTPUT)builtin-test.o
430BUILTIN_OBJS += $(OUTPUT)builtin-inject.o 418BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
431 419
432PERFLIBS = $(LIB_FILE) 420PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
433 421
434# Files needed for the python binding, perf.so 422# Files needed for the python binding, perf.so
435# pyrf is just an internal name needed for all those wrappers. 423# pyrf is just an internal name needed for all those wrappers.
@@ -506,22 +494,23 @@ else
506 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 494 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
507 BASIC_CFLAGS += -I/usr/include/slang 495 BASIC_CFLAGS += -I/usr/include/slang
508 EXTLIBS += -lnewt -lslang 496 EXTLIBS += -lnewt -lslang
509 LIB_OBJS += $(OUTPUT)util/ui/setup.o 497 LIB_OBJS += $(OUTPUT)ui/setup.o
510 LIB_OBJS += $(OUTPUT)util/ui/browser.o 498 LIB_OBJS += $(OUTPUT)ui/browser.o
511 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 499 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
512 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 500 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
513 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 501 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
514 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 502 LIB_OBJS += $(OUTPUT)ui/helpline.o
515 LIB_OBJS += $(OUTPUT)util/ui/progress.o 503 LIB_OBJS += $(OUTPUT)ui/progress.o
516 LIB_OBJS += $(OUTPUT)util/ui/util.o 504 LIB_OBJS += $(OUTPUT)ui/util.o
517 LIB_H += util/ui/browser.h 505 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
518 LIB_H += util/ui/browsers/map.h 506 LIB_H += ui/browser.h
519 LIB_H += util/ui/helpline.h 507 LIB_H += ui/browsers/map.h
520 LIB_H += util/ui/keysyms.h 508 LIB_H += ui/helpline.h
521 LIB_H += util/ui/libslang.h 509 LIB_H += ui/keysyms.h
522 LIB_H += util/ui/progress.h 510 LIB_H += ui/libslang.h
523 LIB_H += util/ui/util.h 511 LIB_H += ui/progress.h
524 LIB_H += util/ui/ui.h 512 LIB_H += ui/util.h
513 LIB_H += ui/ui.h
525 endif 514 endif
526endif 515endif
527 516
@@ -535,7 +524,12 @@ else
535 else 524 else
536 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0) 525 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
537 EXTLIBS += $(shell pkg-config --libs gtk+-2.0) 526 EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
538 LIB_OBJS += $(OUTPUT)util/gtk/browser.o 527 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
528 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
529 # Make sure that it'd be included only once.
530 ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
531 LIB_OBJS += $(OUTPUT)ui/setup.o
532 endif
539 endif 533 endif
540endif 534endif
541 535
@@ -678,18 +672,6 @@ else
678 endif 672 endif
679endif 673endif
680 674
681ifneq ($(findstring $(MAKEFLAGS),s),s)
682ifndef V
683 QUIET_CC = @echo ' ' CC $@;
684 QUIET_AR = @echo ' ' AR $@;
685 QUIET_LINK = @echo ' ' LINK $@;
686 QUIET_MKDIR = @echo ' ' MKDIR $@;
687 QUIET_GEN = @echo ' ' GEN $@;
688 QUIET_FLEX = @echo ' ' FLEX $@;
689 QUIET_BISON = @echo ' ' BISON $@;
690endif
691endif
692
693ifdef ASCIIDOC8 675ifdef ASCIIDOC8
694 export ASCIIDOC8 676 export ASCIIDOC8
695endif 677endif
@@ -774,10 +756,10 @@ $(OUTPUT)perf.o perf.spec \
774# over the general rule for .o 756# over the general rule for .o
775 757
776$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS 758$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
777 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $< 759 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Iutil/ -w $<
778 760
779$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS 761$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
780 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $< 762 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -Iutil/ -w $<
781 763
782$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 764$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
783 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 765 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
@@ -800,16 +782,16 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
800$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 782$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
801 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 783 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
802 784
803$(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS 785$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
804 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 786 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
805 787
806$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 788$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
807 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 789 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
808 790
809$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 791$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
810 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 792 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
811 793
812$(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS 794$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
813 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 795 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
814 796
815$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 797$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
@@ -844,6 +826,10 @@ $(sort $(dir $(DIRECTORY_DEPS))):
844$(LIB_FILE): $(LIB_OBJS) 826$(LIB_FILE): $(LIB_OBJS)
845 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 827 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
846 828
829# libtraceevent.a
830$(LIBTRACEEVENT):
831 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) $(COMMAND_O) libtraceevent.a
832
847help: 833help:
848 @echo 'Perf make targets:' 834 @echo 'Perf make targets:'
849 @echo ' doc - make *all* documentation (see below)' 835 @echo ' doc - make *all* documentation (see below)'
@@ -990,6 +976,6 @@ clean:
990 $(RM) $(OUTPUT)util/*-{bison,flex}* 976 $(RM) $(OUTPUT)util/*-{bison,flex}*
991 $(python-clean) 977 $(python-clean)
992 978
993.PHONY: all install clean strip 979.PHONY: all install clean strip $(LIBTRACEEVENT)
994.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 980.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
995.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 981.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 806e0a286634..67522cf87405 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -215,7 +215,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
215 } 215 }
216 216
217 if (total_nr_samples == 0) { 217 if (total_nr_samples == 0) {
218 ui__warning("The %s file has no samples!\n", session->filename); 218 ui__error("The %s file has no samples!\n", session->filename);
219 goto out_delete; 219 goto out_delete;
220 } 220 }
221out_delete: 221out_delete:
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 52480467e9ff..6b2bcfbde150 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -84,7 +84,11 @@ static int perf_session__list_build_ids(void)
84 if (filename__fprintf_build_id(session->filename, stdout)) 84 if (filename__fprintf_build_id(session->filename, stdout))
85 goto out; 85 goto out;
86 86
87 if (with_hits) 87 /*
88 * in pipe-mode, the only way to get the buildids is to parse
89 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
90 */
91 if (with_hits || session->fd_pipe)
88 perf_session__process_events(session, &build_id__mark_dso_hit_ops); 92 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
89 93
90 perf_session__fprintf_dsos_buildid(session, stdout, with_hits); 94 perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 26760322c4f4..acd78dc28341 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,9 +15,40 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17 17
18static const char *input_name; 18struct perf_attr_details {
19 bool freq;
20 bool verbose;
21};
22
23static int comma_printf(bool *first, const char *fmt, ...)
24{
25 va_list args;
26 int ret = 0;
27
28 if (!*first) {
29 ret += printf(",");
30 } else {
31 ret += printf(":");
32 *first = false;
33 }
34
35 va_start(args, fmt);
36 ret += vprintf(fmt, args);
37 va_end(args);
38 return ret;
39}
40
41static int __if_print(bool *first, const char *field, u64 value)
42{
43 if (value == 0)
44 return 0;
45
46 return comma_printf(first, " %s: %" PRIu64, field, value);
47}
48
49#define if_print(field) __if_print(&first, #field, pos->attr.field)
19 50
20static int __cmd_evlist(void) 51static int __cmd_evlist(const char *input_name, struct perf_attr_details *details)
21{ 52{
22 struct perf_session *session; 53 struct perf_session *session;
23 struct perf_evsel *pos; 54 struct perf_evsel *pos;
@@ -26,8 +57,52 @@ static int __cmd_evlist(void)
26 if (session == NULL) 57 if (session == NULL)
27 return -ENOMEM; 58 return -ENOMEM;
28 59
29 list_for_each_entry(pos, &session->evlist->entries, node) 60 list_for_each_entry(pos, &session->evlist->entries, node) {
30 printf("%s\n", event_name(pos)); 61 bool first = true;
62
63 printf("%s", event_name(pos));
64
65 if (details->verbose || details->freq) {
66 comma_printf(&first, " sample_freq=%" PRIu64,
67 (u64)pos->attr.sample_freq);
68 }
69
70 if (details->verbose) {
71 if_print(type);
72 if_print(config);
73 if_print(config1);
74 if_print(config2);
75 if_print(size);
76 if_print(sample_type);
77 if_print(read_format);
78 if_print(disabled);
79 if_print(inherit);
80 if_print(pinned);
81 if_print(exclusive);
82 if_print(exclude_user);
83 if_print(exclude_kernel);
84 if_print(exclude_hv);
85 if_print(exclude_idle);
86 if_print(mmap);
87 if_print(comm);
88 if_print(freq);
89 if_print(inherit_stat);
90 if_print(enable_on_exec);
91 if_print(task);
92 if_print(watermark);
93 if_print(precise_ip);
94 if_print(mmap_data);
95 if_print(sample_id_all);
96 if_print(exclude_host);
97 if_print(exclude_guest);
98 if_print(__reserved_1);
99 if_print(wakeup_events);
100 if_print(bp_type);
101 if_print(branch_sample_type);
102 }
103
104 putchar('\n');
105 }
31 106
32 perf_session__delete(session); 107 perf_session__delete(session);
33 return 0; 108 return 0;
@@ -38,17 +113,23 @@ static const char * const evlist_usage[] = {
38 NULL 113 NULL
39}; 114};
40 115
41static const struct option options[] = {
42 OPT_STRING('i', "input", &input_name, "file",
43 "input file name"),
44 OPT_END()
45};
46
47int cmd_evlist(int argc, const char **argv, const char *prefix __used) 116int cmd_evlist(int argc, const char **argv, const char *prefix __used)
48{ 117{
118 struct perf_attr_details details = { .verbose = false, };
119 const char *input_name = NULL;
120 const struct option options[] = {
121 OPT_STRING('i', "input", &input_name, "file",
122 "Input file name"),
123 OPT_BOOLEAN('F', "freq", &details.freq,
124 "Show the sample frequency"),
125 OPT_BOOLEAN('v', "verbose", &details.verbose,
126 "Show all event attr details"),
127 OPT_END()
128 };
129
49 argc = parse_options(argc, argv, options, evlist_usage, 0); 130 argc = parse_options(argc, argv, options, evlist_usage, 0);
50 if (argc) 131 if (argc)
51 usage_with_options(evlist_usage, options); 132 usage_with_options(evlist_usage, options);
52 133
53 return __cmd_evlist(); 134 return __cmd_evlist(input_name, &details);
54} 135}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 09c106193e65..3beab489afc5 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -60,6 +60,11 @@ static int perf_event__repipe_tracing_data_synth(union perf_event *event,
60static int perf_event__repipe_attr(union perf_event *event, 60static int perf_event__repipe_attr(union perf_event *event,
61 struct perf_evlist **pevlist __used) 61 struct perf_evlist **pevlist __used)
62{ 62{
63 int ret;
64 ret = perf_event__process_attr(event, pevlist);
65 if (ret)
66 return ret;
67
63 return perf_event__repipe_synth(NULL, event, NULL); 68 return perf_event__repipe_synth(NULL, event, NULL);
64} 69}
65 70
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 39104c0beea3..547af48deb4f 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -192,7 +192,7 @@ static void insert_caller_stat(unsigned long call_site,
192} 192}
193 193
194static void process_alloc_event(void *data, 194static void process_alloc_event(void *data,
195 struct event *event, 195 struct event_format *event,
196 int cpu, 196 int cpu,
197 u64 timestamp __used, 197 u64 timestamp __used,
198 struct thread *thread __used, 198 struct thread *thread __used,
@@ -253,7 +253,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr,
253} 253}
254 254
255static void process_free_event(void *data, 255static void process_free_event(void *data,
256 struct event *event, 256 struct event_format *event,
257 int cpu, 257 int cpu,
258 u64 timestamp __used, 258 u64 timestamp __used,
259 struct thread *thread __used) 259 struct thread *thread __used)
@@ -281,7 +281,7 @@ static void process_free_event(void *data,
281static void process_raw_event(union perf_event *raw_event __used, void *data, 281static void process_raw_event(union perf_event *raw_event __used, void *data,
282 int cpu, u64 timestamp, struct thread *thread) 282 int cpu, u64 timestamp, struct thread *thread)
283{ 283{
284 struct event *event; 284 struct event_format *event;
285 int type; 285 int type;
286 286
287 type = trace_parse_common_type(data); 287 type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 12c814838993..fd53319de20d 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -356,25 +356,25 @@ struct trace_release_event {
356 356
357struct trace_lock_handler { 357struct trace_lock_handler {
358 void (*acquire_event)(struct trace_acquire_event *, 358 void (*acquire_event)(struct trace_acquire_event *,
359 struct event *, 359 struct event_format *,
360 int cpu, 360 int cpu,
361 u64 timestamp, 361 u64 timestamp,
362 struct thread *thread); 362 struct thread *thread);
363 363
364 void (*acquired_event)(struct trace_acquired_event *, 364 void (*acquired_event)(struct trace_acquired_event *,
365 struct event *, 365 struct event_format *,
366 int cpu, 366 int cpu,
367 u64 timestamp, 367 u64 timestamp,
368 struct thread *thread); 368 struct thread *thread);
369 369
370 void (*contended_event)(struct trace_contended_event *, 370 void (*contended_event)(struct trace_contended_event *,
371 struct event *, 371 struct event_format *,
372 int cpu, 372 int cpu,
373 u64 timestamp, 373 u64 timestamp,
374 struct thread *thread); 374 struct thread *thread);
375 375
376 void (*release_event)(struct trace_release_event *, 376 void (*release_event)(struct trace_release_event *,
377 struct event *, 377 struct event_format *,
378 int cpu, 378 int cpu,
379 u64 timestamp, 379 u64 timestamp,
380 struct thread *thread); 380 struct thread *thread);
@@ -416,7 +416,7 @@ enum acquire_flags {
416 416
417static void 417static void
418report_lock_acquire_event(struct trace_acquire_event *acquire_event, 418report_lock_acquire_event(struct trace_acquire_event *acquire_event,
419 struct event *__event __used, 419 struct event_format *__event __used,
420 int cpu __used, 420 int cpu __used,
421 u64 timestamp __used, 421 u64 timestamp __used,
422 struct thread *thread __used) 422 struct thread *thread __used)
@@ -480,7 +480,7 @@ end:
480 480
481static void 481static void
482report_lock_acquired_event(struct trace_acquired_event *acquired_event, 482report_lock_acquired_event(struct trace_acquired_event *acquired_event,
483 struct event *__event __used, 483 struct event_format *__event __used,
484 int cpu __used, 484 int cpu __used,
485 u64 timestamp __used, 485 u64 timestamp __used,
486 struct thread *thread __used) 486 struct thread *thread __used)
@@ -536,7 +536,7 @@ end:
536 536
537static void 537static void
538report_lock_contended_event(struct trace_contended_event *contended_event, 538report_lock_contended_event(struct trace_contended_event *contended_event,
539 struct event *__event __used, 539 struct event_format *__event __used,
540 int cpu __used, 540 int cpu __used,
541 u64 timestamp __used, 541 u64 timestamp __used,
542 struct thread *thread __used) 542 struct thread *thread __used)
@@ -583,7 +583,7 @@ end:
583 583
584static void 584static void
585report_lock_release_event(struct trace_release_event *release_event, 585report_lock_release_event(struct trace_release_event *release_event,
586 struct event *__event __used, 586 struct event_format *__event __used,
587 int cpu __used, 587 int cpu __used,
588 u64 timestamp __used, 588 u64 timestamp __used,
589 struct thread *thread __used) 589 struct thread *thread __used)
@@ -647,7 +647,7 @@ static struct trace_lock_handler *trace_handler;
647 647
648static void 648static void
649process_lock_acquire_event(void *data, 649process_lock_acquire_event(void *data,
650 struct event *event __used, 650 struct event_format *event __used,
651 int cpu __used, 651 int cpu __used,
652 u64 timestamp __used, 652 u64 timestamp __used,
653 struct thread *thread __used) 653 struct thread *thread __used)
@@ -666,7 +666,7 @@ process_lock_acquire_event(void *data,
666 666
667static void 667static void
668process_lock_acquired_event(void *data, 668process_lock_acquired_event(void *data,
669 struct event *event __used, 669 struct event_format *event __used,
670 int cpu __used, 670 int cpu __used,
671 u64 timestamp __used, 671 u64 timestamp __used,
672 struct thread *thread __used) 672 struct thread *thread __used)
@@ -684,7 +684,7 @@ process_lock_acquired_event(void *data,
684 684
685static void 685static void
686process_lock_contended_event(void *data, 686process_lock_contended_event(void *data,
687 struct event *event __used, 687 struct event_format *event __used,
688 int cpu __used, 688 int cpu __used,
689 u64 timestamp __used, 689 u64 timestamp __used,
690 struct thread *thread __used) 690 struct thread *thread __used)
@@ -702,7 +702,7 @@ process_lock_contended_event(void *data,
702 702
703static void 703static void
704process_lock_release_event(void *data, 704process_lock_release_event(void *data,
705 struct event *event __used, 705 struct event_format *event __used,
706 int cpu __used, 706 int cpu __used,
707 u64 timestamp __used, 707 u64 timestamp __used,
708 struct thread *thread __used) 708 struct thread *thread __used)
@@ -721,7 +721,7 @@ process_lock_release_event(void *data,
721static void 721static void
722process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread) 722process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
723{ 723{
724 struct event *event; 724 struct event_format *event;
725 int type; 725 int type;
726 726
727 type = trace_parse_common_type(data); 727 type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 4935c09dd5b5..e215ae61b2ae 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -54,6 +54,7 @@ static struct {
54 bool show_ext_vars; 54 bool show_ext_vars;
55 bool show_funcs; 55 bool show_funcs;
56 bool mod_events; 56 bool mod_events;
57 bool uprobes;
57 int nevents; 58 int nevents;
58 struct perf_probe_event events[MAX_PROBES]; 59 struct perf_probe_event events[MAX_PROBES];
59 struct strlist *dellist; 60 struct strlist *dellist;
@@ -75,6 +76,8 @@ static int parse_probe_event(const char *str)
75 return -1; 76 return -1;
76 } 77 }
77 78
79 pev->uprobes = params.uprobes;
80
78 /* Parse a perf-probe command into event */ 81 /* Parse a perf-probe command into event */
79 ret = parse_perf_probe_command(str, pev); 82 ret = parse_perf_probe_command(str, pev);
80 pr_debug("%d arguments\n", pev->nargs); 83 pr_debug("%d arguments\n", pev->nargs);
@@ -82,21 +85,58 @@ static int parse_probe_event(const char *str)
82 return ret; 85 return ret;
83} 86}
84 87
88static int set_target(const char *ptr)
89{
90 int found = 0;
91 const char *buf;
92
93 /*
94 * The first argument after options can be an absolute path
95 * to an executable / library or kernel module.
96 *
97 * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH,
98 * short module name.
99 */
100 if (!params.target && ptr && *ptr == '/') {
101 params.target = ptr;
102 found = 1;
103 buf = ptr + (strlen(ptr) - 3);
104
105 if (strcmp(buf, ".ko"))
106 params.uprobes = true;
107
108 }
109
110 return found;
111}
112
85static int parse_probe_event_argv(int argc, const char **argv) 113static int parse_probe_event_argv(int argc, const char **argv)
86{ 114{
87 int i, len, ret; 115 int i, len, ret, found_target;
88 char *buf; 116 char *buf;
89 117
118 found_target = set_target(argv[0]);
119 if (found_target && argc == 1)
120 return 0;
121
90 /* Bind up rest arguments */ 122 /* Bind up rest arguments */
91 len = 0; 123 len = 0;
92 for (i = 0; i < argc; i++) 124 for (i = 0; i < argc; i++) {
125 if (i == 0 && found_target)
126 continue;
127
93 len += strlen(argv[i]) + 1; 128 len += strlen(argv[i]) + 1;
129 }
94 buf = zalloc(len + 1); 130 buf = zalloc(len + 1);
95 if (buf == NULL) 131 if (buf == NULL)
96 return -ENOMEM; 132 return -ENOMEM;
97 len = 0; 133 len = 0;
98 for (i = 0; i < argc; i++) 134 for (i = 0; i < argc; i++) {
135 if (i == 0 && found_target)
136 continue;
137
99 len += sprintf(&buf[len], "%s ", argv[i]); 138 len += sprintf(&buf[len], "%s ", argv[i]);
139 }
100 params.mod_events = true; 140 params.mod_events = true;
101 ret = parse_probe_event(buf); 141 ret = parse_probe_event(buf);
102 free(buf); 142 free(buf);
@@ -125,6 +165,28 @@ static int opt_del_probe_event(const struct option *opt __used,
125 return 0; 165 return 0;
126} 166}
127 167
168static int opt_set_target(const struct option *opt, const char *str,
169 int unset __used)
170{
171 int ret = -ENOENT;
172
173 if (str && !params.target) {
174 if (!strcmp(opt->long_name, "exec"))
175 params.uprobes = true;
176#ifdef DWARF_SUPPORT
177 else if (!strcmp(opt->long_name, "module"))
178 params.uprobes = false;
179#endif
180 else
181 return ret;
182
183 params.target = str;
184 ret = 0;
185 }
186
187 return ret;
188}
189
128#ifdef DWARF_SUPPORT 190#ifdef DWARF_SUPPORT
129static int opt_show_lines(const struct option *opt __used, 191static int opt_show_lines(const struct option *opt __used,
130 const char *str, int unset __used) 192 const char *str, int unset __used)
@@ -246,9 +308,9 @@ static const struct option options[] = {
246 "file", "vmlinux pathname"), 308 "file", "vmlinux pathname"),
247 OPT_STRING('s', "source", &symbol_conf.source_prefix, 309 OPT_STRING('s', "source", &symbol_conf.source_prefix,
248 "directory", "path to kernel source"), 310 "directory", "path to kernel source"),
249 OPT_STRING('m', "module", &params.target, 311 OPT_CALLBACK('m', "module", NULL, "modname|path",
250 "modname|path", 312 "target module name (for online) or path (for offline)",
251 "target module name (for online) or path (for offline)"), 313 opt_set_target),
252#endif 314#endif
253 OPT__DRY_RUN(&probe_event_dry_run), 315 OPT__DRY_RUN(&probe_event_dry_run),
254 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 316 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -260,6 +322,8 @@ static const struct option options[] = {
260 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" 322 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
261 "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", 323 "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
262 opt_set_filter), 324 opt_set_filter),
325 OPT_CALLBACK('x', "exec", NULL, "executable|path",
326 "target executable name or path", opt_set_target),
263 OPT_END() 327 OPT_END()
264}; 328};
265 329
@@ -310,6 +374,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
310 pr_err(" Error: Don't use --list with --funcs.\n"); 374 pr_err(" Error: Don't use --list with --funcs.\n");
311 usage_with_options(probe_usage, options); 375 usage_with_options(probe_usage, options);
312 } 376 }
377 if (params.uprobes) {
378 pr_warning(" Error: Don't use --list with --exec.\n");
379 usage_with_options(probe_usage, options);
380 }
313 ret = show_perf_probe_events(); 381 ret = show_perf_probe_events();
314 if (ret < 0) 382 if (ret < 0)
315 pr_err(" Error: Failed to show event list. (%d)\n", 383 pr_err(" Error: Failed to show event list. (%d)\n",
@@ -333,8 +401,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
333 if (!params.filter) 401 if (!params.filter)
334 params.filter = strfilter__new(DEFAULT_FUNC_FILTER, 402 params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
335 NULL); 403 NULL);
336 ret = show_available_funcs(params.target, 404 ret = show_available_funcs(params.target, params.filter,
337 params.filter); 405 params.uprobes);
338 strfilter__delete(params.filter); 406 strfilter__delete(params.filter);
339 if (ret < 0) 407 if (ret < 0)
340 pr_err(" Error: Failed to show functions." 408 pr_err(" Error: Failed to show functions."
@@ -343,7 +411,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
343 } 411 }
344 412
345#ifdef DWARF_SUPPORT 413#ifdef DWARF_SUPPORT
346 if (params.show_lines) { 414 if (params.show_lines && !params.uprobes) {
347 if (params.mod_events) { 415 if (params.mod_events) {
348 pr_err(" Error: Don't use --line with" 416 pr_err(" Error: Don't use --line with"
349 " --add/--del.\n"); 417 " --add/--del.\n");
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index be4e1eee782e..f95840d04e4c 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -44,7 +44,6 @@ struct perf_record {
44 struct perf_evlist *evlist; 44 struct perf_evlist *evlist;
45 struct perf_session *session; 45 struct perf_session *session;
46 const char *progname; 46 const char *progname;
47 const char *uid_str;
48 int output; 47 int output;
49 unsigned int page_size; 48 unsigned int page_size;
50 int realtime_prio; 49 int realtime_prio;
@@ -218,7 +217,7 @@ try_again:
218 if (err == EPERM || err == EACCES) { 217 if (err == EPERM || err == EACCES) {
219 ui__error_paranoid(); 218 ui__error_paranoid();
220 exit(EXIT_FAILURE); 219 exit(EXIT_FAILURE);
221 } else if (err == ENODEV && opts->cpu_list) { 220 } else if (err == ENODEV && opts->target.cpu_list) {
222 die("No such device - did you specify" 221 die("No such device - did you specify"
223 " an out-of-range profile CPU?\n"); 222 " an out-of-range profile CPU?\n");
224 } else if (err == EINVAL) { 223 } else if (err == EINVAL) {
@@ -243,9 +242,13 @@ try_again:
243 /* 242 /*
244 * If it's cycles then fall back to hrtimer 243 * If it's cycles then fall back to hrtimer
245 * based cpu-clock-tick sw counter, which 244 * based cpu-clock-tick sw counter, which
246 * is always available even if no PMU support: 245 * is always available even if no PMU support.
246 *
247 * PPC returns ENXIO until 2.6.37 (behavior changed
248 * with commit b0a873e).
247 */ 249 */
248 if (attr->type == PERF_TYPE_HARDWARE 250 if ((err == ENOENT || err == ENXIO)
251 && attr->type == PERF_TYPE_HARDWARE
249 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 252 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
250 253
251 if (verbose) 254 if (verbose)
@@ -253,11 +256,15 @@ try_again:
253 "trying to fall back to cpu-clock-ticks\n"); 256 "trying to fall back to cpu-clock-ticks\n");
254 attr->type = PERF_TYPE_SOFTWARE; 257 attr->type = PERF_TYPE_SOFTWARE;
255 attr->config = PERF_COUNT_SW_CPU_CLOCK; 258 attr->config = PERF_COUNT_SW_CPU_CLOCK;
259 if (pos->name) {
260 free(pos->name);
261 pos->name = NULL;
262 }
256 goto try_again; 263 goto try_again;
257 } 264 }
258 265
259 if (err == ENOENT) { 266 if (err == ENOENT) {
260 ui__warning("The %s event is not supported.\n", 267 ui__error("The %s event is not supported.\n",
261 event_name(pos)); 268 event_name(pos));
262 exit(EXIT_FAILURE); 269 exit(EXIT_FAILURE);
263 } 270 }
@@ -389,7 +396,7 @@ static void perf_record__mmap_read_all(struct perf_record *rec)
389 perf_record__mmap_read(rec, &rec->evlist->mmap[i]); 396 perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
390 } 397 }
391 398
392 if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO)) 399 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
393 write_output(rec, &finished_round_event, sizeof(finished_round_event)); 400 write_output(rec, &finished_round_event, sizeof(finished_round_event));
394} 401}
395 402
@@ -471,7 +478,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
471 perf_header__clear_feat(&session->header, HEADER_BUILD_ID); 478 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
472 479
473 if (!have_tracepoints(&evsel_list->entries)) 480 if (!have_tracepoints(&evsel_list->entries))
474 perf_header__clear_feat(&session->header, HEADER_TRACE_INFO); 481 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
475 482
476 if (!rec->opts.branch_stack) 483 if (!rec->opts.branch_stack)
477 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 484 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
@@ -578,7 +585,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
578 perf_session__process_machines(session, tool, 585 perf_session__process_machines(session, tool,
579 perf_event__synthesize_guest_os); 586 perf_event__synthesize_guest_os);
580 587
581 if (!opts->system_wide) 588 if (!opts->target.system_wide)
582 perf_event__synthesize_thread_map(tool, evsel_list->threads, 589 perf_event__synthesize_thread_map(tool, evsel_list->threads,
583 process_synthesized_event, 590 process_synthesized_event,
584 machine); 591 machine);
@@ -746,7 +753,10 @@ static struct perf_record record = {
746 .mmap_pages = UINT_MAX, 753 .mmap_pages = UINT_MAX,
747 .user_freq = UINT_MAX, 754 .user_freq = UINT_MAX,
748 .user_interval = ULLONG_MAX, 755 .user_interval = ULLONG_MAX,
749 .freq = 1000, 756 .freq = 4000,
757 .target = {
758 .uses_mmap = true,
759 },
750 }, 760 },
751 .write_mode = WRITE_FORCE, 761 .write_mode = WRITE_FORCE,
752 .file_new = true, 762 .file_new = true,
@@ -765,9 +775,9 @@ const struct option record_options[] = {
765 parse_events_option), 775 parse_events_option),
766 OPT_CALLBACK(0, "filter", &record.evlist, "filter", 776 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
767 "event filter", parse_filter), 777 "event filter", parse_filter),
768 OPT_STRING('p', "pid", &record.opts.target_pid, "pid", 778 OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
769 "record events on existing process id"), 779 "record events on existing process id"),
770 OPT_STRING('t', "tid", &record.opts.target_tid, "tid", 780 OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
771 "record events on existing thread id"), 781 "record events on existing thread id"),
772 OPT_INTEGER('r', "realtime", &record.realtime_prio, 782 OPT_INTEGER('r', "realtime", &record.realtime_prio,
773 "collect data with this RT SCHED_FIFO priority"), 783 "collect data with this RT SCHED_FIFO priority"),
@@ -775,11 +785,11 @@ const struct option record_options[] = {
775 "collect data without buffering"), 785 "collect data without buffering"),
776 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, 786 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
777 "collect raw sample records from all opened counters"), 787 "collect raw sample records from all opened counters"),
778 OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide, 788 OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
779 "system-wide collection from all CPUs"), 789 "system-wide collection from all CPUs"),
780 OPT_BOOLEAN('A', "append", &record.append_file, 790 OPT_BOOLEAN('A', "append", &record.append_file,
781 "append to the output file to do incremental profiling"), 791 "append to the output file to do incremental profiling"),
782 OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu", 792 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
783 "list of cpus to monitor"), 793 "list of cpus to monitor"),
784 OPT_BOOLEAN('f', "force", &record.force, 794 OPT_BOOLEAN('f', "force", &record.force,
785 "overwrite existing data file (deprecated)"), 795 "overwrite existing data file (deprecated)"),
@@ -813,7 +823,8 @@ const struct option record_options[] = {
813 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 823 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
814 "monitor event in cgroup name only", 824 "monitor event in cgroup name only",
815 parse_cgroups), 825 parse_cgroups),
816 OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"), 826 OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
827 "user to profile"),
817 828
818 OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack, 829 OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
819 "branch any", "sample any taken branches", 830 "branch any", "sample any taken branches",
@@ -831,6 +842,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
831 struct perf_evsel *pos; 842 struct perf_evsel *pos;
832 struct perf_evlist *evsel_list; 843 struct perf_evlist *evsel_list;
833 struct perf_record *rec = &record; 844 struct perf_record *rec = &record;
845 char errbuf[BUFSIZ];
834 846
835 perf_header__set_cmdline(argc, argv); 847 perf_header__set_cmdline(argc, argv);
836 848
@@ -842,13 +854,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
842 854
843 argc = parse_options(argc, argv, record_options, record_usage, 855 argc = parse_options(argc, argv, record_options, record_usage,
844 PARSE_OPT_STOP_AT_NON_OPTION); 856 PARSE_OPT_STOP_AT_NON_OPTION);
845 if (!argc && !rec->opts.target_pid && !rec->opts.target_tid && 857 if (!argc && perf_target__none(&rec->opts.target))
846 !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
847 usage_with_options(record_usage, record_options); 858 usage_with_options(record_usage, record_options);
848 859
849 if (rec->force && rec->append_file) { 860 if (rec->force && rec->append_file) {
850 fprintf(stderr, "Can't overwrite and append at the same time." 861 ui__error("Can't overwrite and append at the same time."
851 " You need to choose between -f and -A"); 862 " You need to choose between -f and -A");
852 usage_with_options(record_usage, record_options); 863 usage_with_options(record_usage, record_options);
853 } else if (rec->append_file) { 864 } else if (rec->append_file) {
854 rec->write_mode = WRITE_APPEND; 865 rec->write_mode = WRITE_APPEND;
@@ -856,9 +867,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
856 rec->write_mode = WRITE_FORCE; 867 rec->write_mode = WRITE_FORCE;
857 } 868 }
858 869
859 if (nr_cgroups && !rec->opts.system_wide) { 870 if (nr_cgroups && !rec->opts.target.system_wide) {
860 fprintf(stderr, "cgroup monitoring only available in" 871 ui__error("cgroup monitoring only available in"
861 " system-wide mode\n"); 872 " system-wide mode\n");
862 usage_with_options(record_usage, record_options); 873 usage_with_options(record_usage, record_options);
863 } 874 }
864 875
@@ -883,17 +894,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
883 goto out_symbol_exit; 894 goto out_symbol_exit;
884 } 895 }
885 896
886 rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid, 897 err = perf_target__validate(&rec->opts.target);
887 rec->opts.target_pid); 898 if (err) {
888 if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1) 899 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
889 goto out_free_fd; 900 ui__warning("%s", errbuf);
901 }
902
903 err = perf_target__parse_uid(&rec->opts.target);
904 if (err) {
905 int saved_errno = errno;
890 906
891 if (rec->opts.target_pid) 907 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
892 rec->opts.target_tid = rec->opts.target_pid; 908 ui__error("%s", errbuf);
909
910 err = -saved_errno;
911 goto out_free_fd;
912 }
893 913
894 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, 914 err = -ENOMEM;
895 rec->opts.target_tid, rec->opts.uid, 915 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
896 rec->opts.cpu_list) < 0)
897 usage_with_options(record_usage, record_options); 916 usage_with_options(record_usage, record_options);
898 917
899 list_for_each_entry(pos, &evsel_list->entries, node) { 918 list_for_each_entry(pos, &evsel_list->entries, node) {
@@ -914,7 +933,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
914 else if (rec->opts.freq) { 933 else if (rec->opts.freq) {
915 rec->opts.default_interval = rec->opts.freq; 934 rec->opts.default_interval = rec->opts.freq;
916 } else { 935 } else {
917 fprintf(stderr, "frequency and count are zero, aborting\n"); 936 ui__error("frequency and count are zero, aborting\n");
918 err = -EINVAL; 937 err = -EINVAL;
919 goto out_free_fd; 938 goto out_free_fd;
920 } 939 }
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2e317438980b..25249f76329d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -152,7 +152,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
152 152
153 if (symbol_conf.use_callchain) { 153 if (symbol_conf.use_callchain) {
154 err = callchain_append(he->callchain, 154 err = callchain_append(he->callchain,
155 &evsel->hists.callchain_cursor, 155 &callchain_cursor,
156 sample->period); 156 sample->period);
157 if (err) 157 if (err)
158 return err; 158 return err;
@@ -162,7 +162,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
162 * so we don't allocated the extra space needed because the stdio 162 * so we don't allocated the extra space needed because the stdio
163 * code will not use it. 163 * code will not use it.
164 */ 164 */
165 if (al->sym != NULL && use_browser > 0) { 165 if (he->ms.sym != NULL && use_browser > 0) {
166 struct annotation *notes = symbol__annotation(he->ms.sym); 166 struct annotation *notes = symbol__annotation(he->ms.sym);
167 167
168 assert(evsel != NULL); 168 assert(evsel != NULL);
@@ -251,13 +251,13 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
251 251
252 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { 252 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
253 if (sort__has_parent) { 253 if (sort__has_parent) {
254 ui__warning("Selected --sort parent, but no " 254 ui__error("Selected --sort parent, but no "
255 "callchain data. Did you call " 255 "callchain data. Did you call "
256 "'perf record' without -g?\n"); 256 "'perf record' without -g?\n");
257 return -EINVAL; 257 return -EINVAL;
258 } 258 }
259 if (symbol_conf.use_callchain) { 259 if (symbol_conf.use_callchain) {
260 ui__warning("Selected -g but no callchain data. Did " 260 ui__error("Selected -g but no callchain data. Did "
261 "you call 'perf record' without -g?\n"); 261 "you call 'perf record' without -g?\n");
262 return -1; 262 return -1;
263 } 263 }
@@ -266,17 +266,15 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
266 !symbol_conf.use_callchain) { 266 !symbol_conf.use_callchain) {
267 symbol_conf.use_callchain = true; 267 symbol_conf.use_callchain = true;
268 if (callchain_register_param(&callchain_param) < 0) { 268 if (callchain_register_param(&callchain_param) < 0) {
269 ui__warning("Can't register callchain " 269 ui__error("Can't register callchain params.\n");
270 "params.\n");
271 return -EINVAL; 270 return -EINVAL;
272 } 271 }
273 } 272 }
274 273
275 if (sort__branch_mode == 1) { 274 if (sort__branch_mode == 1) {
276 if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) { 275 if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
277 fprintf(stderr, "selected -b but no branch data." 276 ui__error("Selected -b but no branch data. "
278 " Did you call perf record without" 277 "Did you call perf record without -b?\n");
279 " -b?\n");
280 return -1; 278 return -1;
281 } 279 }
282 } 280 }
@@ -296,12 +294,15 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
296{ 294{
297 size_t ret; 295 size_t ret;
298 char unit; 296 char unit;
299 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 297 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
298 u64 nr_events = self->stats.total_period;
300 299
301 nr_events = convert_unit(nr_events, &unit); 300 nr_samples = convert_unit(nr_samples, &unit);
302 ret = fprintf(fp, "# Events: %lu%c", nr_events, unit); 301 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
303 if (evname != NULL) 302 if (evname != NULL)
304 ret += fprintf(fp, " %s", evname); 303 ret += fprintf(fp, " of event '%s'", evname);
304
305 ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
305 return ret + fprintf(fp, "\n#\n"); 306 return ret + fprintf(fp, "\n#\n");
306} 307}
307 308
@@ -374,16 +375,23 @@ static int __cmd_report(struct perf_report *rep)
374 (kernel_map->dso->hit && 375 (kernel_map->dso->hit &&
375 (kernel_kmap->ref_reloc_sym == NULL || 376 (kernel_kmap->ref_reloc_sym == NULL ||
376 kernel_kmap->ref_reloc_sym->addr == 0))) { 377 kernel_kmap->ref_reloc_sym->addr == 0))) {
377 const struct dso *kdso = kernel_map->dso; 378 const char *desc =
379 "As no suitable kallsyms nor vmlinux was found, kernel samples\n"
380 "can't be resolved.";
381
382 if (kernel_map) {
383 const struct dso *kdso = kernel_map->dso;
384 if (!RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION])) {
385 desc = "If some relocation was applied (e.g. "
386 "kexec) symbols may be misresolved.";
387 }
388 }
378 389
379 ui__warning( 390 ui__warning(
380"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n" 391"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"
381"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n" 392"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"
382"Samples in kernel modules can't be resolved as well.\n\n", 393"Samples in kernel modules can't be resolved as well.\n\n",
383 RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION]) ? 394 desc);
384"As no suitable kallsyms nor vmlinux was found, kernel samples\n"
385"can't be resolved." :
386"If some relocation was applied (e.g. kexec) symbols may be misresolved.");
387 } 395 }
388 396
389 if (dump_trace) { 397 if (dump_trace) {
@@ -410,7 +418,7 @@ static int __cmd_report(struct perf_report *rep)
410 } 418 }
411 419
412 if (nr_samples == 0) { 420 if (nr_samples == 0) {
413 ui__warning("The %s file has no samples!\n", session->filename); 421 ui__error("The %s file has no samples!\n", session->filename);
414 goto out_delete; 422 goto out_delete;
415 } 423 }
416 424
@@ -673,14 +681,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
673 681
674 } 682 }
675 683
676 if (strcmp(report.input_name, "-") != 0) { 684 if (strcmp(report.input_name, "-") != 0)
677 if (report.use_gtk) 685 setup_browser(true);
678 perf_gtk_setup_browser(argc, argv, true); 686 else
679 else
680 setup_browser(true);
681 } else {
682 use_browser = 0; 687 use_browser = 0;
683 }
684 688
685 /* 689 /*
686 * Only in the newt browser we are doing integrated annotation, 690 * Only in the newt browser we are doing integrated annotation,
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 1cad3af4bf4c..b125e07eb399 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -728,34 +728,34 @@ struct trace_migrate_task_event {
728struct trace_sched_handler { 728struct trace_sched_handler {
729 void (*switch_event)(struct trace_switch_event *, 729 void (*switch_event)(struct trace_switch_event *,
730 struct machine *, 730 struct machine *,
731 struct event *, 731 struct event_format *,
732 int cpu, 732 int cpu,
733 u64 timestamp, 733 u64 timestamp,
734 struct thread *thread); 734 struct thread *thread);
735 735
736 void (*runtime_event)(struct trace_runtime_event *, 736 void (*runtime_event)(struct trace_runtime_event *,
737 struct machine *, 737 struct machine *,
738 struct event *, 738 struct event_format *,
739 int cpu, 739 int cpu,
740 u64 timestamp, 740 u64 timestamp,
741 struct thread *thread); 741 struct thread *thread);
742 742
743 void (*wakeup_event)(struct trace_wakeup_event *, 743 void (*wakeup_event)(struct trace_wakeup_event *,
744 struct machine *, 744 struct machine *,
745 struct event *, 745 struct event_format *,
746 int cpu, 746 int cpu,
747 u64 timestamp, 747 u64 timestamp,
748 struct thread *thread); 748 struct thread *thread);
749 749
750 void (*fork_event)(struct trace_fork_event *, 750 void (*fork_event)(struct trace_fork_event *,
751 struct event *, 751 struct event_format *,
752 int cpu, 752 int cpu,
753 u64 timestamp, 753 u64 timestamp,
754 struct thread *thread); 754 struct thread *thread);
755 755
756 void (*migrate_task_event)(struct trace_migrate_task_event *, 756 void (*migrate_task_event)(struct trace_migrate_task_event *,
757 struct machine *machine, 757 struct machine *machine,
758 struct event *, 758 struct event_format *,
759 int cpu, 759 int cpu,
760 u64 timestamp, 760 u64 timestamp,
761 struct thread *thread); 761 struct thread *thread);
@@ -765,7 +765,7 @@ struct trace_sched_handler {
765static void 765static void
766replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 766replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
767 struct machine *machine __used, 767 struct machine *machine __used,
768 struct event *event, 768 struct event_format *event,
769 int cpu __used, 769 int cpu __used,
770 u64 timestamp __used, 770 u64 timestamp __used,
771 struct thread *thread __used) 771 struct thread *thread __used)
@@ -792,7 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];
792static void 792static void
793replay_switch_event(struct trace_switch_event *switch_event, 793replay_switch_event(struct trace_switch_event *switch_event,
794 struct machine *machine __used, 794 struct machine *machine __used,
795 struct event *event, 795 struct event_format *event,
796 int cpu, 796 int cpu,
797 u64 timestamp, 797 u64 timestamp,
798 struct thread *thread __used) 798 struct thread *thread __used)
@@ -835,7 +835,7 @@ replay_switch_event(struct trace_switch_event *switch_event,
835 835
836static void 836static void
837replay_fork_event(struct trace_fork_event *fork_event, 837replay_fork_event(struct trace_fork_event *fork_event,
838 struct event *event, 838 struct event_format *event,
839 int cpu __used, 839 int cpu __used,
840 u64 timestamp __used, 840 u64 timestamp __used,
841 struct thread *thread __used) 841 struct thread *thread __used)
@@ -944,7 +944,7 @@ static void thread_atoms_insert(struct thread *thread)
944 944
945static void 945static void
946latency_fork_event(struct trace_fork_event *fork_event __used, 946latency_fork_event(struct trace_fork_event *fork_event __used,
947 struct event *event __used, 947 struct event_format *event __used,
948 int cpu __used, 948 int cpu __used,
949 u64 timestamp __used, 949 u64 timestamp __used,
950 struct thread *thread __used) 950 struct thread *thread __used)
@@ -1026,7 +1026,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1026static void 1026static void
1027latency_switch_event(struct trace_switch_event *switch_event, 1027latency_switch_event(struct trace_switch_event *switch_event,
1028 struct machine *machine, 1028 struct machine *machine,
1029 struct event *event __used, 1029 struct event_format *event __used,
1030 int cpu, 1030 int cpu,
1031 u64 timestamp, 1031 u64 timestamp,
1032 struct thread *thread __used) 1032 struct thread *thread __used)
@@ -1079,7 +1079,7 @@ latency_switch_event(struct trace_switch_event *switch_event,
1079static void 1079static void
1080latency_runtime_event(struct trace_runtime_event *runtime_event, 1080latency_runtime_event(struct trace_runtime_event *runtime_event,
1081 struct machine *machine, 1081 struct machine *machine,
1082 struct event *event __used, 1082 struct event_format *event __used,
1083 int cpu, 1083 int cpu,
1084 u64 timestamp, 1084 u64 timestamp,
1085 struct thread *this_thread __used) 1085 struct thread *this_thread __used)
@@ -1102,7 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1102static void 1102static void
1103latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1103latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1104 struct machine *machine, 1104 struct machine *machine,
1105 struct event *__event __used, 1105 struct event_format *__event __used,
1106 int cpu __used, 1106 int cpu __used,
1107 u64 timestamp, 1107 u64 timestamp,
1108 struct thread *thread __used) 1108 struct thread *thread __used)
@@ -1150,7 +1150,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1150static void 1150static void
1151latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, 1151latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1152 struct machine *machine, 1152 struct machine *machine,
1153 struct event *__event __used, 1153 struct event_format *__event __used,
1154 int cpu __used, 1154 int cpu __used,
1155 u64 timestamp, 1155 u64 timestamp,
1156 struct thread *thread __used) 1156 struct thread *thread __used)
@@ -1361,7 +1361,7 @@ static struct trace_sched_handler *trace_handler;
1361 1361
1362static void 1362static void
1363process_sched_wakeup_event(struct perf_tool *tool __used, 1363process_sched_wakeup_event(struct perf_tool *tool __used,
1364 struct event *event, 1364 struct event_format *event,
1365 struct perf_sample *sample, 1365 struct perf_sample *sample,
1366 struct machine *machine, 1366 struct machine *machine,
1367 struct thread *thread) 1367 struct thread *thread)
@@ -1398,7 +1398,7 @@ static char next_shortname2 = '0';
1398static void 1398static void
1399map_switch_event(struct trace_switch_event *switch_event, 1399map_switch_event(struct trace_switch_event *switch_event,
1400 struct machine *machine, 1400 struct machine *machine,
1401 struct event *event __used, 1401 struct event_format *event __used,
1402 int this_cpu, 1402 int this_cpu,
1403 u64 timestamp, 1403 u64 timestamp,
1404 struct thread *thread __used) 1404 struct thread *thread __used)
@@ -1476,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1476 1476
1477static void 1477static void
1478process_sched_switch_event(struct perf_tool *tool __used, 1478process_sched_switch_event(struct perf_tool *tool __used,
1479 struct event *event, 1479 struct event_format *event,
1480 struct perf_sample *sample, 1480 struct perf_sample *sample,
1481 struct machine *machine, 1481 struct machine *machine,
1482 struct thread *thread) 1482 struct thread *thread)
@@ -1512,7 +1512,7 @@ process_sched_switch_event(struct perf_tool *tool __used,
1512 1512
1513static void 1513static void
1514process_sched_runtime_event(struct perf_tool *tool __used, 1514process_sched_runtime_event(struct perf_tool *tool __used,
1515 struct event *event, 1515 struct event_format *event,
1516 struct perf_sample *sample, 1516 struct perf_sample *sample,
1517 struct machine *machine, 1517 struct machine *machine,
1518 struct thread *thread) 1518 struct thread *thread)
@@ -1532,7 +1532,7 @@ process_sched_runtime_event(struct perf_tool *tool __used,
1532 1532
1533static void 1533static void
1534process_sched_fork_event(struct perf_tool *tool __used, 1534process_sched_fork_event(struct perf_tool *tool __used,
1535 struct event *event, 1535 struct event_format *event,
1536 struct perf_sample *sample, 1536 struct perf_sample *sample,
1537 struct machine *machine __used, 1537 struct machine *machine __used,
1538 struct thread *thread) 1538 struct thread *thread)
@@ -1554,7 +1554,7 @@ process_sched_fork_event(struct perf_tool *tool __used,
1554 1554
1555static void 1555static void
1556process_sched_exit_event(struct perf_tool *tool __used, 1556process_sched_exit_event(struct perf_tool *tool __used,
1557 struct event *event, 1557 struct event_format *event,
1558 struct perf_sample *sample __used, 1558 struct perf_sample *sample __used,
1559 struct machine *machine __used, 1559 struct machine *machine __used,
1560 struct thread *thread __used) 1560 struct thread *thread __used)
@@ -1565,7 +1565,7 @@ process_sched_exit_event(struct perf_tool *tool __used,
1565 1565
1566static void 1566static void
1567process_sched_migrate_task_event(struct perf_tool *tool __used, 1567process_sched_migrate_task_event(struct perf_tool *tool __used,
1568 struct event *event, 1568 struct event_format *event,
1569 struct perf_sample *sample, 1569 struct perf_sample *sample,
1570 struct machine *machine, 1570 struct machine *machine,
1571 struct thread *thread) 1571 struct thread *thread)
@@ -1586,7 +1586,7 @@ process_sched_migrate_task_event(struct perf_tool *tool __used,
1586 sample->time, thread); 1586 sample->time, thread);
1587} 1587}
1588 1588
1589typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event, 1589typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event_format *event,
1590 struct perf_sample *sample, 1590 struct perf_sample *sample,
1591 struct machine *machine, 1591 struct machine *machine,
1592 struct thread *thread); 1592 struct thread *thread);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index d4ce733b9eba..8e395a538eb9 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -261,7 +261,7 @@ static void print_sample_start(struct perf_sample *sample,
261 struct perf_event_attr *attr) 261 struct perf_event_attr *attr)
262{ 262{
263 int type; 263 int type;
264 struct event *event; 264 struct event_format *event;
265 const char *evname = NULL; 265 const char *evname = NULL;
266 unsigned long secs; 266 unsigned long secs;
267 unsigned long usecs; 267 unsigned long usecs;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c941bb640f49..07b5c7703dd1 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -173,24 +173,23 @@ static struct perf_event_attr very_very_detailed_attrs[] = {
173 173
174 174
175 175
176struct perf_evlist *evsel_list; 176static struct perf_evlist *evsel_list;
177 177
178static bool system_wide = false; 178static struct perf_target target = {
179static int run_idx = 0; 179 .uid = UINT_MAX,
180};
180 181
182static int run_idx = 0;
181static int run_count = 1; 183static int run_count = 1;
182static bool no_inherit = false; 184static bool no_inherit = false;
183static bool scale = true; 185static bool scale = true;
184static bool no_aggr = false; 186static bool no_aggr = false;
185static const char *target_pid;
186static const char *target_tid;
187static pid_t child_pid = -1; 187static pid_t child_pid = -1;
188static bool null_run = false; 188static bool null_run = false;
189static int detailed_run = 0; 189static int detailed_run = 0;
190static bool sync_run = false; 190static bool sync_run = false;
191static bool big_num = true; 191static bool big_num = true;
192static int big_num_opt = -1; 192static int big_num_opt = -1;
193static const char *cpu_list;
194static const char *csv_sep = NULL; 193static const char *csv_sep = NULL;
195static bool csv_output = false; 194static bool csv_output = false;
196static bool group = false; 195static bool group = false;
@@ -265,24 +264,26 @@ static double stddev_stats(struct stats *stats)
265 return sqrt(variance_mean); 264 return sqrt(variance_mean);
266} 265}
267 266
268struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 267static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
269struct stats runtime_cycles_stats[MAX_NR_CPUS]; 268static struct stats runtime_cycles_stats[MAX_NR_CPUS];
270struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; 269static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
271struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS]; 270static struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
272struct stats runtime_branches_stats[MAX_NR_CPUS]; 271static struct stats runtime_branches_stats[MAX_NR_CPUS];
273struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; 272static struct stats runtime_cacherefs_stats[MAX_NR_CPUS];
274struct stats runtime_l1_dcache_stats[MAX_NR_CPUS]; 273static struct stats runtime_l1_dcache_stats[MAX_NR_CPUS];
275struct stats runtime_l1_icache_stats[MAX_NR_CPUS]; 274static struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
276struct stats runtime_ll_cache_stats[MAX_NR_CPUS]; 275static struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
277struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; 276static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
278struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 277static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
279struct stats walltime_nsecs_stats; 278static struct stats walltime_nsecs_stats;
280 279
281static int create_perf_stat_counter(struct perf_evsel *evsel, 280static int create_perf_stat_counter(struct perf_evsel *evsel,
282 struct perf_evsel *first) 281 struct perf_evsel *first)
283{ 282{
284 struct perf_event_attr *attr = &evsel->attr; 283 struct perf_event_attr *attr = &evsel->attr;
285 struct xyarray *group_fd = NULL; 284 struct xyarray *group_fd = NULL;
285 bool exclude_guest_missing = false;
286 int ret;
286 287
287 if (group && evsel != first) 288 if (group && evsel != first)
288 group_fd = first->fd; 289 group_fd = first->fd;
@@ -293,16 +294,39 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
293 294
294 attr->inherit = !no_inherit; 295 attr->inherit = !no_inherit;
295 296
296 if (system_wide) 297retry:
297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, 298 if (exclude_guest_missing)
298 group, group_fd); 299 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
299 if (!target_pid && !target_tid && (!group || evsel == first)) { 300
301 if (perf_target__has_cpu(&target)) {
302 ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
303 group, group_fd);
304 if (ret)
305 goto check_ret;
306 return 0;
307 }
308
309 if (!perf_target__has_task(&target) && (!group || evsel == first)) {
300 attr->disabled = 1; 310 attr->disabled = 1;
301 attr->enable_on_exec = 1; 311 attr->enable_on_exec = 1;
302 } 312 }
303 313
304 return perf_evsel__open_per_thread(evsel, evsel_list->threads, 314 ret = perf_evsel__open_per_thread(evsel, evsel_list->threads,
305 group, group_fd); 315 group, group_fd);
316 if (!ret)
317 return 0;
318 /* fall through */
319check_ret:
320 if (ret && errno == EINVAL) {
321 if (!exclude_guest_missing &&
322 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
323 pr_debug("Old kernel, cannot exclude "
324 "guest or host samples.\n");
325 exclude_guest_missing = true;
326 goto retry;
327 }
328 }
329 return ret;
306} 330}
307 331
308/* 332/*
@@ -446,7 +470,7 @@ static int run_perf_stat(int argc __used, const char **argv)
446 exit(-1); 470 exit(-1);
447 } 471 }
448 472
449 if (!target_tid && !target_pid && !system_wide) 473 if (perf_target__none(&target))
450 evsel_list->threads->map[0] = child_pid; 474 evsel_list->threads->map[0] = child_pid;
451 475
452 /* 476 /*
@@ -463,8 +487,13 @@ static int run_perf_stat(int argc __used, const char **argv)
463 487
464 list_for_each_entry(counter, &evsel_list->entries, node) { 488 list_for_each_entry(counter, &evsel_list->entries, node) {
465 if (create_perf_stat_counter(counter, first) < 0) { 489 if (create_perf_stat_counter(counter, first) < 0) {
490 /*
491 * PPC returns ENXIO for HW counters until 2.6.37
492 * (behavior changed with commit b0a873e).
493 */
466 if (errno == EINVAL || errno == ENOSYS || 494 if (errno == EINVAL || errno == ENOSYS ||
467 errno == ENOENT || errno == EOPNOTSUPP) { 495 errno == ENOENT || errno == EOPNOTSUPP ||
496 errno == ENXIO) {
468 if (verbose) 497 if (verbose)
469 ui__warning("%s event is not supported by the kernel.\n", 498 ui__warning("%s event is not supported by the kernel.\n",
470 event_name(counter)); 499 event_name(counter));
@@ -476,7 +505,7 @@ static int run_perf_stat(int argc __used, const char **argv)
476 error("You may not have permission to collect %sstats.\n" 505 error("You may not have permission to collect %sstats.\n"
477 "\t Consider tweaking" 506 "\t Consider tweaking"
478 " /proc/sys/kernel/perf_event_paranoid or running as root.", 507 " /proc/sys/kernel/perf_event_paranoid or running as root.",
479 system_wide ? "system-wide " : ""); 508 target.system_wide ? "system-wide " : "");
480 } else { 509 } else {
481 error("open_counter returned with %d (%s). " 510 error("open_counter returned with %d (%s). "
482 "/bin/dmesg may provide additional information.\n", 511 "/bin/dmesg may provide additional information.\n",
@@ -968,14 +997,14 @@ static void print_stat(int argc, const char **argv)
968 if (!csv_output) { 997 if (!csv_output) {
969 fprintf(output, "\n"); 998 fprintf(output, "\n");
970 fprintf(output, " Performance counter stats for "); 999 fprintf(output, " Performance counter stats for ");
971 if (!target_pid && !target_tid) { 1000 if (!perf_target__has_task(&target)) {
972 fprintf(output, "\'%s", argv[0]); 1001 fprintf(output, "\'%s", argv[0]);
973 for (i = 1; i < argc; i++) 1002 for (i = 1; i < argc; i++)
974 fprintf(output, " %s", argv[i]); 1003 fprintf(output, " %s", argv[i]);
975 } else if (target_pid) 1004 } else if (target.pid)
976 fprintf(output, "process id \'%s", target_pid); 1005 fprintf(output, "process id \'%s", target.pid);
977 else 1006 else
978 fprintf(output, "thread id \'%s", target_tid); 1007 fprintf(output, "thread id \'%s", target.tid);
979 1008
980 fprintf(output, "\'"); 1009 fprintf(output, "\'");
981 if (run_count > 1) 1010 if (run_count > 1)
@@ -1049,11 +1078,11 @@ static const struct option options[] = {
1049 "event filter", parse_filter), 1078 "event filter", parse_filter),
1050 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 1079 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
1051 "child tasks do not inherit counters"), 1080 "child tasks do not inherit counters"),
1052 OPT_STRING('p', "pid", &target_pid, "pid", 1081 OPT_STRING('p', "pid", &target.pid, "pid",
1053 "stat events on existing process id"), 1082 "stat events on existing process id"),
1054 OPT_STRING('t', "tid", &target_tid, "tid", 1083 OPT_STRING('t', "tid", &target.tid, "tid",
1055 "stat events on existing thread id"), 1084 "stat events on existing thread id"),
1056 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1085 OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
1057 "system-wide collection from all CPUs"), 1086 "system-wide collection from all CPUs"),
1058 OPT_BOOLEAN('g', "group", &group, 1087 OPT_BOOLEAN('g', "group", &group,
1059 "put the counters into a counter group"), 1088 "put the counters into a counter group"),
@@ -1072,7 +1101,7 @@ static const struct option options[] = {
1072 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, 1101 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
1073 "print large numbers with thousands\' separators", 1102 "print large numbers with thousands\' separators",
1074 stat__set_big_num), 1103 stat__set_big_num),
1075 OPT_STRING('C', "cpu", &cpu_list, "cpu", 1104 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
1076 "list of cpus to monitor in system-wide"), 1105 "list of cpus to monitor in system-wide"),
1077 OPT_BOOLEAN('A', "no-aggr", &no_aggr, 1106 OPT_BOOLEAN('A', "no-aggr", &no_aggr,
1078 "disable CPU count aggregation"), 1107 "disable CPU count aggregation"),
@@ -1100,7 +1129,7 @@ static int add_default_attributes(void)
1100 return 0; 1129 return 0;
1101 1130
1102 if (!evsel_list->nr_entries) { 1131 if (!evsel_list->nr_entries) {
1103 if (perf_evlist__add_attrs_array(evsel_list, default_attrs) < 0) 1132 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0)
1104 return -1; 1133 return -1;
1105 } 1134 }
1106 1135
@@ -1110,21 +1139,21 @@ static int add_default_attributes(void)
1110 return 0; 1139 return 0;
1111 1140
1112 /* Append detailed run extra attributes: */ 1141 /* Append detailed run extra attributes: */
1113 if (perf_evlist__add_attrs_array(evsel_list, detailed_attrs) < 0) 1142 if (perf_evlist__add_default_attrs(evsel_list, detailed_attrs) < 0)
1114 return -1; 1143 return -1;
1115 1144
1116 if (detailed_run < 2) 1145 if (detailed_run < 2)
1117 return 0; 1146 return 0;
1118 1147
1119 /* Append very detailed run extra attributes: */ 1148 /* Append very detailed run extra attributes: */
1120 if (perf_evlist__add_attrs_array(evsel_list, very_detailed_attrs) < 0) 1149 if (perf_evlist__add_default_attrs(evsel_list, very_detailed_attrs) < 0)
1121 return -1; 1150 return -1;
1122 1151
1123 if (detailed_run < 3) 1152 if (detailed_run < 3)
1124 return 0; 1153 return 0;
1125 1154
1126 /* Append very, very detailed run extra attributes: */ 1155 /* Append very, very detailed run extra attributes: */
1127 return perf_evlist__add_attrs_array(evsel_list, very_very_detailed_attrs); 1156 return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs);
1128} 1157}
1129 1158
1130int cmd_stat(int argc, const char **argv, const char *prefix __used) 1159int cmd_stat(int argc, const char **argv, const char *prefix __used)
@@ -1150,6 +1179,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1150 fprintf(stderr, "cannot use both --output and --log-fd\n"); 1179 fprintf(stderr, "cannot use both --output and --log-fd\n");
1151 usage_with_options(stat_usage, options); 1180 usage_with_options(stat_usage, options);
1152 } 1181 }
1182
1183 if (output_fd < 0) {
1184 fprintf(stderr, "argument to --log-fd must be a > 0\n");
1185 usage_with_options(stat_usage, options);
1186 }
1187
1153 if (!output) { 1188 if (!output) {
1154 struct timespec tm; 1189 struct timespec tm;
1155 mode = append_file ? "a" : "w"; 1190 mode = append_file ? "a" : "w";
@@ -1161,7 +1196,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1161 } 1196 }
1162 clock_gettime(CLOCK_REALTIME, &tm); 1197 clock_gettime(CLOCK_REALTIME, &tm);
1163 fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); 1198 fprintf(output, "# started on %s\n", ctime(&tm.tv_sec));
1164 } else if (output_fd != 2) { 1199 } else if (output_fd > 0) {
1165 mode = append_file ? "a" : "w"; 1200 mode = append_file ? "a" : "w";
1166 output = fdopen(output_fd, mode); 1201 output = fdopen(output_fd, mode);
1167 if (!output) { 1202 if (!output) {
@@ -1190,13 +1225,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1190 } else if (big_num_opt == 0) /* User passed --no-big-num */ 1225 } else if (big_num_opt == 0) /* User passed --no-big-num */
1191 big_num = false; 1226 big_num = false;
1192 1227
1193 if (!argc && !target_pid && !target_tid) 1228 if (!argc && !perf_target__has_task(&target))
1194 usage_with_options(stat_usage, options); 1229 usage_with_options(stat_usage, options);
1195 if (run_count <= 0) 1230 if (run_count <= 0)
1196 usage_with_options(stat_usage, options); 1231 usage_with_options(stat_usage, options);
1197 1232
1198 /* no_aggr, cgroup are for system-wide only */ 1233 /* no_aggr, cgroup are for system-wide only */
1199 if ((no_aggr || nr_cgroups) && !system_wide) { 1234 if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) {
1200 fprintf(stderr, "both cgroup and no-aggregation " 1235 fprintf(stderr, "both cgroup and no-aggregation "
1201 "modes only available in system-wide mode\n"); 1236 "modes only available in system-wide mode\n");
1202 1237
@@ -1206,23 +1241,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1206 if (add_default_attributes()) 1241 if (add_default_attributes())
1207 goto out; 1242 goto out;
1208 1243
1209 if (target_pid) 1244 perf_target__validate(&target);
1210 target_tid = target_pid;
1211 1245
1212 evsel_list->threads = thread_map__new_str(target_pid, 1246 if (perf_evlist__create_maps(evsel_list, &target) < 0) {
1213 target_tid, UINT_MAX); 1247 if (perf_target__has_task(&target))
1214 if (evsel_list->threads == NULL) { 1248 pr_err("Problems finding threads of monitor\n");
1215 pr_err("Problems finding threads of monitor\n"); 1249 if (perf_target__has_cpu(&target))
1216 usage_with_options(stat_usage, options); 1250 perror("failed to parse CPUs map");
1217 }
1218
1219 if (system_wide)
1220 evsel_list->cpus = cpu_map__new(cpu_list);
1221 else
1222 evsel_list->cpus = cpu_map__dummy_new();
1223 1251
1224 if (evsel_list->cpus == NULL) {
1225 perror("failed to parse CPUs map");
1226 usage_with_options(stat_usage, options); 1252 usage_with_options(stat_usage, options);
1227 return -1; 1253 return -1;
1228 } 1254 }
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 1c5b9801ac61..5a8727c08757 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -604,526 +604,6 @@ out_free_threads:
604#undef nsyscalls 604#undef nsyscalls
605} 605}
606 606
607#define TEST_ASSERT_VAL(text, cond) \
608do { \
609 if (!(cond)) { \
610 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
611 return -1; \
612 } \
613} while (0)
614
615static int test__checkevent_tracepoint(struct perf_evlist *evlist)
616{
617 struct perf_evsel *evsel = list_entry(evlist->entries.next,
618 struct perf_evsel, node);
619
620 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
621 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
622 TEST_ASSERT_VAL("wrong sample_type",
623 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
624 evsel->attr.sample_type);
625 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
626 return 0;
627}
628
629static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
630{
631 struct perf_evsel *evsel;
632
633 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
634
635 list_for_each_entry(evsel, &evlist->entries, node) {
636 TEST_ASSERT_VAL("wrong type",
637 PERF_TYPE_TRACEPOINT == evsel->attr.type);
638 TEST_ASSERT_VAL("wrong sample_type",
639 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
640 == evsel->attr.sample_type);
641 TEST_ASSERT_VAL("wrong sample_period",
642 1 == evsel->attr.sample_period);
643 }
644 return 0;
645}
646
647static int test__checkevent_raw(struct perf_evlist *evlist)
648{
649 struct perf_evsel *evsel = list_entry(evlist->entries.next,
650 struct perf_evsel, node);
651
652 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
653 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
654 TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
655 return 0;
656}
657
658static int test__checkevent_numeric(struct perf_evlist *evlist)
659{
660 struct perf_evsel *evsel = list_entry(evlist->entries.next,
661 struct perf_evsel, node);
662
663 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
664 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
665 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
666 return 0;
667}
668
669static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
670{
671 struct perf_evsel *evsel = list_entry(evlist->entries.next,
672 struct perf_evsel, node);
673
674 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
675 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
676 TEST_ASSERT_VAL("wrong config",
677 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
678 return 0;
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
699static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
700{
701 struct perf_evsel *evsel = list_entry(evlist->entries.next,
702 struct perf_evsel, node);
703
704 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
705 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
706 TEST_ASSERT_VAL("wrong config",
707 PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
708 return 0;
709}
710
711static int test__checkevent_genhw(struct perf_evlist *evlist)
712{
713 struct perf_evsel *evsel = list_entry(evlist->entries.next,
714 struct perf_evsel, node);
715
716 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
717 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
718 TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
719 return 0;
720}
721
722static int test__checkevent_breakpoint(struct perf_evlist *evlist)
723{
724 struct perf_evsel *evsel = list_entry(evlist->entries.next,
725 struct perf_evsel, node);
726
727 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
728 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
729 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
730 TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
731 evsel->attr.bp_type);
732 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
733 evsel->attr.bp_len);
734 return 0;
735}
736
737static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
738{
739 struct perf_evsel *evsel = list_entry(evlist->entries.next,
740 struct perf_evsel, node);
741
742 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
743 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
744 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
745 TEST_ASSERT_VAL("wrong bp_type",
746 HW_BREAKPOINT_X == evsel->attr.bp_type);
747 TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
748 return 0;
749}
750
751static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
752{
753 struct perf_evsel *evsel = list_entry(evlist->entries.next,
754 struct perf_evsel, node);
755
756 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
757 TEST_ASSERT_VAL("wrong type",
758 PERF_TYPE_BREAKPOINT == evsel->attr.type);
759 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
760 TEST_ASSERT_VAL("wrong bp_type",
761 HW_BREAKPOINT_R == evsel->attr.bp_type);
762 TEST_ASSERT_VAL("wrong bp_len",
763 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
764 return 0;
765}
766
767static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
768{
769 struct perf_evsel *evsel = list_entry(evlist->entries.next,
770 struct perf_evsel, node);
771
772 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
773 TEST_ASSERT_VAL("wrong type",
774 PERF_TYPE_BREAKPOINT == evsel->attr.type);
775 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
776 TEST_ASSERT_VAL("wrong bp_type",
777 HW_BREAKPOINT_W == evsel->attr.bp_type);
778 TEST_ASSERT_VAL("wrong bp_len",
779 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
780 return 0;
781}
782
783static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
784{
785 struct perf_evsel *evsel = list_entry(evlist->entries.next,
786 struct perf_evsel, node);
787
788 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
789 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
790 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
791 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
792
793 return test__checkevent_tracepoint(evlist);
794}
795
796static int
797test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
798{
799 struct perf_evsel *evsel;
800
801 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
802
803 list_for_each_entry(evsel, &evlist->entries, node) {
804 TEST_ASSERT_VAL("wrong exclude_user",
805 !evsel->attr.exclude_user);
806 TEST_ASSERT_VAL("wrong exclude_kernel",
807 evsel->attr.exclude_kernel);
808 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
809 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
810 }
811
812 return test__checkevent_tracepoint_multi(evlist);
813}
814
815static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
816{
817 struct perf_evsel *evsel = list_entry(evlist->entries.next,
818 struct perf_evsel, node);
819
820 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
821 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
822 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
823 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
824
825 return test__checkevent_raw(evlist);
826}
827
828static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
829{
830 struct perf_evsel *evsel = list_entry(evlist->entries.next,
831 struct perf_evsel, node);
832
833 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
834 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
835 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
836 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
837
838 return test__checkevent_numeric(evlist);
839}
840
841static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
842{
843 struct perf_evsel *evsel = list_entry(evlist->entries.next,
844 struct perf_evsel, node);
845
846 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
847 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
848 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
849 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
850
851 return test__checkevent_symbolic_name(evlist);
852}
853
854static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
855{
856 struct perf_evsel *evsel = list_entry(evlist->entries.next,
857 struct perf_evsel, node);
858
859 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
860 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
861 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
862 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
863
864 return test__checkevent_symbolic_alias(evlist);
865}
866
867static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
868{
869 struct perf_evsel *evsel = list_entry(evlist->entries.next,
870 struct perf_evsel, node);
871
872 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
873 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
874 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
875 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
876
877 return test__checkevent_genhw(evlist);
878}
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
989static struct test__event_st {
990 const char *name;
991 __u32 type;
992 int (*check)(struct perf_evlist *evlist);
993} test__events[] = {
994 {
995 .name = "syscalls:sys_enter_open",
996 .check = test__checkevent_tracepoint,
997 },
998 {
999 .name = "syscalls:*",
1000 .check = test__checkevent_tracepoint_multi,
1001 },
1002 {
1003 .name = "r1a",
1004 .check = test__checkevent_raw,
1005 },
1006 {
1007 .name = "1:1",
1008 .check = test__checkevent_numeric,
1009 },
1010 {
1011 .name = "instructions",
1012 .check = test__checkevent_symbolic_name,
1013 },
1014 {
1015 .name = "cycles/period=100000,config2/",
1016 .check = test__checkevent_symbolic_name_config,
1017 },
1018 {
1019 .name = "faults",
1020 .check = test__checkevent_symbolic_alias,
1021 },
1022 {
1023 .name = "L1-dcache-load-miss",
1024 .check = test__checkevent_genhw,
1025 },
1026 {
1027 .name = "mem:0",
1028 .check = test__checkevent_breakpoint,
1029 },
1030 {
1031 .name = "mem:0:x",
1032 .check = test__checkevent_breakpoint_x,
1033 },
1034 {
1035 .name = "mem:0:r",
1036 .check = test__checkevent_breakpoint_r,
1037 },
1038 {
1039 .name = "mem:0:w",
1040 .check = test__checkevent_breakpoint_w,
1041 },
1042 {
1043 .name = "syscalls:sys_enter_open:k",
1044 .check = test__checkevent_tracepoint_modifier,
1045 },
1046 {
1047 .name = "syscalls:*:u",
1048 .check = test__checkevent_tracepoint_multi_modifier,
1049 },
1050 {
1051 .name = "r1a:kp",
1052 .check = test__checkevent_raw_modifier,
1053 },
1054 {
1055 .name = "1:1:hp",
1056 .check = test__checkevent_numeric_modifier,
1057 },
1058 {
1059 .name = "instructions:h",
1060 .check = test__checkevent_symbolic_name_modifier,
1061 },
1062 {
1063 .name = "faults:u",
1064 .check = test__checkevent_symbolic_alias_modifier,
1065 },
1066 {
1067 .name = "L1-dcache-load-miss:kp",
1068 .check = test__checkevent_genhw_modifier,
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 },
1094};
1095
1096#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
1097
1098static int test__parse_events(void)
1099{
1100 struct perf_evlist *evlist;
1101 u_int i;
1102 int ret = 0;
1103
1104 for (i = 0; i < TEST__EVENTS_CNT; i++) {
1105 struct test__event_st *e = &test__events[i];
1106
1107 evlist = perf_evlist__new(NULL, NULL);
1108 if (evlist == NULL)
1109 break;
1110
1111 ret = parse_events(evlist, e->name, 0);
1112 if (ret) {
1113 pr_debug("failed to parse event '%s', err %d\n",
1114 e->name, ret);
1115 break;
1116 }
1117
1118 ret = e->check(evlist);
1119 perf_evlist__delete(evlist);
1120 if (ret)
1121 break;
1122 }
1123
1124 return ret;
1125}
1126
1127static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp, 607static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
1128 size_t *sizep) 608 size_t *sizep)
1129{ 609{
@@ -1165,6 +645,10 @@ realloc:
1165static int test__PERF_RECORD(void) 645static int test__PERF_RECORD(void)
1166{ 646{
1167 struct perf_record_opts opts = { 647 struct perf_record_opts opts = {
648 .target = {
649 .uid = UINT_MAX,
650 .uses_mmap = true,
651 },
1168 .no_delay = true, 652 .no_delay = true,
1169 .freq = 10, 653 .freq = 10,
1170 .mmap_pages = 256, 654 .mmap_pages = 256,
@@ -1207,8 +691,7 @@ static int test__PERF_RECORD(void)
1207 * perf_evlist__prepare_workload we'll fill in the only thread 691 * perf_evlist__prepare_workload we'll fill in the only thread
1208 * we're monitoring, the one forked there. 692 * we're monitoring, the one forked there.
1209 */ 693 */
1210 err = perf_evlist__create_maps(evlist, opts.target_pid, 694 err = perf_evlist__create_maps(evlist, &opts.target);
1211 opts.target_tid, UINT_MAX, opts.cpu_list);
1212 if (err < 0) { 695 if (err < 0) {
1213 pr_debug("Not enough memory to create thread/cpu maps\n"); 696 pr_debug("Not enough memory to create thread/cpu maps\n");
1214 goto out_delete_evlist; 697 goto out_delete_evlist;
@@ -1549,8 +1032,6 @@ static int __test__rdpmc(void)
1549 sa.sa_sigaction = segfault_handler; 1032 sa.sa_sigaction = segfault_handler;
1550 sigaction(SIGSEGV, &sa, NULL); 1033 sigaction(SIGSEGV, &sa, NULL);
1551 1034
1552 fprintf(stderr, "\n\n");
1553
1554 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 1035 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
1555 if (fd < 0) { 1036 if (fd < 0) {
1556 die("Error: sys_perf_event_open() syscall returned " 1037 die("Error: sys_perf_event_open() syscall returned "
@@ -1575,7 +1056,7 @@ static int __test__rdpmc(void)
1575 loops *= 10; 1056 loops *= 10;
1576 1057
1577 delta = now - stamp; 1058 delta = now - stamp;
1578 fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta); 1059 pr_debug("%14d: %14Lu\n", n, (long long)delta);
1579 1060
1580 delta_sum += delta; 1061 delta_sum += delta;
1581 } 1062 }
@@ -1583,7 +1064,7 @@ static int __test__rdpmc(void)
1583 munmap(addr, page_size); 1064 munmap(addr, page_size);
1584 close(fd); 1065 close(fd);
1585 1066
1586 fprintf(stderr, " "); 1067 pr_debug(" ");
1587 1068
1588 if (!delta_sum) 1069 if (!delta_sum)
1589 return -1; 1070 return -1;
@@ -1644,7 +1125,7 @@ static struct test {
1644 }, 1125 },
1645 { 1126 {
1646 .desc = "parse events tests", 1127 .desc = "parse events tests",
1647 .func = test__parse_events, 1128 .func = parse_events__test,
1648 }, 1129 },
1649#if defined(__x86_64__) || defined(__i386__) 1130#if defined(__x86_64__) || defined(__i386__)
1650 { 1131 {
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8ef59f8262bb..6bb0277b7dfe 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -588,7 +588,7 @@ static void *display_thread_tui(void *arg)
588 * via --uid. 588 * via --uid.
589 */ 589 */
590 list_for_each_entry(pos, &top->evlist->entries, node) 590 list_for_each_entry(pos, &top->evlist->entries, node)
591 pos->hists.uid_filter_str = top->uid_str; 591 pos->hists.uid_filter_str = top->target.uid_str;
592 592
593 perf_evlist__tui_browse_hists(top->evlist, help, 593 perf_evlist__tui_browse_hists(top->evlist, help,
594 perf_top__sort_new_samples, 594 perf_top__sort_new_samples,
@@ -787,7 +787,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
787 } 787 }
788 788
789 if (symbol_conf.use_callchain) { 789 if (symbol_conf.use_callchain) {
790 err = callchain_append(he->callchain, &evsel->hists.callchain_cursor, 790 err = callchain_append(he->callchain, &callchain_cursor,
791 sample->period); 791 sample->period);
792 if (err) 792 if (err)
793 return; 793 return;
@@ -900,6 +900,9 @@ static void perf_top__start_counters(struct perf_top *top)
900 attr->read_format |= PERF_FORMAT_ID; 900 attr->read_format |= PERF_FORMAT_ID;
901 } 901 }
902 902
903 if (perf_target__has_cpu(&top->target))
904 attr->sample_type |= PERF_SAMPLE_CPU;
905
903 if (symbol_conf.use_callchain) 906 if (symbol_conf.use_callchain)
904 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 907 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
905 908
@@ -948,20 +951,24 @@ try_again:
948 951
949 attr->type = PERF_TYPE_SOFTWARE; 952 attr->type = PERF_TYPE_SOFTWARE;
950 attr->config = PERF_COUNT_SW_CPU_CLOCK; 953 attr->config = PERF_COUNT_SW_CPU_CLOCK;
954 if (counter->name) {
955 free(counter->name);
956 counter->name = NULL;
957 }
951 goto try_again; 958 goto try_again;
952 } 959 }
953 960
954 if (err == ENOENT) { 961 if (err == ENOENT) {
955 ui__warning("The %s event is not supported.\n", 962 ui__error("The %s event is not supported.\n",
956 event_name(counter)); 963 event_name(counter));
957 goto out_err; 964 goto out_err;
958 } else if (err == EMFILE) { 965 } else if (err == EMFILE) {
959 ui__warning("Too many events are opened.\n" 966 ui__error("Too many events are opened.\n"
960 "Try again after reducing the number of events\n"); 967 "Try again after reducing the number of events\n");
961 goto out_err; 968 goto out_err;
962 } 969 }
963 970
964 ui__warning("The sys_perf_event_open() syscall " 971 ui__error("The sys_perf_event_open() syscall "
965 "returned with %d (%s). /bin/dmesg " 972 "returned with %d (%s). /bin/dmesg "
966 "may provide additional information.\n" 973 "may provide additional information.\n"
967 "No CONFIG_PERF_EVENTS=y kernel support " 974 "No CONFIG_PERF_EVENTS=y kernel support "
@@ -971,7 +978,7 @@ try_again:
971 } 978 }
972 979
973 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { 980 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) {
974 ui__warning("Failed to mmap with %d (%s)\n", 981 ui__error("Failed to mmap with %d (%s)\n",
975 errno, strerror(errno)); 982 errno, strerror(errno));
976 goto out_err; 983 goto out_err;
977 } 984 }
@@ -987,12 +994,12 @@ static int perf_top__setup_sample_type(struct perf_top *top)
987{ 994{
988 if (!top->sort_has_symbols) { 995 if (!top->sort_has_symbols) {
989 if (symbol_conf.use_callchain) { 996 if (symbol_conf.use_callchain) {
990 ui__warning("Selected -g but \"sym\" not present in --sort/-s."); 997 ui__error("Selected -g but \"sym\" not present in --sort/-s.");
991 return -EINVAL; 998 return -EINVAL;
992 } 999 }
993 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { 1000 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
994 if (callchain_register_param(&callchain_param) < 0) { 1001 if (callchain_register_param(&callchain_param) < 0) {
995 ui__warning("Can't register callchain params.\n"); 1002 ui__error("Can't register callchain params.\n");
996 return -EINVAL; 1003 return -EINVAL;
997 } 1004 }
998 } 1005 }
@@ -1016,7 +1023,7 @@ static int __cmd_top(struct perf_top *top)
1016 if (ret) 1023 if (ret)
1017 goto out_delete; 1024 goto out_delete;
1018 1025
1019 if (top->target_tid || top->uid != UINT_MAX) 1026 if (perf_target__has_task(&top->target))
1020 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 1027 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
1021 perf_event__process, 1028 perf_event__process,
1022 &top->session->host_machine); 1029 &top->session->host_machine);
@@ -1034,7 +1041,7 @@ static int __cmd_top(struct perf_top *top)
1034 1041
1035 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 1042 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
1036 display_thread), top)) { 1043 display_thread), top)) {
1037 printf("Could not create display thread.\n"); 1044 ui__error("Could not create display thread.\n");
1038 exit(-1); 1045 exit(-1);
1039 } 1046 }
1040 1047
@@ -1043,7 +1050,7 @@ static int __cmd_top(struct perf_top *top)
1043 1050
1044 param.sched_priority = top->realtime_prio; 1051 param.sched_priority = top->realtime_prio;
1045 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 1052 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
1046 printf("Could not set realtime priority.\n"); 1053 ui__error("Could not set realtime priority.\n");
1047 exit(-1); 1054 exit(-1);
1048 } 1055 }
1049 } 1056 }
@@ -1150,14 +1157,17 @@ static const char * const top_usage[] = {
1150int cmd_top(int argc, const char **argv, const char *prefix __used) 1157int cmd_top(int argc, const char **argv, const char *prefix __used)
1151{ 1158{
1152 struct perf_evsel *pos; 1159 struct perf_evsel *pos;
1153 int status = -ENOMEM; 1160 int status;
1161 char errbuf[BUFSIZ];
1154 struct perf_top top = { 1162 struct perf_top top = {
1155 .count_filter = 5, 1163 .count_filter = 5,
1156 .delay_secs = 2, 1164 .delay_secs = 2,
1157 .uid = UINT_MAX, 1165 .freq = 4000, /* 4 KHz */
1158 .freq = 1000, /* 1 KHz */
1159 .mmap_pages = 128, 1166 .mmap_pages = 128,
1160 .sym_pcnt_filter = 5, 1167 .sym_pcnt_filter = 5,
1168 .target = {
1169 .uses_mmap = true,
1170 },
1161 }; 1171 };
1162 char callchain_default_opt[] = "fractal,0.5,callee"; 1172 char callchain_default_opt[] = "fractal,0.5,callee";
1163 const struct option options[] = { 1173 const struct option options[] = {
@@ -1166,13 +1176,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1166 parse_events_option), 1176 parse_events_option),
1167 OPT_INTEGER('c', "count", &top.default_interval, 1177 OPT_INTEGER('c', "count", &top.default_interval,
1168 "event period to sample"), 1178 "event period to sample"),
1169 OPT_STRING('p', "pid", &top.target_pid, "pid", 1179 OPT_STRING('p', "pid", &top.target.pid, "pid",
1170 "profile events on existing process id"), 1180 "profile events on existing process id"),
1171 OPT_STRING('t', "tid", &top.target_tid, "tid", 1181 OPT_STRING('t', "tid", &top.target.tid, "tid",
1172 "profile events on existing thread id"), 1182 "profile events on existing thread id"),
1173 OPT_BOOLEAN('a', "all-cpus", &top.system_wide, 1183 OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide,
1174 "system-wide collection from all CPUs"), 1184 "system-wide collection from all CPUs"),
1175 OPT_STRING('C', "cpu", &top.cpu_list, "cpu", 1185 OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu",
1176 "list of cpus to monitor"), 1186 "list of cpus to monitor"),
1177 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1187 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1178 "file", "vmlinux pathname"), 1188 "file", "vmlinux pathname"),
@@ -1227,7 +1237,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1227 "Display raw encoding of assembly instructions (default)"), 1237 "Display raw encoding of assembly instructions (default)"),
1228 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1238 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1229 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1239 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1230 OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"), 1240 OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),
1231 OPT_END() 1241 OPT_END()
1232 }; 1242 };
1233 1243
@@ -1253,27 +1263,32 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1253 1263
1254 setup_browser(false); 1264 setup_browser(false);
1255 1265
1256 top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid); 1266 status = perf_target__validate(&top.target);
1257 if (top.uid_str != NULL && top.uid == UINT_MAX - 1) 1267 if (status) {
1258 goto out_delete_evlist; 1268 perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
1269 ui__warning("%s", errbuf);
1270 }
1259 1271
1260 /* CPU and PID are mutually exclusive */ 1272 status = perf_target__parse_uid(&top.target);
1261 if (top.target_tid && top.cpu_list) { 1273 if (status) {
1262 printf("WARNING: PID switch overriding CPU\n"); 1274 int saved_errno = errno;
1263 sleep(1); 1275
1264 top.cpu_list = NULL; 1276 perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
1277 ui__error("%s", errbuf);
1278
1279 status = -saved_errno;
1280 goto out_delete_evlist;
1265 } 1281 }
1266 1282
1267 if (top.target_pid) 1283 if (perf_target__none(&top.target))
1268 top.target_tid = top.target_pid; 1284 top.target.system_wide = true;
1269 1285
1270 if (perf_evlist__create_maps(top.evlist, top.target_pid, 1286 if (perf_evlist__create_maps(top.evlist, &top.target) < 0)
1271 top.target_tid, top.uid, top.cpu_list) < 0)
1272 usage_with_options(top_usage, options); 1287 usage_with_options(top_usage, options);
1273 1288
1274 if (!top.evlist->nr_entries && 1289 if (!top.evlist->nr_entries &&
1275 perf_evlist__add_default(top.evlist) < 0) { 1290 perf_evlist__add_default(top.evlist) < 0) {
1276 pr_err("Not enough memory for event selector list\n"); 1291 ui__error("Not enough memory for event selector list\n");
1277 return -ENOMEM; 1292 return -ENOMEM;
1278 } 1293 }
1279 1294
@@ -1290,7 +1305,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1290 else if (top.freq) { 1305 else if (top.freq) {
1291 top.default_interval = top.freq; 1306 top.default_interval = top.freq;
1292 } else { 1307 } else {
1293 fprintf(stderr, "frequency and count are zero, aborting\n"); 1308 ui__error("frequency and count are zero, aborting\n");
1294 exit(EXIT_FAILURE); 1309 exit(EXIT_FAILURE);
1295 } 1310 }
1296 1311
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index bd0bb1b1279b..67e5d0cace85 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -409,14 +409,15 @@ Counters can be enabled and disabled in two ways: via ioctl and via
409prctl. When a counter is disabled, it doesn't count or generate 409prctl. When a counter is disabled, it doesn't count or generate
410events but does continue to exist and maintain its count value. 410events but does continue to exist and maintain its count value.
411 411
412An individual counter or counter group can be enabled with 412An individual counter can be enabled with
413 413
414 ioctl(fd, PERF_EVENT_IOC_ENABLE); 414 ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
415 415
416or disabled with 416or disabled with
417 417
418 ioctl(fd, PERF_EVENT_IOC_DISABLE); 418 ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
419 419
420For a counter group, pass PERF_IOC_FLAG_GROUP as the third argument.
420Enabling or disabling the leader of a group enables or disables the 421Enabling or disabling the leader of a group enables or disables the
421whole group; that is, while the group leader is disabled, none of the 422whole group; that is, while the group leader is disabled, none of the
422counters in the group will count. Enabling or disabling a member of a 423counters in the group will count. Enabling or disabling a member of a
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 89e3355ab173..f960ccb2edc6 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -207,10 +207,10 @@ extern const char perf_version_string[];
207 207
208void pthread__unblock_sigwinch(void); 208void pthread__unblock_sigwinch(void);
209 209
210#include "util/target.h"
211
210struct perf_record_opts { 212struct perf_record_opts {
211 const char *target_pid; 213 struct perf_target target;
212 const char *target_tid;
213 uid_t uid;
214 bool call_graph; 214 bool call_graph;
215 bool group; 215 bool group;
216 bool inherit_stat; 216 bool inherit_stat;
@@ -223,15 +223,13 @@ struct perf_record_opts {
223 bool sample_time; 223 bool sample_time;
224 bool sample_id_all_missing; 224 bool sample_id_all_missing;
225 bool exclude_guest_missing; 225 bool exclude_guest_missing;
226 bool system_wide;
227 bool period; 226 bool period;
228 unsigned int freq; 227 unsigned int freq;
229 unsigned int mmap_pages; 228 unsigned int mmap_pages;
230 unsigned int user_freq; 229 unsigned int user_freq;
231 int branch_stack; 230 u64 branch_stack;
232 u64 default_interval; 231 u64 default_interval;
233 u64 user_interval; 232 u64 user_interval;
234 const char *cpu_list;
235}; 233};
236 234
237#endif 235#endif
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/ui/browser.c
index 556829124b02..1818a531f1d3 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -27,21 +27,24 @@ static int ui_browser__percent_color(struct ui_browser *browser,
27 return HE_COLORSET_NORMAL; 27 return HE_COLORSET_NORMAL;
28} 28}
29 29
30void ui_browser__set_color(struct ui_browser *self __used, int color) 30int ui_browser__set_color(struct ui_browser *browser, int color)
31{ 31{
32 int ret = browser->current_color;
33 browser->current_color = color;
32 SLsmg_set_color(color); 34 SLsmg_set_color(color);
35 return ret;
33} 36}
34 37
35void ui_browser__set_percent_color(struct ui_browser *self, 38void ui_browser__set_percent_color(struct ui_browser *browser,
36 double percent, bool current) 39 double percent, bool current)
37{ 40{
38 int color = ui_browser__percent_color(self, percent, current); 41 int color = ui_browser__percent_color(browser, percent, current);
39 ui_browser__set_color(self, color); 42 ui_browser__set_color(browser, color);
40} 43}
41 44
42void ui_browser__gotorc(struct ui_browser *self, int y, int x) 45void ui_browser__gotorc(struct ui_browser *browser, int y, int x)
43{ 46{
44 SLsmg_gotorc(self->y + y, self->x + x); 47 SLsmg_gotorc(browser->y + y, browser->x + x);
45} 48}
46 49
47static struct list_head * 50static struct list_head *
@@ -70,23 +73,23 @@ ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
70 return NULL; 73 return NULL;
71} 74}
72 75
73void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) 76void ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int whence)
74{ 77{
75 struct list_head *head = self->entries; 78 struct list_head *head = browser->entries;
76 struct list_head *pos; 79 struct list_head *pos;
77 80
78 if (self->nr_entries == 0) 81 if (browser->nr_entries == 0)
79 return; 82 return;
80 83
81 switch (whence) { 84 switch (whence) {
82 case SEEK_SET: 85 case SEEK_SET:
83 pos = ui_browser__list_head_filter_entries(self, head->next); 86 pos = ui_browser__list_head_filter_entries(browser, head->next);
84 break; 87 break;
85 case SEEK_CUR: 88 case SEEK_CUR:
86 pos = self->top; 89 pos = browser->top;
87 break; 90 break;
88 case SEEK_END: 91 case SEEK_END:
89 pos = ui_browser__list_head_filter_prev_entries(self, head->prev); 92 pos = ui_browser__list_head_filter_prev_entries(browser, head->prev);
90 break; 93 break;
91 default: 94 default:
92 return; 95 return;
@@ -96,18 +99,18 @@ void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whenc
96 99
97 if (offset > 0) { 100 if (offset > 0) {
98 while (offset-- != 0) 101 while (offset-- != 0)
99 pos = ui_browser__list_head_filter_entries(self, pos->next); 102 pos = ui_browser__list_head_filter_entries(browser, pos->next);
100 } else { 103 } else {
101 while (offset++ != 0) 104 while (offset++ != 0)
102 pos = ui_browser__list_head_filter_prev_entries(self, pos->prev); 105 pos = ui_browser__list_head_filter_prev_entries(browser, pos->prev);
103 } 106 }
104 107
105 self->top = pos; 108 browser->top = pos;
106} 109}
107 110
108void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence) 111void ui_browser__rb_tree_seek(struct ui_browser *browser, off_t offset, int whence)
109{ 112{
110 struct rb_root *root = self->entries; 113 struct rb_root *root = browser->entries;
111 struct rb_node *nd; 114 struct rb_node *nd;
112 115
113 switch (whence) { 116 switch (whence) {
@@ -115,7 +118,7 @@ void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
115 nd = rb_first(root); 118 nd = rb_first(root);
116 break; 119 break;
117 case SEEK_CUR: 120 case SEEK_CUR:
118 nd = self->top; 121 nd = browser->top;
119 break; 122 break;
120 case SEEK_END: 123 case SEEK_END:
121 nd = rb_last(root); 124 nd = rb_last(root);
@@ -132,23 +135,23 @@ void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
132 nd = rb_prev(nd); 135 nd = rb_prev(nd);
133 } 136 }
134 137
135 self->top = nd; 138 browser->top = nd;
136} 139}
137 140
138unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self) 141unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
139{ 142{
140 struct rb_node *nd; 143 struct rb_node *nd;
141 int row = 0; 144 int row = 0;
142 145
143 if (self->top == NULL) 146 if (browser->top == NULL)
144 self->top = rb_first(self->entries); 147 browser->top = rb_first(browser->entries);
145 148
146 nd = self->top; 149 nd = browser->top;
147 150
148 while (nd != NULL) { 151 while (nd != NULL) {
149 ui_browser__gotorc(self, row, 0); 152 ui_browser__gotorc(browser, row, 0);
150 self->write(self, nd, row); 153 browser->write(browser, nd, row);
151 if (++row == self->height) 154 if (++row == browser->height)
152 break; 155 break;
153 nd = rb_next(nd); 156 nd = rb_next(nd);
154 } 157 }
@@ -156,17 +159,17 @@ unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
156 return row; 159 return row;
157} 160}
158 161
159bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) 162bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row)
160{ 163{
161 return self->top_idx + row == self->index; 164 return browser->top_idx + row == browser->index;
162} 165}
163 166
164void ui_browser__refresh_dimensions(struct ui_browser *self) 167void ui_browser__refresh_dimensions(struct ui_browser *browser)
165{ 168{
166 self->width = SLtt_Screen_Cols - 1; 169 browser->width = SLtt_Screen_Cols - 1;
167 self->height = SLtt_Screen_Rows - 2; 170 browser->height = SLtt_Screen_Rows - 2;
168 self->y = 1; 171 browser->y = 1;
169 self->x = 0; 172 browser->x = 0;
170} 173}
171 174
172void ui_browser__handle_resize(struct ui_browser *browser) 175void ui_browser__handle_resize(struct ui_browser *browser)
@@ -222,10 +225,10 @@ bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
222 return key == K_ENTER || toupper(key) == 'Y'; 225 return key == K_ENTER || toupper(key) == 'Y';
223} 226}
224 227
225void ui_browser__reset_index(struct ui_browser *self) 228void ui_browser__reset_index(struct ui_browser *browser)
226{ 229{
227 self->index = self->top_idx = 0; 230 browser->index = browser->top_idx = 0;
228 self->seek(self, 0, SEEK_SET); 231 browser->seek(browser, 0, SEEK_SET);
229} 232}
230 233
231void __ui_browser__show_title(struct ui_browser *browser, const char *title) 234void __ui_browser__show_title(struct ui_browser *browser, const char *title)
@@ -242,26 +245,26 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title)
242 pthread_mutex_unlock(&ui__lock); 245 pthread_mutex_unlock(&ui__lock);
243} 246}
244 247
245int ui_browser__show(struct ui_browser *self, const char *title, 248int ui_browser__show(struct ui_browser *browser, const char *title,
246 const char *helpline, ...) 249 const char *helpline, ...)
247{ 250{
248 int err; 251 int err;
249 va_list ap; 252 va_list ap;
250 253
251 ui_browser__refresh_dimensions(self); 254 ui_browser__refresh_dimensions(browser);
252 255
253 pthread_mutex_lock(&ui__lock); 256 pthread_mutex_lock(&ui__lock);
254 __ui_browser__show_title(self, title); 257 __ui_browser__show_title(browser, title);
255 258
256 self->title = title; 259 browser->title = title;
257 free(self->helpline); 260 free(browser->helpline);
258 self->helpline = NULL; 261 browser->helpline = NULL;
259 262
260 va_start(ap, helpline); 263 va_start(ap, helpline);
261 err = vasprintf(&self->helpline, helpline, ap); 264 err = vasprintf(&browser->helpline, helpline, ap);
262 va_end(ap); 265 va_end(ap);
263 if (err > 0) 266 if (err > 0)
264 ui_helpline__push(self->helpline); 267 ui_helpline__push(browser->helpline);
265 pthread_mutex_unlock(&ui__lock); 268 pthread_mutex_unlock(&ui__lock);
266 return err ? 0 : -1; 269 return err ? 0 : -1;
267} 270}
@@ -347,7 +350,7 @@ void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
347 browser->seek(browser, browser->top_idx, SEEK_SET); 350 browser->seek(browser, browser->top_idx, SEEK_SET);
348} 351}
349 352
350int ui_browser__run(struct ui_browser *self, int delay_secs) 353int ui_browser__run(struct ui_browser *browser, int delay_secs)
351{ 354{
352 int err, key; 355 int err, key;
353 356
@@ -355,7 +358,7 @@ int ui_browser__run(struct ui_browser *self, int delay_secs)
355 off_t offset; 358 off_t offset;
356 359
357 pthread_mutex_lock(&ui__lock); 360 pthread_mutex_lock(&ui__lock);
358 err = __ui_browser__refresh(self); 361 err = __ui_browser__refresh(browser);
359 SLsmg_refresh(); 362 SLsmg_refresh();
360 pthread_mutex_unlock(&ui__lock); 363 pthread_mutex_unlock(&ui__lock);
361 if (err < 0) 364 if (err < 0)
@@ -365,18 +368,18 @@ int ui_browser__run(struct ui_browser *self, int delay_secs)
365 368
366 if (key == K_RESIZE) { 369 if (key == K_RESIZE) {
367 ui__refresh_dimensions(false); 370 ui__refresh_dimensions(false);
368 ui_browser__refresh_dimensions(self); 371 ui_browser__refresh_dimensions(browser);
369 __ui_browser__show_title(self, self->title); 372 __ui_browser__show_title(browser, browser->title);
370 ui_helpline__puts(self->helpline); 373 ui_helpline__puts(browser->helpline);
371 continue; 374 continue;
372 } 375 }
373 376
374 if (self->use_navkeypressed && !self->navkeypressed) { 377 if (browser->use_navkeypressed && !browser->navkeypressed) {
375 if (key == K_DOWN || key == K_UP || 378 if (key == K_DOWN || key == K_UP ||
376 key == K_PGDN || key == K_PGUP || 379 key == K_PGDN || key == K_PGUP ||
377 key == K_HOME || key == K_END || 380 key == K_HOME || key == K_END ||
378 key == ' ') { 381 key == ' ') {
379 self->navkeypressed = true; 382 browser->navkeypressed = true;
380 continue; 383 continue;
381 } else 384 } else
382 return key; 385 return key;
@@ -384,59 +387,59 @@ int ui_browser__run(struct ui_browser *self, int delay_secs)
384 387
385 switch (key) { 388 switch (key) {
386 case K_DOWN: 389 case K_DOWN:
387 if (self->index == self->nr_entries - 1) 390 if (browser->index == browser->nr_entries - 1)
388 break; 391 break;
389 ++self->index; 392 ++browser->index;
390 if (self->index == self->top_idx + self->height) { 393 if (browser->index == browser->top_idx + browser->height) {
391 ++self->top_idx; 394 ++browser->top_idx;
392 self->seek(self, +1, SEEK_CUR); 395 browser->seek(browser, +1, SEEK_CUR);
393 } 396 }
394 break; 397 break;
395 case K_UP: 398 case K_UP:
396 if (self->index == 0) 399 if (browser->index == 0)
397 break; 400 break;
398 --self->index; 401 --browser->index;
399 if (self->index < self->top_idx) { 402 if (browser->index < browser->top_idx) {
400 --self->top_idx; 403 --browser->top_idx;
401 self->seek(self, -1, SEEK_CUR); 404 browser->seek(browser, -1, SEEK_CUR);
402 } 405 }
403 break; 406 break;
404 case K_PGDN: 407 case K_PGDN:
405 case ' ': 408 case ' ':
406 if (self->top_idx + self->height > self->nr_entries - 1) 409 if (browser->top_idx + browser->height > browser->nr_entries - 1)
407 break; 410 break;
408 411
409 offset = self->height; 412 offset = browser->height;
410 if (self->index + offset > self->nr_entries - 1) 413 if (browser->index + offset > browser->nr_entries - 1)
411 offset = self->nr_entries - 1 - self->index; 414 offset = browser->nr_entries - 1 - browser->index;
412 self->index += offset; 415 browser->index += offset;
413 self->top_idx += offset; 416 browser->top_idx += offset;
414 self->seek(self, +offset, SEEK_CUR); 417 browser->seek(browser, +offset, SEEK_CUR);
415 break; 418 break;
416 case K_PGUP: 419 case K_PGUP:
417 if (self->top_idx == 0) 420 if (browser->top_idx == 0)
418 break; 421 break;
419 422
420 if (self->top_idx < self->height) 423 if (browser->top_idx < browser->height)
421 offset = self->top_idx; 424 offset = browser->top_idx;
422 else 425 else
423 offset = self->height; 426 offset = browser->height;
424 427
425 self->index -= offset; 428 browser->index -= offset;
426 self->top_idx -= offset; 429 browser->top_idx -= offset;
427 self->seek(self, -offset, SEEK_CUR); 430 browser->seek(browser, -offset, SEEK_CUR);
428 break; 431 break;
429 case K_HOME: 432 case K_HOME:
430 ui_browser__reset_index(self); 433 ui_browser__reset_index(browser);
431 break; 434 break;
432 case K_END: 435 case K_END:
433 offset = self->height - 1; 436 offset = browser->height - 1;
434 if (offset >= self->nr_entries) 437 if (offset >= browser->nr_entries)
435 offset = self->nr_entries - 1; 438 offset = browser->nr_entries - 1;
436 439
437 self->index = self->nr_entries - 1; 440 browser->index = browser->nr_entries - 1;
438 self->top_idx = self->index - offset; 441 browser->top_idx = browser->index - offset;
439 self->seek(self, -offset, SEEK_END); 442 browser->seek(browser, -offset, SEEK_END);
440 break; 443 break;
441 default: 444 default:
442 return key; 445 return key;
@@ -445,22 +448,22 @@ int ui_browser__run(struct ui_browser *self, int delay_secs)
445 return -1; 448 return -1;
446} 449}
447 450
448unsigned int ui_browser__list_head_refresh(struct ui_browser *self) 451unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
449{ 452{
450 struct list_head *pos; 453 struct list_head *pos;
451 struct list_head *head = self->entries; 454 struct list_head *head = browser->entries;
452 int row = 0; 455 int row = 0;
453 456
454 if (self->top == NULL || self->top == self->entries) 457 if (browser->top == NULL || browser->top == browser->entries)
455 self->top = ui_browser__list_head_filter_entries(self, head->next); 458 browser->top = ui_browser__list_head_filter_entries(browser, head->next);
456 459
457 pos = self->top; 460 pos = browser->top;
458 461
459 list_for_each_from(pos, head) { 462 list_for_each_from(pos, head) {
460 if (!self->filter || !self->filter(self, pos)) { 463 if (!browser->filter || !browser->filter(browser, pos)) {
461 ui_browser__gotorc(self, row, 0); 464 ui_browser__gotorc(browser, row, 0);
462 self->write(self, pos, row); 465 browser->write(browser, pos, row);
463 if (++row == self->height) 466 if (++row == browser->height)
464 break; 467 break;
465 } 468 }
466 } 469 }
@@ -503,6 +506,12 @@ static struct ui_browser__colorset {
503 .bg = "default", 506 .bg = "default",
504 }, 507 },
505 { 508 {
509 .colorset = HE_COLORSET_ADDR,
510 .name = "addr",
511 .fg = "magenta",
512 .bg = "default",
513 },
514 {
506 .name = NULL, 515 .name = NULL,
507 } 516 }
508}; 517};
@@ -584,6 +593,111 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
584 return row; 593 return row;
585} 594}
586 595
596void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
597 u16 start, u16 end)
598{
599 SLsmg_set_char_set(1);
600 ui_browser__gotorc(browser, start, column);
601 SLsmg_draw_vline(end - start + 1);
602 SLsmg_set_char_set(0);
603}
604
605void ui_browser__write_graph(struct ui_browser *browser __used, int graph)
606{
607 SLsmg_set_char_set(1);
608 SLsmg_write_char(graph);
609 SLsmg_set_char_set(0);
610}
611
612static void __ui_browser__line_arrow_up(struct ui_browser *browser,
613 unsigned int column,
614 u64 start, u64 end)
615{
616 unsigned int row, end_row;
617
618 SLsmg_set_char_set(1);
619
620 if (start < browser->top_idx + browser->height) {
621 row = start - browser->top_idx;
622 ui_browser__gotorc(browser, row, column);
623 SLsmg_write_char(SLSMG_LLCORN_CHAR);
624 ui_browser__gotorc(browser, row, column + 1);
625 SLsmg_draw_hline(2);
626
627 if (row-- == 0)
628 goto out;
629 } else
630 row = browser->height - 1;
631
632 if (end > browser->top_idx)
633 end_row = end - browser->top_idx;
634 else
635 end_row = 0;
636
637 ui_browser__gotorc(browser, end_row, column);
638 SLsmg_draw_vline(row - end_row + 1);
639
640 ui_browser__gotorc(browser, end_row, column);
641 if (end >= browser->top_idx) {
642 SLsmg_write_char(SLSMG_ULCORN_CHAR);
643 ui_browser__gotorc(browser, end_row, column + 1);
644 SLsmg_write_char(SLSMG_HLINE_CHAR);
645 ui_browser__gotorc(browser, end_row, column + 2);
646 SLsmg_write_char(SLSMG_RARROW_CHAR);
647 }
648out:
649 SLsmg_set_char_set(0);
650}
651
652static void __ui_browser__line_arrow_down(struct ui_browser *browser,
653 unsigned int column,
654 u64 start, u64 end)
655{
656 unsigned int row, end_row;
657
658 SLsmg_set_char_set(1);
659
660 if (start >= browser->top_idx) {
661 row = start - browser->top_idx;
662 ui_browser__gotorc(browser, row, column);
663 SLsmg_write_char(SLSMG_ULCORN_CHAR);
664 ui_browser__gotorc(browser, row, column + 1);
665 SLsmg_draw_hline(2);
666
667 if (row++ == 0)
668 goto out;
669 } else
670 row = 0;
671
672 if (end >= browser->top_idx + browser->height)
673 end_row = browser->height - 1;
674 else
675 end_row = end - browser->top_idx;;
676
677 ui_browser__gotorc(browser, row, column);
678 SLsmg_draw_vline(end_row - row + 1);
679
680 ui_browser__gotorc(browser, end_row, column);
681 if (end < browser->top_idx + browser->height) {
682 SLsmg_write_char(SLSMG_LLCORN_CHAR);
683 ui_browser__gotorc(browser, end_row, column + 1);
684 SLsmg_write_char(SLSMG_HLINE_CHAR);
685 ui_browser__gotorc(browser, end_row, column + 2);
686 SLsmg_write_char(SLSMG_RARROW_CHAR);
687 }
688out:
689 SLsmg_set_char_set(0);
690}
691
692void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
693 u64 start, u64 end)
694{
695 if (start > end)
696 __ui_browser__line_arrow_up(browser, column, start, end);
697 else
698 __ui_browser__line_arrow_down(browser, column, start, end);
699}
700
587void ui_browser__init(void) 701void ui_browser__init(void)
588{ 702{
589 int i = 0; 703 int i = 0;
@@ -594,4 +708,6 @@ void ui_browser__init(void)
594 struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; 708 struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
595 sltt_set_color(c->colorset, c->name, c->fg, c->bg); 709 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
596 } 710 }
711
712 annotate_browser__init();
597} 713}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/ui/browser.h
index 6ee82f60feaf..af70314605e5 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -10,11 +10,13 @@
10#define HE_COLORSET_NORMAL 52 10#define HE_COLORSET_NORMAL 52
11#define HE_COLORSET_SELECTED 53 11#define HE_COLORSET_SELECTED 53
12#define HE_COLORSET_CODE 54 12#define HE_COLORSET_CODE 54
13#define HE_COLORSET_ADDR 55
13 14
14struct ui_browser { 15struct ui_browser {
15 u64 index, top_idx; 16 u64 index, top_idx;
16 void *top, *entries; 17 void *top, *entries;
17 u16 y, x, width, height; 18 u16 y, x, width, height;
19 int current_color;
18 void *priv; 20 void *priv;
19 const char *title; 21 const char *title;
20 char *helpline; 22 char *helpline;
@@ -27,7 +29,7 @@ struct ui_browser {
27 bool use_navkeypressed; 29 bool use_navkeypressed;
28}; 30};
29 31
30void ui_browser__set_color(struct ui_browser *self, int color); 32int ui_browser__set_color(struct ui_browser *browser, int color);
31void ui_browser__set_percent_color(struct ui_browser *self, 33void ui_browser__set_percent_color(struct ui_browser *self,
32 double percent, bool current); 34 double percent, bool current);
33bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row); 35bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
@@ -35,6 +37,9 @@ void ui_browser__refresh_dimensions(struct ui_browser *self);
35void ui_browser__reset_index(struct ui_browser *self); 37void ui_browser__reset_index(struct ui_browser *self);
36 38
37void ui_browser__gotorc(struct ui_browser *self, int y, int x); 39void ui_browser__gotorc(struct ui_browser *self, int y, int x);
40void ui_browser__write_graph(struct ui_browser *browser, int graph);
41void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
42 u64 start, u64 end);
38void __ui_browser__show_title(struct ui_browser *browser, const char *title); 43void __ui_browser__show_title(struct ui_browser *browser, const char *title);
39void ui_browser__show_title(struct ui_browser *browser, const char *title); 44void ui_browser__show_title(struct ui_browser *browser, const char *title);
40int ui_browser__show(struct ui_browser *self, const char *title, 45int ui_browser__show(struct ui_browser *self, const char *title,
@@ -44,6 +49,8 @@ int ui_browser__refresh(struct ui_browser *self);
44int ui_browser__run(struct ui_browser *browser, int delay_secs); 49int ui_browser__run(struct ui_browser *browser, int delay_secs);
45void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); 50void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
46void ui_browser__handle_resize(struct ui_browser *browser); 51void ui_browser__handle_resize(struct ui_browser *browser);
52void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
53 u16 start, u16 end);
47 54
48int ui_browser__warning(struct ui_browser *browser, int timeout, 55int ui_browser__warning(struct ui_browser *browser, int timeout,
49 const char *format, ...); 56 const char *format, ...);
@@ -62,4 +69,5 @@ void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whenc
62unsigned int ui_browser__list_head_refresh(struct ui_browser *self); 69unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
63 70
64void ui_browser__init(void); 71void ui_browser__init(void);
72void annotate_browser__init(void);
65#endif /* _PERF_UI_BROWSER_H_ */ 73#endif /* _PERF_UI_BROWSER_H_ */
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
new file mode 100644
index 000000000000..34b1c46eaf42
--- /dev/null
+++ b/tools/perf/ui/browsers/annotate.c
@@ -0,0 +1,951 @@
1#include "../../util/util.h"
2#include "../browser.h"
3#include "../helpline.h"
4#include "../libslang.h"
5#include "../ui.h"
6#include "../util.h"
7#include "../../util/annotate.h"
8#include "../../util/hist.h"
9#include "../../util/sort.h"
10#include "../../util/symbol.h"
11#include <pthread.h>
12#include <newt.h>
13
14struct browser_disasm_line {
15 struct rb_node rb_node;
16 double percent;
17 u32 idx;
18 int idx_asm;
19 int jump_sources;
20};
21
22static struct annotate_browser_opt {
23 bool hide_src_code,
24 use_offset,
25 jump_arrows,
26 show_nr_jumps;
27} annotate_browser__opts = {
28 .use_offset = true,
29 .jump_arrows = true,
30};
31
32struct annotate_browser {
33 struct ui_browser b;
34 struct rb_root entries;
35 struct rb_node *curr_hot;
36 struct disasm_line *selection;
37 struct disasm_line **offsets;
38 u64 start;
39 int nr_asm_entries;
40 int nr_entries;
41 int max_jump_sources;
42 int nr_jumps;
43 bool searching_backwards;
44 u8 addr_width;
45 u8 jumps_width;
46 u8 target_width;
47 u8 min_addr_width;
48 u8 max_addr_width;
49 char search_bf[128];
50};
51
52static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
53{
54 return (struct browser_disasm_line *)(dl + 1);
55}
56
57static bool disasm_line__filter(struct ui_browser *browser __used, void *entry)
58{
59 if (annotate_browser__opts.hide_src_code) {
60 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
61 return dl->offset == -1;
62 }
63
64 return false;
65}
66
67static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
68 int nr, bool current)
69{
70 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
71 return HE_COLORSET_SELECTED;
72 if (nr == browser->max_jump_sources)
73 return HE_COLORSET_TOP;
74 if (nr > 1)
75 return HE_COLORSET_MEDIUM;
76 return HE_COLORSET_NORMAL;
77}
78
79static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
80 int nr, bool current)
81{
82 int color = annotate_browser__jumps_percent_color(browser, nr, current);
83 return ui_browser__set_color(&browser->b, color);
84}
85
86static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
87{
88 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
89 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
90 struct browser_disasm_line *bdl = disasm_line__browser(dl);
91 bool current_entry = ui_browser__is_current_entry(browser, row);
92 bool change_color = (!annotate_browser__opts.hide_src_code &&
93 (!current_entry || (browser->use_navkeypressed &&
94 !browser->navkeypressed)));
95 int width = browser->width, printed;
96 char bf[256];
97
98 if (dl->offset != -1 && bdl->percent != 0.0) {
99 ui_browser__set_percent_color(browser, bdl->percent, current_entry);
100 slsmg_printf("%6.2f ", bdl->percent);
101 } else {
102 ui_browser__set_percent_color(browser, 0, current_entry);
103 slsmg_write_nstring(" ", 7);
104 }
105
106 SLsmg_write_char(' ');
107
108 /* The scroll bar isn't being used */
109 if (!browser->navkeypressed)
110 width += 1;
111
112 if (!*dl->line)
113 slsmg_write_nstring(" ", width - 7);
114 else if (dl->offset == -1) {
115 printed = scnprintf(bf, sizeof(bf), "%*s ",
116 ab->addr_width, " ");
117 slsmg_write_nstring(bf, printed);
118 slsmg_write_nstring(dl->line, width - printed - 6);
119 } else {
120 u64 addr = dl->offset;
121 int color = -1;
122
123 if (!annotate_browser__opts.use_offset)
124 addr += ab->start;
125
126 if (!annotate_browser__opts.use_offset) {
127 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
128 } else {
129 if (bdl->jump_sources) {
130 if (annotate_browser__opts.show_nr_jumps) {
131 int prev;
132 printed = scnprintf(bf, sizeof(bf), "%*d ",
133 ab->jumps_width,
134 bdl->jump_sources);
135 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
136 current_entry);
137 slsmg_write_nstring(bf, printed);
138 ui_browser__set_color(browser, prev);
139 }
140
141 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
142 ab->target_width, addr);
143 } else {
144 printed = scnprintf(bf, sizeof(bf), "%*s ",
145 ab->addr_width, " ");
146 }
147 }
148
149 if (change_color)
150 color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
151 slsmg_write_nstring(bf, printed);
152 if (change_color)
153 ui_browser__set_color(browser, color);
154 if (dl->ins && dl->ins->ops->scnprintf) {
155 if (ins__is_jump(dl->ins)) {
156 bool fwd = dl->ops.target.offset > (u64)dl->offset;
157
158 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
159 SLSMG_UARROW_CHAR);
160 SLsmg_write_char(' ');
161 } else if (ins__is_call(dl->ins)) {
162 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
163 SLsmg_write_char(' ');
164 } else {
165 slsmg_write_nstring(" ", 2);
166 }
167 } else {
168 if (strcmp(dl->name, "retq")) {
169 slsmg_write_nstring(" ", 2);
170 } else {
171 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
172 SLsmg_write_char(' ');
173 }
174 }
175
176 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
177 slsmg_write_nstring(bf, width - 10 - printed);
178 }
179
180 if (current_entry)
181 ab->selection = dl;
182}
183
184static void annotate_browser__draw_current_jump(struct ui_browser *browser)
185{
186 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
187 struct disasm_line *cursor = ab->selection, *target;
188 struct browser_disasm_line *btarget, *bcursor;
189 unsigned int from, to;
190
191 if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
192 !disasm_line__has_offset(cursor))
193 return;
194
195 target = ab->offsets[cursor->ops.target.offset];
196 if (!target)
197 return;
198
199 bcursor = disasm_line__browser(cursor);
200 btarget = disasm_line__browser(target);
201
202 if (annotate_browser__opts.hide_src_code) {
203 from = bcursor->idx_asm;
204 to = btarget->idx_asm;
205 } else {
206 from = (u64)bcursor->idx;
207 to = (u64)btarget->idx;
208 }
209
210 ui_browser__set_color(browser, HE_COLORSET_CODE);
211 __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
212}
213
214static unsigned int annotate_browser__refresh(struct ui_browser *browser)
215{
216 int ret = ui_browser__list_head_refresh(browser);
217
218 if (annotate_browser__opts.jump_arrows)
219 annotate_browser__draw_current_jump(browser);
220
221 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
222 __ui_browser__vline(browser, 7, 0, browser->height - 1);
223 return ret;
224}
225
226static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
227{
228 double percent = 0.0;
229
230 if (dl->offset != -1) {
231 int len = sym->end - sym->start;
232 unsigned int hits = 0;
233 struct annotation *notes = symbol__annotation(sym);
234 struct source_line *src_line = notes->src->lines;
235 struct sym_hist *h = annotation__histogram(notes, evidx);
236 s64 offset = dl->offset;
237 struct disasm_line *next;
238
239 next = disasm__get_next_ip_line(&notes->src->source, dl);
240 while (offset < (s64)len &&
241 (next == NULL || offset < next->offset)) {
242 if (src_line) {
243 percent += src_line[offset].percent;
244 } else
245 hits += h->addr[offset];
246
247 ++offset;
248 }
249 /*
250 * If the percentage wasn't already calculated in
251 * symbol__get_source_line, do it now:
252 */
253 if (src_line == NULL && h->sum)
254 percent = 100.0 * hits / h->sum;
255 }
256
257 return percent;
258}
259
260static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
261{
262 struct rb_node **p = &root->rb_node;
263 struct rb_node *parent = NULL;
264 struct browser_disasm_line *l;
265
266 while (*p != NULL) {
267 parent = *p;
268 l = rb_entry(parent, struct browser_disasm_line, rb_node);
269 if (bdl->percent < l->percent)
270 p = &(*p)->rb_left;
271 else
272 p = &(*p)->rb_right;
273 }
274 rb_link_node(&bdl->rb_node, parent, p);
275 rb_insert_color(&bdl->rb_node, root);
276}
277
278static void annotate_browser__set_top(struct annotate_browser *browser,
279 struct disasm_line *pos, u32 idx)
280{
281 unsigned back;
282
283 ui_browser__refresh_dimensions(&browser->b);
284 back = browser->b.height / 2;
285 browser->b.top_idx = browser->b.index = idx;
286
287 while (browser->b.top_idx != 0 && back != 0) {
288 pos = list_entry(pos->node.prev, struct disasm_line, node);
289
290 if (disasm_line__filter(&browser->b, &pos->node))
291 continue;
292
293 --browser->b.top_idx;
294 --back;
295 }
296
297 browser->b.top = pos;
298 browser->b.navkeypressed = true;
299}
300
301static void annotate_browser__set_rb_top(struct annotate_browser *browser,
302 struct rb_node *nd)
303{
304 struct browser_disasm_line *bpos;
305 struct disasm_line *pos;
306 u32 idx;
307
308 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
309 pos = ((struct disasm_line *)bpos) - 1;
310 idx = bpos->idx;
311 if (annotate_browser__opts.hide_src_code)
312 idx = bpos->idx_asm;
313 annotate_browser__set_top(browser, pos, idx);
314 browser->curr_hot = nd;
315}
316
317static void annotate_browser__calc_percent(struct annotate_browser *browser,
318 int evidx)
319{
320 struct map_symbol *ms = browser->b.priv;
321 struct symbol *sym = ms->sym;
322 struct annotation *notes = symbol__annotation(sym);
323 struct disasm_line *pos;
324
325 browser->entries = RB_ROOT;
326
327 pthread_mutex_lock(&notes->lock);
328
329 list_for_each_entry(pos, &notes->src->source, node) {
330 struct browser_disasm_line *bpos = disasm_line__browser(pos);
331 bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
332 if (bpos->percent < 0.01) {
333 RB_CLEAR_NODE(&bpos->rb_node);
334 continue;
335 }
336 disasm_rb_tree__insert(&browser->entries, bpos);
337 }
338 pthread_mutex_unlock(&notes->lock);
339
340 browser->curr_hot = rb_last(&browser->entries);
341}
342
343static bool annotate_browser__toggle_source(struct annotate_browser *browser)
344{
345 struct disasm_line *dl;
346 struct browser_disasm_line *bdl;
347 off_t offset = browser->b.index - browser->b.top_idx;
348
349 browser->b.seek(&browser->b, offset, SEEK_CUR);
350 dl = list_entry(browser->b.top, struct disasm_line, node);
351 bdl = disasm_line__browser(dl);
352
353 if (annotate_browser__opts.hide_src_code) {
354 if (bdl->idx_asm < offset)
355 offset = bdl->idx;
356
357 browser->b.nr_entries = browser->nr_entries;
358 annotate_browser__opts.hide_src_code = false;
359 browser->b.seek(&browser->b, -offset, SEEK_CUR);
360 browser->b.top_idx = bdl->idx - offset;
361 browser->b.index = bdl->idx;
362 } else {
363 if (bdl->idx_asm < 0) {
364 ui_helpline__puts("Only available for assembly lines.");
365 browser->b.seek(&browser->b, -offset, SEEK_CUR);
366 return false;
367 }
368
369 if (bdl->idx_asm < offset)
370 offset = bdl->idx_asm;
371
372 browser->b.nr_entries = browser->nr_asm_entries;
373 annotate_browser__opts.hide_src_code = true;
374 browser->b.seek(&browser->b, -offset, SEEK_CUR);
375 browser->b.top_idx = bdl->idx_asm - offset;
376 browser->b.index = bdl->idx_asm;
377 }
378
379 return true;
380}
381
382static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
383{
384 ui_browser__reset_index(&browser->b);
385 browser->b.nr_entries = browser->nr_asm_entries;
386}
387
388static bool annotate_browser__callq(struct annotate_browser *browser,
389 int evidx, void (*timer)(void *arg),
390 void *arg, int delay_secs)
391{
392 struct map_symbol *ms = browser->b.priv;
393 struct disasm_line *dl = browser->selection;
394 struct symbol *sym = ms->sym;
395 struct annotation *notes;
396 struct symbol *target;
397 u64 ip;
398
399 if (!ins__is_call(dl->ins))
400 return false;
401
402 ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
403 target = map__find_symbol(ms->map, ip, NULL);
404 if (target == NULL) {
405 ui_helpline__puts("The called function was not found.");
406 return true;
407 }
408
409 notes = symbol__annotation(target);
410 pthread_mutex_lock(&notes->lock);
411
412 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
413 pthread_mutex_unlock(&notes->lock);
414 ui__warning("Not enough memory for annotating '%s' symbol!\n",
415 target->name);
416 return true;
417 }
418
419 pthread_mutex_unlock(&notes->lock);
420 symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
421 ui_browser__show_title(&browser->b, sym->name);
422 return true;
423}
424
425static
426struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
427 s64 offset, s64 *idx)
428{
429 struct map_symbol *ms = browser->b.priv;
430 struct symbol *sym = ms->sym;
431 struct annotation *notes = symbol__annotation(sym);
432 struct disasm_line *pos;
433
434 *idx = 0;
435 list_for_each_entry(pos, &notes->src->source, node) {
436 if (pos->offset == offset)
437 return pos;
438 if (!disasm_line__filter(&browser->b, &pos->node))
439 ++*idx;
440 }
441
442 return NULL;
443}
444
445static bool annotate_browser__jump(struct annotate_browser *browser)
446{
447 struct disasm_line *dl = browser->selection;
448 s64 idx;
449
450 if (!ins__is_jump(dl->ins))
451 return false;
452
453 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
454 if (dl == NULL) {
455 ui_helpline__puts("Invallid jump offset");
456 return true;
457 }
458
459 annotate_browser__set_top(browser, dl, idx);
460
461 return true;
462}
463
464static
465struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
466 char *s, s64 *idx)
467{
468 struct map_symbol *ms = browser->b.priv;
469 struct symbol *sym = ms->sym;
470 struct annotation *notes = symbol__annotation(sym);
471 struct disasm_line *pos = browser->selection;
472
473 *idx = browser->b.index;
474 list_for_each_entry_continue(pos, &notes->src->source, node) {
475 if (disasm_line__filter(&browser->b, &pos->node))
476 continue;
477
478 ++*idx;
479
480 if (pos->line && strstr(pos->line, s) != NULL)
481 return pos;
482 }
483
484 return NULL;
485}
486
487static bool __annotate_browser__search(struct annotate_browser *browser)
488{
489 struct disasm_line *dl;
490 s64 idx;
491
492 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
493 if (dl == NULL) {
494 ui_helpline__puts("String not found!");
495 return false;
496 }
497
498 annotate_browser__set_top(browser, dl, idx);
499 browser->searching_backwards = false;
500 return true;
501}
502
503static
504struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
505 char *s, s64 *idx)
506{
507 struct map_symbol *ms = browser->b.priv;
508 struct symbol *sym = ms->sym;
509 struct annotation *notes = symbol__annotation(sym);
510 struct disasm_line *pos = browser->selection;
511
512 *idx = browser->b.index;
513 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
514 if (disasm_line__filter(&browser->b, &pos->node))
515 continue;
516
517 --*idx;
518
519 if (pos->line && strstr(pos->line, s) != NULL)
520 return pos;
521 }
522
523 return NULL;
524}
525
526static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
527{
528 struct disasm_line *dl;
529 s64 idx;
530
531 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
532 if (dl == NULL) {
533 ui_helpline__puts("String not found!");
534 return false;
535 }
536
537 annotate_browser__set_top(browser, dl, idx);
538 browser->searching_backwards = true;
539 return true;
540}
541
542static bool annotate_browser__search_window(struct annotate_browser *browser,
543 int delay_secs)
544{
545 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
546 "ENTER: OK, ESC: Cancel",
547 delay_secs * 2) != K_ENTER ||
548 !*browser->search_bf)
549 return false;
550
551 return true;
552}
553
554static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
555{
556 if (annotate_browser__search_window(browser, delay_secs))
557 return __annotate_browser__search(browser);
558
559 return false;
560}
561
562static bool annotate_browser__continue_search(struct annotate_browser *browser,
563 int delay_secs)
564{
565 if (!*browser->search_bf)
566 return annotate_browser__search(browser, delay_secs);
567
568 return __annotate_browser__search(browser);
569}
570
571static bool annotate_browser__search_reverse(struct annotate_browser *browser,
572 int delay_secs)
573{
574 if (annotate_browser__search_window(browser, delay_secs))
575 return __annotate_browser__search_reverse(browser);
576
577 return false;
578}
579
580static
581bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
582 int delay_secs)
583{
584 if (!*browser->search_bf)
585 return annotate_browser__search_reverse(browser, delay_secs);
586
587 return __annotate_browser__search_reverse(browser);
588}
589
590static void annotate_browser__update_addr_width(struct annotate_browser *browser)
591{
592 if (annotate_browser__opts.use_offset)
593 browser->target_width = browser->min_addr_width;
594 else
595 browser->target_width = browser->max_addr_width;
596
597 browser->addr_width = browser->target_width;
598
599 if (annotate_browser__opts.show_nr_jumps)
600 browser->addr_width += browser->jumps_width + 1;
601}
602
603static int annotate_browser__run(struct annotate_browser *browser, int evidx,
604 void(*timer)(void *arg),
605 void *arg, int delay_secs)
606{
607 struct rb_node *nd = NULL;
608 struct map_symbol *ms = browser->b.priv;
609 struct symbol *sym = ms->sym;
610 const char *help = "Press 'h' for help on key bindings";
611 int key;
612
613 if (ui_browser__show(&browser->b, sym->name, help) < 0)
614 return -1;
615
616 annotate_browser__calc_percent(browser, evidx);
617
618 if (browser->curr_hot) {
619 annotate_browser__set_rb_top(browser, browser->curr_hot);
620 browser->b.navkeypressed = false;
621 }
622
623 nd = browser->curr_hot;
624
625 while (1) {
626 key = ui_browser__run(&browser->b, delay_secs);
627
628 if (delay_secs != 0) {
629 annotate_browser__calc_percent(browser, evidx);
630 /*
631 * Current line focus got out of the list of most active
632 * lines, NULL it so that if TAB|UNTAB is pressed, we
633 * move to curr_hot (current hottest line).
634 */
635 if (nd != NULL && RB_EMPTY_NODE(nd))
636 nd = NULL;
637 }
638
639 switch (key) {
640 case K_TIMER:
641 if (timer != NULL)
642 timer(arg);
643
644 if (delay_secs != 0)
645 symbol__annotate_decay_histogram(sym, evidx);
646 continue;
647 case K_TAB:
648 if (nd != NULL) {
649 nd = rb_prev(nd);
650 if (nd == NULL)
651 nd = rb_last(&browser->entries);
652 } else
653 nd = browser->curr_hot;
654 break;
655 case K_UNTAB:
656 if (nd != NULL)
657 nd = rb_next(nd);
658 if (nd == NULL)
659 nd = rb_first(&browser->entries);
660 else
661 nd = browser->curr_hot;
662 break;
663 case K_F1:
664 case 'h':
665 ui_browser__help_window(&browser->b,
666 "UP/DOWN/PGUP\n"
667 "PGDN/SPACE Navigate\n"
668 "q/ESC/CTRL+C Exit\n\n"
669 "-> Go to target\n"
670 "<- Exit\n"
671 "H Cycle thru hottest instructions\n"
672 "j Toggle showing jump to target arrows\n"
673 "J Toggle showing number of jump sources on targets\n"
674 "n Search next string\n"
675 "o Toggle disassembler output/simplified view\n"
676 "s Toggle source code view\n"
677 "/ Search string\n"
678 "? Search previous string\n");
679 continue;
680 case 'H':
681 nd = browser->curr_hot;
682 break;
683 case 's':
684 if (annotate_browser__toggle_source(browser))
685 ui_helpline__puts(help);
686 continue;
687 case 'o':
688 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
689 annotate_browser__update_addr_width(browser);
690 continue;
691 case 'j':
692 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
693 continue;
694 case 'J':
695 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
696 annotate_browser__update_addr_width(browser);
697 continue;
698 case '/':
699 if (annotate_browser__search(browser, delay_secs)) {
700show_help:
701 ui_helpline__puts(help);
702 }
703 continue;
704 case 'n':
705 if (browser->searching_backwards ?
706 annotate_browser__continue_search_reverse(browser, delay_secs) :
707 annotate_browser__continue_search(browser, delay_secs))
708 goto show_help;
709 continue;
710 case '?':
711 if (annotate_browser__search_reverse(browser, delay_secs))
712 goto show_help;
713 continue;
714 case 'D': {
715 static int seq;
716 ui_helpline__pop();
717 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
718 seq++, browser->b.nr_entries,
719 browser->b.height,
720 browser->b.index,
721 browser->b.top_idx,
722 browser->nr_asm_entries);
723 }
724 continue;
725 case K_ENTER:
726 case K_RIGHT:
727 if (browser->selection == NULL)
728 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
729 else if (browser->selection->offset == -1)
730 ui_helpline__puts("Actions are only available for assembly lines.");
731 else if (!browser->selection->ins) {
732 if (strcmp(browser->selection->name, "retq"))
733 goto show_sup_ins;
734 goto out;
735 } else if (!(annotate_browser__jump(browser) ||
736 annotate_browser__callq(browser, evidx, timer, arg, delay_secs))) {
737show_sup_ins:
738 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
739 }
740 continue;
741 case K_LEFT:
742 case K_ESC:
743 case 'q':
744 case CTRL('c'):
745 goto out;
746 default:
747 continue;
748 }
749
750 if (nd != NULL)
751 annotate_browser__set_rb_top(browser, nd);
752 }
753out:
754 ui_browser__hide(&browser->b);
755 return key;
756}
757
758int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
759 void(*timer)(void *arg), void *arg, int delay_secs)
760{
761 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
762 timer, arg, delay_secs);
763}
764
765static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
766 size_t size)
767{
768 u64 offset;
769
770 for (offset = 0; offset < size; ++offset) {
771 struct disasm_line *dl = browser->offsets[offset], *dlt;
772 struct browser_disasm_line *bdlt;
773
774 if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
775 !disasm_line__has_offset(dl))
776 continue;
777
778 if (dl->ops.target.offset >= size) {
779 ui__error("jump to after symbol!\n"
780 "size: %zx, jump target: %" PRIx64,
781 size, dl->ops.target.offset);
782 continue;
783 }
784
785 dlt = browser->offsets[dl->ops.target.offset];
786 /*
787 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
788 * have to adjust to the previous offset?
789 */
790 if (dlt == NULL)
791 continue;
792
793 bdlt = disasm_line__browser(dlt);
794 if (++bdlt->jump_sources > browser->max_jump_sources)
795 browser->max_jump_sources = bdlt->jump_sources;
796
797 ++browser->nr_jumps;
798 }
799
800}
801
802static inline int width_jumps(int n)
803{
804 if (n >= 100)
805 return 5;
806 if (n / 10)
807 return 2;
808 return 1;
809}
810
811int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
812 void(*timer)(void *arg), void *arg,
813 int delay_secs)
814{
815 struct disasm_line *pos, *n;
816 struct annotation *notes;
817 const size_t size = symbol__size(sym);
818 struct map_symbol ms = {
819 .map = map,
820 .sym = sym,
821 };
822 struct annotate_browser browser = {
823 .b = {
824 .refresh = annotate_browser__refresh,
825 .seek = ui_browser__list_head_seek,
826 .write = annotate_browser__write,
827 .filter = disasm_line__filter,
828 .priv = &ms,
829 .use_navkeypressed = true,
830 },
831 };
832 int ret = -1;
833
834 if (sym == NULL)
835 return -1;
836
837 if (map->dso->annotate_warned)
838 return -1;
839
840 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
841 if (browser.offsets == NULL) {
842 ui__error("Not enough memory!");
843 return -1;
844 }
845
846 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
847 ui__error("%s", ui_helpline__last_msg);
848 goto out_free_offsets;
849 }
850
851 ui_helpline__push("Press <- or ESC to exit");
852
853 notes = symbol__annotation(sym);
854 browser.start = map__rip_2objdump(map, sym->start);
855
856 list_for_each_entry(pos, &notes->src->source, node) {
857 struct browser_disasm_line *bpos;
858 size_t line_len = strlen(pos->line);
859
860 if (browser.b.width < line_len)
861 browser.b.width = line_len;
862 bpos = disasm_line__browser(pos);
863 bpos->idx = browser.nr_entries++;
864 if (pos->offset != -1) {
865 bpos->idx_asm = browser.nr_asm_entries++;
866 /*
867 * FIXME: short term bandaid to cope with assembly
868 * routines that comes with labels in the same column
869 * as the address in objdump, sigh.
870 *
871 * E.g. copy_user_generic_unrolled
872 */
873 if (pos->offset < (s64)size)
874 browser.offsets[pos->offset] = pos;
875 } else
876 bpos->idx_asm = -1;
877 }
878
879 annotate_browser__mark_jump_targets(&browser, size);
880
881 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
882 browser.max_addr_width = hex_width(sym->end);
883 browser.jumps_width = width_jumps(browser.max_jump_sources);
884 browser.b.nr_entries = browser.nr_entries;
885 browser.b.entries = &notes->src->source,
886 browser.b.width += 18; /* Percentage */
887
888 if (annotate_browser__opts.hide_src_code)
889 annotate_browser__init_asm_mode(&browser);
890
891 annotate_browser__update_addr_width(&browser);
892
893 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
894 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
895 list_del(&pos->node);
896 disasm_line__free(pos);
897 }
898
899out_free_offsets:
900 free(browser.offsets);
901 return ret;
902}
903
904#define ANNOTATE_CFG(n) \
905 { .name = #n, .value = &annotate_browser__opts.n, }
906
907/*
908 * Keep the entries sorted, they are bsearch'ed
909 */
910static struct annotate__config {
911 const char *name;
912 bool *value;
913} annotate__configs[] = {
914 ANNOTATE_CFG(hide_src_code),
915 ANNOTATE_CFG(jump_arrows),
916 ANNOTATE_CFG(show_nr_jumps),
917 ANNOTATE_CFG(use_offset),
918};
919
920#undef ANNOTATE_CFG
921
922static int annotate_config__cmp(const void *name, const void *cfgp)
923{
924 const struct annotate__config *cfg = cfgp;
925
926 return strcmp(name, cfg->name);
927}
928
929static int annotate__config(const char *var, const char *value, void *data __used)
930{
931 struct annotate__config *cfg;
932 const char *name;
933
934 if (prefixcmp(var, "annotate.") != 0)
935 return 0;
936
937 name = var + 9;
938 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
939 sizeof(struct annotate__config), annotate_config__cmp);
940
941 if (cfg == NULL)
942 return -1;
943
944 *cfg->value = perf_config_bool(name, value);
945 return 0;
946}
947
948void annotate_browser__init(void)
949{
950 perf_config(annotate__config, NULL);
951}
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 2f83e5dc9967..53f6697d014e 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -5,12 +5,12 @@
5#include <newt.h> 5#include <newt.h>
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7 7
8#include "../../evsel.h" 8#include "../../util/evsel.h"
9#include "../../evlist.h" 9#include "../../util/evlist.h"
10#include "../../hist.h" 10#include "../../util/hist.h"
11#include "../../pstack.h" 11#include "../../util/pstack.h"
12#include "../../sort.h" 12#include "../../util/sort.h"
13#include "../../util.h" 13#include "../../util/util.h"
14 14
15#include "../browser.h" 15#include "../browser.h"
16#include "../helpline.h" 16#include "../helpline.h"
@@ -26,21 +26,21 @@ struct hist_browser {
26 bool has_symbols; 26 bool has_symbols;
27}; 27};
28 28
29static int hists__browser_title(struct hists *self, char *bf, size_t size, 29static int hists__browser_title(struct hists *hists, char *bf, size_t size,
30 const char *ev_name); 30 const char *ev_name);
31 31
32static void hist_browser__refresh_dimensions(struct hist_browser *self) 32static void hist_browser__refresh_dimensions(struct hist_browser *browser)
33{ 33{
34 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 34 /* 3 == +/- toggle symbol before actual hist_entry rendering */
35 self->b.width = 3 + (hists__sort_list_width(self->hists) + 35 browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
36 sizeof("[k]")); 36 sizeof("[k]"));
37} 37}
38 38
39static void hist_browser__reset(struct hist_browser *self) 39static void hist_browser__reset(struct hist_browser *browser)
40{ 40{
41 self->b.nr_entries = self->hists->nr_entries; 41 browser->b.nr_entries = browser->hists->nr_entries;
42 hist_browser__refresh_dimensions(self); 42 hist_browser__refresh_dimensions(browser);
43 ui_browser__reset_index(&self->b); 43 ui_browser__reset_index(&browser->b);
44} 44}
45 45
46static char tree__folded_sign(bool unfolded) 46static char tree__folded_sign(bool unfolded)
@@ -48,32 +48,32 @@ static char tree__folded_sign(bool unfolded)
48 return unfolded ? '-' : '+'; 48 return unfolded ? '-' : '+';
49} 49}
50 50
51static char map_symbol__folded(const struct map_symbol *self) 51static char map_symbol__folded(const struct map_symbol *ms)
52{ 52{
53 return self->has_children ? tree__folded_sign(self->unfolded) : ' '; 53 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
54} 54}
55 55
56static char hist_entry__folded(const struct hist_entry *self) 56static char hist_entry__folded(const struct hist_entry *he)
57{ 57{
58 return map_symbol__folded(&self->ms); 58 return map_symbol__folded(&he->ms);
59} 59}
60 60
61static char callchain_list__folded(const struct callchain_list *self) 61static char callchain_list__folded(const struct callchain_list *cl)
62{ 62{
63 return map_symbol__folded(&self->ms); 63 return map_symbol__folded(&cl->ms);
64} 64}
65 65
66static void map_symbol__set_folding(struct map_symbol *self, bool unfold) 66static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
67{ 67{
68 self->unfolded = unfold ? self->has_children : false; 68 ms->unfolded = unfold ? ms->has_children : false;
69} 69}
70 70
71static int callchain_node__count_rows_rb_tree(struct callchain_node *self) 71static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
72{ 72{
73 int n = 0; 73 int n = 0;
74 struct rb_node *nd; 74 struct rb_node *nd;
75 75
76 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { 76 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
77 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 77 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
78 struct callchain_list *chain; 78 struct callchain_list *chain;
79 char folded_sign = ' '; /* No children */ 79 char folded_sign = ' '; /* No children */
@@ -123,23 +123,23 @@ static int callchain__count_rows(struct rb_root *chain)
123 return n; 123 return n;
124} 124}
125 125
126static bool map_symbol__toggle_fold(struct map_symbol *self) 126static bool map_symbol__toggle_fold(struct map_symbol *ms)
127{ 127{
128 if (!self) 128 if (!ms)
129 return false; 129 return false;
130 130
131 if (!self->has_children) 131 if (!ms->has_children)
132 return false; 132 return false;
133 133
134 self->unfolded = !self->unfolded; 134 ms->unfolded = !ms->unfolded;
135 return true; 135 return true;
136} 136}
137 137
138static void callchain_node__init_have_children_rb_tree(struct callchain_node *self) 138static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
139{ 139{
140 struct rb_node *nd = rb_first(&self->rb_root); 140 struct rb_node *nd = rb_first(&node->rb_root);
141 141
142 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { 142 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
143 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 143 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
144 struct callchain_list *chain; 144 struct callchain_list *chain;
145 bool first = true; 145 bool first = true;
@@ -158,49 +158,49 @@ static void callchain_node__init_have_children_rb_tree(struct callchain_node *se
158 } 158 }
159} 159}
160 160
161static void callchain_node__init_have_children(struct callchain_node *self) 161static void callchain_node__init_have_children(struct callchain_node *node)
162{ 162{
163 struct callchain_list *chain; 163 struct callchain_list *chain;
164 164
165 list_for_each_entry(chain, &self->val, list) 165 list_for_each_entry(chain, &node->val, list)
166 chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root); 166 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
167 167
168 callchain_node__init_have_children_rb_tree(self); 168 callchain_node__init_have_children_rb_tree(node);
169} 169}
170 170
171static void callchain__init_have_children(struct rb_root *self) 171static void callchain__init_have_children(struct rb_root *root)
172{ 172{
173 struct rb_node *nd; 173 struct rb_node *nd;
174 174
175 for (nd = rb_first(self); nd; nd = rb_next(nd)) { 175 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
176 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 176 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
177 callchain_node__init_have_children(node); 177 callchain_node__init_have_children(node);
178 } 178 }
179} 179}
180 180
181static void hist_entry__init_have_children(struct hist_entry *self) 181static void hist_entry__init_have_children(struct hist_entry *he)
182{ 182{
183 if (!self->init_have_children) { 183 if (!he->init_have_children) {
184 self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain); 184 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
185 callchain__init_have_children(&self->sorted_chain); 185 callchain__init_have_children(&he->sorted_chain);
186 self->init_have_children = true; 186 he->init_have_children = true;
187 } 187 }
188} 188}
189 189
190static bool hist_browser__toggle_fold(struct hist_browser *self) 190static bool hist_browser__toggle_fold(struct hist_browser *browser)
191{ 191{
192 if (map_symbol__toggle_fold(self->selection)) { 192 if (map_symbol__toggle_fold(browser->selection)) {
193 struct hist_entry *he = self->he_selection; 193 struct hist_entry *he = browser->he_selection;
194 194
195 hist_entry__init_have_children(he); 195 hist_entry__init_have_children(he);
196 self->hists->nr_entries -= he->nr_rows; 196 browser->hists->nr_entries -= he->nr_rows;
197 197
198 if (he->ms.unfolded) 198 if (he->ms.unfolded)
199 he->nr_rows = callchain__count_rows(&he->sorted_chain); 199 he->nr_rows = callchain__count_rows(&he->sorted_chain);
200 else 200 else
201 he->nr_rows = 0; 201 he->nr_rows = 0;
202 self->hists->nr_entries += he->nr_rows; 202 browser->hists->nr_entries += he->nr_rows;
203 self->b.nr_entries = self->hists->nr_entries; 203 browser->b.nr_entries = browser->hists->nr_entries;
204 204
205 return true; 205 return true;
206 } 206 }
@@ -209,12 +209,12 @@ static bool hist_browser__toggle_fold(struct hist_browser *self)
209 return false; 209 return false;
210} 210}
211 211
212static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold) 212static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
213{ 213{
214 int n = 0; 214 int n = 0;
215 struct rb_node *nd; 215 struct rb_node *nd;
216 216
217 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { 217 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
218 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 218 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
219 struct callchain_list *chain; 219 struct callchain_list *chain;
220 bool has_children = false; 220 bool has_children = false;
@@ -263,37 +263,37 @@ static int callchain__set_folding(struct rb_root *chain, bool unfold)
263 return n; 263 return n;
264} 264}
265 265
266static void hist_entry__set_folding(struct hist_entry *self, bool unfold) 266static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
267{ 267{
268 hist_entry__init_have_children(self); 268 hist_entry__init_have_children(he);
269 map_symbol__set_folding(&self->ms, unfold); 269 map_symbol__set_folding(&he->ms, unfold);
270 270
271 if (self->ms.has_children) { 271 if (he->ms.has_children) {
272 int n = callchain__set_folding(&self->sorted_chain, unfold); 272 int n = callchain__set_folding(&he->sorted_chain, unfold);
273 self->nr_rows = unfold ? n : 0; 273 he->nr_rows = unfold ? n : 0;
274 } else 274 } else
275 self->nr_rows = 0; 275 he->nr_rows = 0;
276} 276}
277 277
278static void hists__set_folding(struct hists *self, bool unfold) 278static void hists__set_folding(struct hists *hists, bool unfold)
279{ 279{
280 struct rb_node *nd; 280 struct rb_node *nd;
281 281
282 self->nr_entries = 0; 282 hists->nr_entries = 0;
283 283
284 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 284 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
285 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 285 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
286 hist_entry__set_folding(he, unfold); 286 hist_entry__set_folding(he, unfold);
287 self->nr_entries += 1 + he->nr_rows; 287 hists->nr_entries += 1 + he->nr_rows;
288 } 288 }
289} 289}
290 290
291static void hist_browser__set_folding(struct hist_browser *self, bool unfold) 291static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
292{ 292{
293 hists__set_folding(self->hists, unfold); 293 hists__set_folding(browser->hists, unfold);
294 self->b.nr_entries = self->hists->nr_entries; 294 browser->b.nr_entries = browser->hists->nr_entries;
295 /* Go to the start, we may be way after valid entries after a collapse */ 295 /* Go to the start, we may be way after valid entries after a collapse */
296 ui_browser__reset_index(&self->b); 296 ui_browser__reset_index(&browser->b);
297} 297}
298 298
299static void ui_browser__warn_lost_events(struct ui_browser *browser) 299static void ui_browser__warn_lost_events(struct ui_browser *browser)
@@ -305,64 +305,64 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
305 "Or reduce the sampling frequency."); 305 "Or reduce the sampling frequency.");
306} 306}
307 307
308static int hist_browser__run(struct hist_browser *self, const char *ev_name, 308static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
309 void(*timer)(void *arg), void *arg, int delay_secs) 309 void(*timer)(void *arg), void *arg, int delay_secs)
310{ 310{
311 int key; 311 int key;
312 char title[160]; 312 char title[160];
313 313
314 self->b.entries = &self->hists->entries; 314 browser->b.entries = &browser->hists->entries;
315 self->b.nr_entries = self->hists->nr_entries; 315 browser->b.nr_entries = browser->hists->nr_entries;
316 316
317 hist_browser__refresh_dimensions(self); 317 hist_browser__refresh_dimensions(browser);
318 hists__browser_title(self->hists, title, sizeof(title), ev_name); 318 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
319 319
320 if (ui_browser__show(&self->b, title, 320 if (ui_browser__show(&browser->b, title,
321 "Press '?' for help on key bindings") < 0) 321 "Press '?' for help on key bindings") < 0)
322 return -1; 322 return -1;
323 323
324 while (1) { 324 while (1) {
325 key = ui_browser__run(&self->b, delay_secs); 325 key = ui_browser__run(&browser->b, delay_secs);
326 326
327 switch (key) { 327 switch (key) {
328 case K_TIMER: 328 case K_TIMER:
329 timer(arg); 329 timer(arg);
330 ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); 330 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
331 331
332 if (self->hists->stats.nr_lost_warned != 332 if (browser->hists->stats.nr_lost_warned !=
333 self->hists->stats.nr_events[PERF_RECORD_LOST]) { 333 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
334 self->hists->stats.nr_lost_warned = 334 browser->hists->stats.nr_lost_warned =
335 self->hists->stats.nr_events[PERF_RECORD_LOST]; 335 browser->hists->stats.nr_events[PERF_RECORD_LOST];
336 ui_browser__warn_lost_events(&self->b); 336 ui_browser__warn_lost_events(&browser->b);
337 } 337 }
338 338
339 hists__browser_title(self->hists, title, sizeof(title), ev_name); 339 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
340 ui_browser__show_title(&self->b, title); 340 ui_browser__show_title(&browser->b, title);
341 continue; 341 continue;
342 case 'D': { /* Debug */ 342 case 'D': { /* Debug */
343 static int seq; 343 static int seq;
344 struct hist_entry *h = rb_entry(self->b.top, 344 struct hist_entry *h = rb_entry(browser->b.top,
345 struct hist_entry, rb_node); 345 struct hist_entry, rb_node);
346 ui_helpline__pop(); 346 ui_helpline__pop();
347 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 347 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
348 seq++, self->b.nr_entries, 348 seq++, browser->b.nr_entries,
349 self->hists->nr_entries, 349 browser->hists->nr_entries,
350 self->b.height, 350 browser->b.height,
351 self->b.index, 351 browser->b.index,
352 self->b.top_idx, 352 browser->b.top_idx,
353 h->row_offset, h->nr_rows); 353 h->row_offset, h->nr_rows);
354 } 354 }
355 break; 355 break;
356 case 'C': 356 case 'C':
357 /* Collapse the whole world. */ 357 /* Collapse the whole world. */
358 hist_browser__set_folding(self, false); 358 hist_browser__set_folding(browser, false);
359 break; 359 break;
360 case 'E': 360 case 'E':
361 /* Expand the whole world. */ 361 /* Expand the whole world. */
362 hist_browser__set_folding(self, true); 362 hist_browser__set_folding(browser, true);
363 break; 363 break;
364 case K_ENTER: 364 case K_ENTER:
365 if (hist_browser__toggle_fold(self)) 365 if (hist_browser__toggle_fold(browser))
366 break; 366 break;
367 /* fall thru */ 367 /* fall thru */
368 default: 368 default:
@@ -370,23 +370,23 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name,
370 } 370 }
371 } 371 }
372out: 372out:
373 ui_browser__hide(&self->b); 373 ui_browser__hide(&browser->b);
374 return key; 374 return key;
375} 375}
376 376
377static char *callchain_list__sym_name(struct callchain_list *self, 377static char *callchain_list__sym_name(struct callchain_list *cl,
378 char *bf, size_t bfsize) 378 char *bf, size_t bfsize)
379{ 379{
380 if (self->ms.sym) 380 if (cl->ms.sym)
381 return self->ms.sym->name; 381 return cl->ms.sym->name;
382 382
383 snprintf(bf, bfsize, "%#" PRIx64, self->ip); 383 snprintf(bf, bfsize, "%#" PRIx64, cl->ip);
384 return bf; 384 return bf;
385} 385}
386 386
387#define LEVEL_OFFSET_STEP 3 387#define LEVEL_OFFSET_STEP 3
388 388
389static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self, 389static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
390 struct callchain_node *chain_node, 390 struct callchain_node *chain_node,
391 u64 total, int level, 391 u64 total, int level,
392 unsigned short row, 392 unsigned short row,
@@ -444,21 +444,21 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
444 } 444 }
445 445
446 color = HE_COLORSET_NORMAL; 446 color = HE_COLORSET_NORMAL;
447 width = self->b.width - (offset + extra_offset + 2); 447 width = browser->b.width - (offset + extra_offset + 2);
448 if (ui_browser__is_current_entry(&self->b, row)) { 448 if (ui_browser__is_current_entry(&browser->b, row)) {
449 self->selection = &chain->ms; 449 browser->selection = &chain->ms;
450 color = HE_COLORSET_SELECTED; 450 color = HE_COLORSET_SELECTED;
451 *is_current_entry = true; 451 *is_current_entry = true;
452 } 452 }
453 453
454 ui_browser__set_color(&self->b, color); 454 ui_browser__set_color(&browser->b, color);
455 ui_browser__gotorc(&self->b, row, 0); 455 ui_browser__gotorc(&browser->b, row, 0);
456 slsmg_write_nstring(" ", offset + extra_offset); 456 slsmg_write_nstring(" ", offset + extra_offset);
457 slsmg_printf("%c ", folded_sign); 457 slsmg_printf("%c ", folded_sign);
458 slsmg_write_nstring(str, width); 458 slsmg_write_nstring(str, width);
459 free(alloc_str); 459 free(alloc_str);
460 460
461 if (++row == self->b.height) 461 if (++row == browser->b.height)
462 goto out; 462 goto out;
463do_next: 463do_next:
464 if (folded_sign == '+') 464 if (folded_sign == '+')
@@ -467,11 +467,11 @@ do_next:
467 467
468 if (folded_sign == '-') { 468 if (folded_sign == '-') {
469 const int new_level = level + (extra_offset ? 2 : 1); 469 const int new_level = level + (extra_offset ? 2 : 1);
470 row += hist_browser__show_callchain_node_rb_tree(self, child, new_total, 470 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
471 new_level, row, row_offset, 471 new_level, row, row_offset,
472 is_current_entry); 472 is_current_entry);
473 } 473 }
474 if (row == self->b.height) 474 if (row == browser->b.height)
475 goto out; 475 goto out;
476 node = next; 476 node = next;
477 } 477 }
@@ -479,7 +479,7 @@ out:
479 return row - first_row; 479 return row - first_row;
480} 480}
481 481
482static int hist_browser__show_callchain_node(struct hist_browser *self, 482static int hist_browser__show_callchain_node(struct hist_browser *browser,
483 struct callchain_node *node, 483 struct callchain_node *node,
484 int level, unsigned short row, 484 int level, unsigned short row,
485 off_t *row_offset, 485 off_t *row_offset,
@@ -488,7 +488,7 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
488 struct callchain_list *chain; 488 struct callchain_list *chain;
489 int first_row = row, 489 int first_row = row,
490 offset = level * LEVEL_OFFSET_STEP, 490 offset = level * LEVEL_OFFSET_STEP,
491 width = self->b.width - offset; 491 width = browser->b.width - offset;
492 char folded_sign = ' '; 492 char folded_sign = ' ';
493 493
494 list_for_each_entry(chain, &node->val, list) { 494 list_for_each_entry(chain, &node->val, list) {
@@ -503,26 +503,26 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
503 } 503 }
504 504
505 color = HE_COLORSET_NORMAL; 505 color = HE_COLORSET_NORMAL;
506 if (ui_browser__is_current_entry(&self->b, row)) { 506 if (ui_browser__is_current_entry(&browser->b, row)) {
507 self->selection = &chain->ms; 507 browser->selection = &chain->ms;
508 color = HE_COLORSET_SELECTED; 508 color = HE_COLORSET_SELECTED;
509 *is_current_entry = true; 509 *is_current_entry = true;
510 } 510 }
511 511
512 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); 512 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
513 ui_browser__gotorc(&self->b, row, 0); 513 ui_browser__gotorc(&browser->b, row, 0);
514 ui_browser__set_color(&self->b, color); 514 ui_browser__set_color(&browser->b, color);
515 slsmg_write_nstring(" ", offset); 515 slsmg_write_nstring(" ", offset);
516 slsmg_printf("%c ", folded_sign); 516 slsmg_printf("%c ", folded_sign);
517 slsmg_write_nstring(s, width - 2); 517 slsmg_write_nstring(s, width - 2);
518 518
519 if (++row == self->b.height) 519 if (++row == browser->b.height)
520 goto out; 520 goto out;
521 } 521 }
522 522
523 if (folded_sign == '-') 523 if (folded_sign == '-')
524 row += hist_browser__show_callchain_node_rb_tree(self, node, 524 row += hist_browser__show_callchain_node_rb_tree(browser, node,
525 self->hists->stats.total_period, 525 browser->hists->stats.total_period,
526 level + 1, row, 526 level + 1, row,
527 row_offset, 527 row_offset,
528 is_current_entry); 528 is_current_entry);
@@ -530,7 +530,7 @@ out:
530 return row - first_row; 530 return row - first_row;
531} 531}
532 532
533static int hist_browser__show_callchain(struct hist_browser *self, 533static int hist_browser__show_callchain(struct hist_browser *browser,
534 struct rb_root *chain, 534 struct rb_root *chain,
535 int level, unsigned short row, 535 int level, unsigned short row,
536 off_t *row_offset, 536 off_t *row_offset,
@@ -542,31 +542,31 @@ static int hist_browser__show_callchain(struct hist_browser *self,
542 for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 542 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
543 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 543 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
544 544
545 row += hist_browser__show_callchain_node(self, node, level, 545 row += hist_browser__show_callchain_node(browser, node, level,
546 row, row_offset, 546 row, row_offset,
547 is_current_entry); 547 is_current_entry);
548 if (row == self->b.height) 548 if (row == browser->b.height)
549 break; 549 break;
550 } 550 }
551 551
552 return row - first_row; 552 return row - first_row;
553} 553}
554 554
555static int hist_browser__show_entry(struct hist_browser *self, 555static int hist_browser__show_entry(struct hist_browser *browser,
556 struct hist_entry *entry, 556 struct hist_entry *entry,
557 unsigned short row) 557 unsigned short row)
558{ 558{
559 char s[256]; 559 char s[256];
560 double percent; 560 double percent;
561 int printed = 0; 561 int printed = 0;
562 int width = self->b.width - 6; /* The percentage */ 562 int width = browser->b.width - 6; /* The percentage */
563 char folded_sign = ' '; 563 char folded_sign = ' ';
564 bool current_entry = ui_browser__is_current_entry(&self->b, row); 564 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
565 off_t row_offset = entry->row_offset; 565 off_t row_offset = entry->row_offset;
566 566
567 if (current_entry) { 567 if (current_entry) {
568 self->he_selection = entry; 568 browser->he_selection = entry;
569 self->selection = &entry->ms; 569 browser->selection = &entry->ms;
570 } 570 }
571 571
572 if (symbol_conf.use_callchain) { 572 if (symbol_conf.use_callchain) {
@@ -575,11 +575,11 @@ static int hist_browser__show_entry(struct hist_browser *self,
575 } 575 }
576 576
577 if (row_offset == 0) { 577 if (row_offset == 0) {
578 hist_entry__snprintf(entry, s, sizeof(s), self->hists); 578 hist_entry__snprintf(entry, s, sizeof(s), browser->hists);
579 percent = (entry->period * 100.0) / self->hists->stats.total_period; 579 percent = (entry->period * 100.0) / browser->hists->stats.total_period;
580 580
581 ui_browser__set_percent_color(&self->b, percent, current_entry); 581 ui_browser__set_percent_color(&browser->b, percent, current_entry);
582 ui_browser__gotorc(&self->b, row, 0); 582 ui_browser__gotorc(&browser->b, row, 0);
583 if (symbol_conf.use_callchain) { 583 if (symbol_conf.use_callchain) {
584 slsmg_printf("%c ", folded_sign); 584 slsmg_printf("%c ", folded_sign);
585 width -= 2; 585 width -= 2;
@@ -588,11 +588,11 @@ static int hist_browser__show_entry(struct hist_browser *self,
588 slsmg_printf(" %5.2f%%", percent); 588 slsmg_printf(" %5.2f%%", percent);
589 589
590 /* The scroll bar isn't being used */ 590 /* The scroll bar isn't being used */
591 if (!self->b.navkeypressed) 591 if (!browser->b.navkeypressed)
592 width += 1; 592 width += 1;
593 593
594 if (!current_entry || !self->b.navkeypressed) 594 if (!current_entry || !browser->b.navkeypressed)
595 ui_browser__set_color(&self->b, HE_COLORSET_NORMAL); 595 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
596 596
597 if (symbol_conf.show_nr_samples) { 597 if (symbol_conf.show_nr_samples) {
598 slsmg_printf(" %11u", entry->nr_events); 598 slsmg_printf(" %11u", entry->nr_events);
@@ -610,12 +610,12 @@ static int hist_browser__show_entry(struct hist_browser *self,
610 } else 610 } else
611 --row_offset; 611 --row_offset;
612 612
613 if (folded_sign == '-' && row != self->b.height) { 613 if (folded_sign == '-' && row != browser->b.height) {
614 printed += hist_browser__show_callchain(self, &entry->sorted_chain, 614 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
615 1, row, &row_offset, 615 1, row, &row_offset,
616 &current_entry); 616 &current_entry);
617 if (current_entry) 617 if (current_entry)
618 self->he_selection = entry; 618 browser->he_selection = entry;
619 } 619 }
620 620
621 return printed; 621 return printed;
@@ -631,22 +631,22 @@ static void ui_browser__hists_init_top(struct ui_browser *browser)
631 } 631 }
632} 632}
633 633
634static unsigned int hist_browser__refresh(struct ui_browser *self) 634static unsigned int hist_browser__refresh(struct ui_browser *browser)
635{ 635{
636 unsigned row = 0; 636 unsigned row = 0;
637 struct rb_node *nd; 637 struct rb_node *nd;
638 struct hist_browser *hb = container_of(self, struct hist_browser, b); 638 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
639 639
640 ui_browser__hists_init_top(self); 640 ui_browser__hists_init_top(browser);
641 641
642 for (nd = self->top; nd; nd = rb_next(nd)) { 642 for (nd = browser->top; nd; nd = rb_next(nd)) {
643 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 643 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
644 644
645 if (h->filtered) 645 if (h->filtered)
646 continue; 646 continue;
647 647
648 row += hist_browser__show_entry(hb, h, row); 648 row += hist_browser__show_entry(hb, h, row);
649 if (row == self->height) 649 if (row == browser->height)
650 break; 650 break;
651 } 651 }
652 652
@@ -679,27 +679,27 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
679 return NULL; 679 return NULL;
680} 680}
681 681
682static void ui_browser__hists_seek(struct ui_browser *self, 682static void ui_browser__hists_seek(struct ui_browser *browser,
683 off_t offset, int whence) 683 off_t offset, int whence)
684{ 684{
685 struct hist_entry *h; 685 struct hist_entry *h;
686 struct rb_node *nd; 686 struct rb_node *nd;
687 bool first = true; 687 bool first = true;
688 688
689 if (self->nr_entries == 0) 689 if (browser->nr_entries == 0)
690 return; 690 return;
691 691
692 ui_browser__hists_init_top(self); 692 ui_browser__hists_init_top(browser);
693 693
694 switch (whence) { 694 switch (whence) {
695 case SEEK_SET: 695 case SEEK_SET:
696 nd = hists__filter_entries(rb_first(self->entries)); 696 nd = hists__filter_entries(rb_first(browser->entries));
697 break; 697 break;
698 case SEEK_CUR: 698 case SEEK_CUR:
699 nd = self->top; 699 nd = browser->top;
700 goto do_offset; 700 goto do_offset;
701 case SEEK_END: 701 case SEEK_END:
702 nd = hists__filter_prev_entries(rb_last(self->entries)); 702 nd = hists__filter_prev_entries(rb_last(browser->entries));
703 first = false; 703 first = false;
704 break; 704 break;
705 default: 705 default:
@@ -710,7 +710,7 @@ static void ui_browser__hists_seek(struct ui_browser *self,
710 * Moves not relative to the first visible entry invalidates its 710 * Moves not relative to the first visible entry invalidates its
711 * row_offset: 711 * row_offset:
712 */ 712 */
713 h = rb_entry(self->top, struct hist_entry, rb_node); 713 h = rb_entry(browser->top, struct hist_entry, rb_node);
714 h->row_offset = 0; 714 h->row_offset = 0;
715 715
716 /* 716 /*
@@ -738,7 +738,7 @@ do_offset:
738 } else { 738 } else {
739 h->row_offset += offset; 739 h->row_offset += offset;
740 offset = 0; 740 offset = 0;
741 self->top = nd; 741 browser->top = nd;
742 break; 742 break;
743 } 743 }
744 } 744 }
@@ -746,7 +746,7 @@ do_offset:
746 if (nd == NULL) 746 if (nd == NULL)
747 break; 747 break;
748 --offset; 748 --offset;
749 self->top = nd; 749 browser->top = nd;
750 } while (offset != 0); 750 } while (offset != 0);
751 } else if (offset < 0) { 751 } else if (offset < 0) {
752 while (1) { 752 while (1) {
@@ -759,7 +759,7 @@ do_offset:
759 } else { 759 } else {
760 h->row_offset += offset; 760 h->row_offset += offset;
761 offset = 0; 761 offset = 0;
762 self->top = nd; 762 browser->top = nd;
763 break; 763 break;
764 } 764 }
765 } else { 765 } else {
@@ -769,7 +769,7 @@ do_offset:
769 } else { 769 } else {
770 h->row_offset = h->nr_rows + offset; 770 h->row_offset = h->nr_rows + offset;
771 offset = 0; 771 offset = 0;
772 self->top = nd; 772 browser->top = nd;
773 break; 773 break;
774 } 774 }
775 } 775 }
@@ -779,7 +779,7 @@ do_offset:
779 if (nd == NULL) 779 if (nd == NULL)
780 break; 780 break;
781 ++offset; 781 ++offset;
782 self->top = nd; 782 browser->top = nd;
783 if (offset == 0) { 783 if (offset == 0) {
784 /* 784 /*
785 * Last unfiltered hist_entry, check if it is 785 * Last unfiltered hist_entry, check if it is
@@ -794,7 +794,7 @@ do_offset:
794 first = false; 794 first = false;
795 } 795 }
796 } else { 796 } else {
797 self->top = nd; 797 browser->top = nd;
798 h = rb_entry(nd, struct hist_entry, rb_node); 798 h = rb_entry(nd, struct hist_entry, rb_node);
799 h->row_offset = 0; 799 h->row_offset = 0;
800 } 800 }
@@ -802,52 +802,56 @@ do_offset:
802 802
803static struct hist_browser *hist_browser__new(struct hists *hists) 803static struct hist_browser *hist_browser__new(struct hists *hists)
804{ 804{
805 struct hist_browser *self = zalloc(sizeof(*self)); 805 struct hist_browser *browser = zalloc(sizeof(*browser));
806 806
807 if (self) { 807 if (browser) {
808 self->hists = hists; 808 browser->hists = hists;
809 self->b.refresh = hist_browser__refresh; 809 browser->b.refresh = hist_browser__refresh;
810 self->b.seek = ui_browser__hists_seek; 810 browser->b.seek = ui_browser__hists_seek;
811 self->b.use_navkeypressed = true; 811 browser->b.use_navkeypressed = true;
812 if (sort__branch_mode == 1) 812 if (sort__branch_mode == 1)
813 self->has_symbols = sort_sym_from.list.next != NULL; 813 browser->has_symbols = sort_sym_from.list.next != NULL;
814 else 814 else
815 self->has_symbols = sort_sym.list.next != NULL; 815 browser->has_symbols = sort_sym.list.next != NULL;
816 } 816 }
817 817
818 return self; 818 return browser;
819} 819}
820 820
821static void hist_browser__delete(struct hist_browser *self) 821static void hist_browser__delete(struct hist_browser *browser)
822{ 822{
823 free(self); 823 free(browser);
824} 824}
825 825
826static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self) 826static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
827{ 827{
828 return self->he_selection; 828 return browser->he_selection;
829} 829}
830 830
831static struct thread *hist_browser__selected_thread(struct hist_browser *self) 831static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
832{ 832{
833 return self->he_selection->thread; 833 return browser->he_selection->thread;
834} 834}
835 835
836static int hists__browser_title(struct hists *self, char *bf, size_t size, 836static int hists__browser_title(struct hists *hists, char *bf, size_t size,
837 const char *ev_name) 837 const char *ev_name)
838{ 838{
839 char unit; 839 char unit;
840 int printed; 840 int printed;
841 const struct dso *dso = self->dso_filter; 841 const struct dso *dso = hists->dso_filter;
842 const struct thread *thread = self->thread_filter; 842 const struct thread *thread = hists->thread_filter;
843 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 843 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
844 u64 nr_events = hists->stats.total_period;
845
846 nr_samples = convert_unit(nr_samples, &unit);
847 printed = scnprintf(bf, size,
848 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
849 nr_samples, unit, ev_name, nr_events);
844 850
845 nr_events = convert_unit(nr_events, &unit);
846 printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
847 851
848 if (self->uid_filter_str) 852 if (hists->uid_filter_str)
849 printed += snprintf(bf + printed, size - printed, 853 printed += snprintf(bf + printed, size - printed,
850 ", UID: %s", self->uid_filter_str); 854 ", UID: %s", hists->uid_filter_str);
851 if (thread) 855 if (thread)
852 printed += scnprintf(bf + printed, size - printed, 856 printed += scnprintf(bf + printed, size - printed,
853 ", Thread: %s(%d)", 857 ", Thread: %s(%d)",
@@ -875,8 +879,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
875 void(*timer)(void *arg), void *arg, 879 void(*timer)(void *arg), void *arg,
876 int delay_secs) 880 int delay_secs)
877{ 881{
878 struct hists *self = &evsel->hists; 882 struct hists *hists = &evsel->hists;
879 struct hist_browser *browser = hist_browser__new(self); 883 struct hist_browser *browser = hist_browser__new(hists);
880 struct branch_info *bi; 884 struct branch_info *bi;
881 struct pstack *fstack; 885 struct pstack *fstack;
882 char *options[16]; 886 char *options[16];
@@ -937,13 +941,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
937 goto zoom_dso; 941 goto zoom_dso;
938 case 't': 942 case 't':
939 goto zoom_thread; 943 goto zoom_thread;
940 case 's': 944 case '/':
941 if (ui_browser__input_window("Symbol to show", 945 if (ui_browser__input_window("Symbol to show",
942 "Please enter the name of symbol you want to see", 946 "Please enter the name of symbol you want to see",
943 buf, "ENTER: OK, ESC: Cancel", 947 buf, "ENTER: OK, ESC: Cancel",
944 delay_secs * 2) == K_ENTER) { 948 delay_secs * 2) == K_ENTER) {
945 self->symbol_filter_str = *buf ? buf : NULL; 949 hists->symbol_filter_str = *buf ? buf : NULL;
946 hists__filter_by_symbol(self); 950 hists__filter_by_symbol(hists);
947 hist_browser__reset(browser); 951 hist_browser__reset(browser);
948 } 952 }
949 continue; 953 continue;
@@ -965,7 +969,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
965 "E Expand all callchains\n" 969 "E Expand all callchains\n"
966 "d Zoom into current DSO\n" 970 "d Zoom into current DSO\n"
967 "t Zoom into current Thread\n" 971 "t Zoom into current Thread\n"
968 "s Filter symbol by name"); 972 "/ Filter symbol by name");
969 continue; 973 continue;
970 case K_ENTER: 974 case K_ENTER:
971 case K_RIGHT: 975 case K_RIGHT:
@@ -1124,7 +1128,7 @@ zoom_out_dso:
1124 sort_dso.elide = true; 1128 sort_dso.elide = true;
1125 pstack__push(fstack, &browser->hists->dso_filter); 1129 pstack__push(fstack, &browser->hists->dso_filter);
1126 } 1130 }
1127 hists__filter_by_dso(self); 1131 hists__filter_by_dso(hists);
1128 hist_browser__reset(browser); 1132 hist_browser__reset(browser);
1129 } else if (choice == zoom_thread) { 1133 } else if (choice == zoom_thread) {
1130zoom_thread: 1134zoom_thread:
@@ -1142,7 +1146,7 @@ zoom_out_thread:
1142 sort_thread.elide = true; 1146 sort_thread.elide = true;
1143 pstack__push(fstack, &browser->hists->thread_filter); 1147 pstack__push(fstack, &browser->hists->thread_filter);
1144 } 1148 }
1145 hists__filter_by_thread(self); 1149 hists__filter_by_thread(hists);
1146 hist_browser__reset(browser); 1150 hist_browser__reset(browser);
1147 } 1151 }
1148 } 1152 }
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index eca6575abfd0..98851d55a53e 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -5,9 +5,9 @@
5#include <sys/ttydefaults.h> 5#include <sys/ttydefaults.h>
6#include <string.h> 6#include <string.h>
7#include <linux/bitops.h> 7#include <linux/bitops.h>
8#include "../../util.h" 8#include "../../util/util.h"
9#include "../../debug.h" 9#include "../../util/debug.h"
10#include "../../symbol.h" 10#include "../../util/symbol.h"
11#include "../browser.h" 11#include "../browser.h"
12#include "../helpline.h" 12#include "../helpline.h"
13#include "map.h" 13#include "map.h"
diff --git a/tools/perf/util/ui/browsers/map.h b/tools/perf/ui/browsers/map.h
index df8581a43e17..df8581a43e17 100644
--- a/tools/perf/util/ui/browsers/map.h
+++ b/tools/perf/ui/browsers/map.h
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 258352a2356c..0656c381a89c 100644
--- a/tools/perf/util/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -9,24 +9,13 @@
9 9
10#define MAX_COLUMNS 32 10#define MAX_COLUMNS 32
11 11
12void perf_gtk_setup_browser(int argc, const char *argv[], 12static void perf_gtk__signal(int sig)
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{ 13{
25 psignal(sig, "perf"); 14 psignal(sig, "perf");
26 gtk_main_quit(); 15 gtk_main_quit();
27} 16}
28 17
29static void perf_gtk_resize_window(GtkWidget *window) 18static void perf_gtk__resize_window(GtkWidget *window)
30{ 19{
31 GdkRectangle rect; 20 GdkRectangle rect;
32 GdkScreen *screen; 21 GdkScreen *screen;
@@ -46,7 +35,7 @@ static void perf_gtk_resize_window(GtkWidget *window)
46 gtk_window_resize(GTK_WINDOW(window), width, height); 35 gtk_window_resize(GTK_WINDOW(window), width, height);
47} 36}
48 37
49static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists) 38static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
50{ 39{
51 GType col_types[MAX_COLUMNS]; 40 GType col_types[MAX_COLUMNS];
52 GtkCellRenderer *renderer; 41 GtkCellRenderer *renderer;
@@ -142,11 +131,11 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
142 GtkWidget *notebook; 131 GtkWidget *notebook;
143 GtkWidget *window; 132 GtkWidget *window;
144 133
145 signal(SIGSEGV, perf_gtk_signal); 134 signal(SIGSEGV, perf_gtk__signal);
146 signal(SIGFPE, perf_gtk_signal); 135 signal(SIGFPE, perf_gtk__signal);
147 signal(SIGINT, perf_gtk_signal); 136 signal(SIGINT, perf_gtk__signal);
148 signal(SIGQUIT, perf_gtk_signal); 137 signal(SIGQUIT, perf_gtk__signal);
149 signal(SIGTERM, perf_gtk_signal); 138 signal(SIGTERM, perf_gtk__signal);
150 139
151 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 140 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
152 141
@@ -168,7 +157,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
168 GTK_POLICY_AUTOMATIC, 157 GTK_POLICY_AUTOMATIC,
169 GTK_POLICY_AUTOMATIC); 158 GTK_POLICY_AUTOMATIC);
170 159
171 perf_gtk_show_hists(scrolled_window, hists); 160 perf_gtk__show_hists(scrolled_window, hists);
172 161
173 tab_label = gtk_label_new(evname); 162 tab_label = gtk_label_new(evname);
174 163
@@ -179,7 +168,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
179 168
180 gtk_widget_show_all(window); 169 gtk_widget_show_all(window);
181 170
182 perf_gtk_resize_window(window); 171 perf_gtk__resize_window(window);
183 172
184 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); 173 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
185 174
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 75177ee04032..75177ee04032 100644
--- a/tools/perf/util/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
new file mode 100644
index 000000000000..829529957766
--- /dev/null
+++ b/tools/perf/ui/gtk/setup.c
@@ -0,0 +1,12 @@
1#include "gtk.h"
2#include "../../util/cache.h"
3
4int perf_gtk__init(void)
5{
6 return gtk_init_check(NULL, NULL) ? 0 : -1;
7}
8
9void perf_gtk__exit(bool wait_for_ok __used)
10{
11 gtk_main_quit();
12}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/ui/helpline.c
index 2f950c2641c8..2f950c2641c8 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/ui/helpline.c
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/ui/helpline.h
index 7bab6b34e35e..7bab6b34e35e 100644
--- a/tools/perf/util/ui/helpline.h
+++ b/tools/perf/ui/helpline.h
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/ui/keysyms.h
index 809eca5707fa..809eca5707fa 100644
--- a/tools/perf/util/ui/keysyms.h
+++ b/tools/perf/ui/keysyms.h
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/ui/libslang.h
index 4d54b6450f5b..4d54b6450f5b 100644
--- a/tools/perf/util/ui/libslang.h
+++ b/tools/perf/ui/libslang.h
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/ui/progress.c
index 13aa64e50e11..13aa64e50e11 100644
--- a/tools/perf/util/ui/progress.c
+++ b/tools/perf/ui/progress.c
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/ui/progress.h
index d9c205b59aa1..d9c205b59aa1 100644
--- a/tools/perf/util/ui/progress.h
+++ b/tools/perf/ui/progress.h
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
new file mode 100644
index 000000000000..791fb15ce350
--- /dev/null
+++ b/tools/perf/ui/setup.c
@@ -0,0 +1,46 @@
1#include "../cache.h"
2#include "../debug.h"
3
4
5void setup_browser(bool fallback_to_pager)
6{
7 if (!isatty(1) || dump_trace)
8 use_browser = 0;
9
10 /* default to TUI */
11 if (use_browser < 0)
12 use_browser = 1;
13
14 switch (use_browser) {
15 case 2:
16 if (perf_gtk__init() == 0)
17 break;
18 /* fall through */
19 case 1:
20 use_browser = 1;
21 if (ui__init() == 0)
22 break;
23 /* fall through */
24 default:
25 use_browser = 0;
26 if (fallback_to_pager)
27 setup_pager();
28 break;
29 }
30}
31
32void exit_browser(bool wait_for_ok)
33{
34 switch (use_browser) {
35 case 2:
36 perf_gtk__exit(wait_for_ok);
37 break;
38
39 case 1:
40 ui__exit(wait_for_ok);
41 break;
42
43 default:
44 break;
45 }
46}
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/ui/tui/setup.c
index 85a69faa09aa..d33e943ac434 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -2,14 +2,14 @@
2#include <signal.h> 2#include <signal.h>
3#include <stdbool.h> 3#include <stdbool.h>
4 4
5#include "../cache.h" 5#include "../../util/cache.h"
6#include "../debug.h" 6#include "../../util/debug.h"
7#include "browser.h" 7#include "../browser.h"
8#include "helpline.h" 8#include "../helpline.h"
9#include "ui.h" 9#include "../ui.h"
10#include "util.h" 10#include "../util.h"
11#include "libslang.h" 11#include "../libslang.h"
12#include "keysyms.h" 12#include "../keysyms.h"
13 13
14pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; 14pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
15 15
@@ -93,45 +93,26 @@ static void newt_suspend(void *d __used)
93 newtResume(); 93 newtResume();
94} 94}
95 95
96static int ui__init(void)
97{
98 int err = SLkp_init();
99
100 if (err < 0)
101 goto out;
102
103 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
104out:
105 return err;
106}
107
108static void ui__exit(void)
109{
110 SLtt_set_cursor_visibility(1);
111 SLsmg_refresh();
112 SLsmg_reset_smg();
113 SLang_reset_tty();
114}
115
116static void ui__signal(int sig) 96static void ui__signal(int sig)
117{ 97{
118 ui__exit(); 98 ui__exit(false);
119 psignal(sig, "perf"); 99 psignal(sig, "perf");
120 exit(0); 100 exit(0);
121} 101}
122 102
123void setup_browser(bool fallback_to_pager) 103int ui__init(void)
124{ 104{
125 if (!isatty(1) || !use_browser || dump_trace) { 105 int err;
126 use_browser = 0;
127 if (fallback_to_pager)
128 setup_pager();
129 return;
130 }
131 106
132 use_browser = 1;
133 newtInit(); 107 newtInit();
134 ui__init(); 108 err = SLkp_init();
109 if (err < 0) {
110 pr_err("TUI initialization failed.\n");
111 goto out;
112 }
113
114 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
115
135 newtSetSuspendCallback(newt_suspend, NULL); 116 newtSetSuspendCallback(newt_suspend, NULL);
136 ui_helpline__init(); 117 ui_helpline__init();
137 ui_browser__init(); 118 ui_browser__init();
@@ -141,15 +122,19 @@ void setup_browser(bool fallback_to_pager)
141 signal(SIGINT, ui__signal); 122 signal(SIGINT, ui__signal);
142 signal(SIGQUIT, ui__signal); 123 signal(SIGQUIT, ui__signal);
143 signal(SIGTERM, ui__signal); 124 signal(SIGTERM, ui__signal);
125out:
126 return err;
144} 127}
145 128
146void exit_browser(bool wait_for_ok) 129void ui__exit(bool wait_for_ok)
147{ 130{
148 if (use_browser > 0) { 131 if (wait_for_ok)
149 if (wait_for_ok) 132 ui__question_window("Fatal Error",
150 ui__question_window("Fatal Error", 133 ui_helpline__last_msg,
151 ui_helpline__last_msg, 134 "Press any key...", 0);
152 "Press any key...", 0); 135
153 ui__exit(); 136 SLtt_set_cursor_visibility(1);
154 } 137 SLsmg_refresh();
138 SLsmg_reset_smg();
139 SLang_reset_tty();
155} 140}
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/ui/ui.h
index 7b67045479f6..7b67045479f6 100644
--- a/tools/perf/util/ui/ui.h
+++ b/tools/perf/ui/ui.h
diff --git a/tools/perf/util/ui/util.c b/tools/perf/ui/util.c
index ad4374a16bb0..ad4374a16bb0 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/ui/util.c
diff --git a/tools/perf/util/ui/util.h b/tools/perf/ui/util.h
index 2d1738bd71c8..2d1738bd71c8 100644
--- a/tools/perf/util/ui/util.h
+++ b/tools/perf/ui/util.h
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index ad73300f7bac..95264f304179 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -12,7 +12,7 @@ LF='
12# First check if there is a .git to get the version from git describe 12# First check if there is a .git to get the version from git describe
13# otherwise try to get the version from the kernel makefile 13# otherwise try to get the version from the kernel makefile
14if test -d ../../.git -o -f ../../.git && 14if test -d ../../.git -o -f ../../.git &&
15 VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && 15 VN=$(git describe --match 'v[0-9].[0-9]*' --abbrev=4 HEAD 2>/dev/null) &&
16 case "$VN" in 16 case "$VN" in
17 *$LF*) (exit 1) ;; 17 *$LF*) (exit 1) ;;
18 v[0-9]*) 18 v[0-9]*)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 08c6d138a655..8069dfb5ba77 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -18,6 +18,403 @@
18 18
19const char *disassembler_style; 19const char *disassembler_style;
20 20
21static struct ins *ins__find(const char *name);
22static int disasm_line__parse(char *line, char **namep, char **rawp);
23
24static void ins__delete(struct ins_operands *ops)
25{
26 free(ops->source.raw);
27 free(ops->source.name);
28 free(ops->target.raw);
29 free(ops->target.name);
30}
31
32static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
33 struct ins_operands *ops)
34{
35 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
36}
37
38int ins__scnprintf(struct ins *ins, char *bf, size_t size,
39 struct ins_operands *ops)
40{
41 if (ins->ops->scnprintf)
42 return ins->ops->scnprintf(ins, bf, size, ops);
43
44 return ins__raw_scnprintf(ins, bf, size, ops);
45}
46
47static int call__parse(struct ins_operands *ops)
48{
49 char *endptr, *tok, *name;
50
51 ops->target.addr = strtoull(ops->raw, &endptr, 16);
52
53 name = strchr(endptr, '<');
54 if (name == NULL)
55 goto indirect_call;
56
57 name++;
58
59 tok = strchr(name, '>');
60 if (tok == NULL)
61 return -1;
62
63 *tok = '\0';
64 ops->target.name = strdup(name);
65 *tok = '>';
66
67 return ops->target.name == NULL ? -1 : 0;
68
69indirect_call:
70 tok = strchr(endptr, '(');
71 if (tok != NULL) {
72 ops->target.addr = 0;
73 return 0;
74 }
75
76 tok = strchr(endptr, '*');
77 if (tok == NULL)
78 return -1;
79
80 ops->target.addr = strtoull(tok + 1, NULL, 16);
81 return 0;
82}
83
84static int call__scnprintf(struct ins *ins, char *bf, size_t size,
85 struct ins_operands *ops)
86{
87 if (ops->target.name)
88 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
89
90 if (ops->target.addr == 0)
91 return ins__raw_scnprintf(ins, bf, size, ops);
92
93 return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
94}
95
96static struct ins_ops call_ops = {
97 .parse = call__parse,
98 .scnprintf = call__scnprintf,
99};
100
101bool ins__is_call(const struct ins *ins)
102{
103 return ins->ops == &call_ops;
104}
105
106static int jump__parse(struct ins_operands *ops)
107{
108 const char *s = strchr(ops->raw, '+');
109
110 ops->target.addr = strtoll(ops->raw, NULL, 16);
111
112 if (s++ != NULL)
113 ops->target.offset = strtoll(s, NULL, 16);
114 else
115 ops->target.offset = UINT64_MAX;
116
117 return 0;
118}
119
120static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
121 struct ins_operands *ops)
122{
123 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
124}
125
126static struct ins_ops jump_ops = {
127 .parse = jump__parse,
128 .scnprintf = jump__scnprintf,
129};
130
131bool ins__is_jump(const struct ins *ins)
132{
133 return ins->ops == &jump_ops;
134}
135
136static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
137{
138 char *endptr, *name, *t;
139
140 if (strstr(raw, "(%rip)") == NULL)
141 return 0;
142
143 *addrp = strtoull(comment, &endptr, 16);
144 name = strchr(endptr, '<');
145 if (name == NULL)
146 return -1;
147
148 name++;
149
150 t = strchr(name, '>');
151 if (t == NULL)
152 return 0;
153
154 *t = '\0';
155 *namep = strdup(name);
156 *t = '>';
157
158 return 0;
159}
160
161static int lock__parse(struct ins_operands *ops)
162{
163 char *name;
164
165 ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
166 if (ops->locked.ops == NULL)
167 return 0;
168
169 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
170 goto out_free_ops;
171
172 ops->locked.ins = ins__find(name);
173 if (ops->locked.ins == NULL)
174 goto out_free_ops;
175
176 if (!ops->locked.ins->ops)
177 return 0;
178
179 if (ops->locked.ins->ops->parse)
180 ops->locked.ins->ops->parse(ops->locked.ops);
181
182 return 0;
183
184out_free_ops:
185 free(ops->locked.ops);
186 ops->locked.ops = NULL;
187 return 0;
188}
189
190static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
191 struct ins_operands *ops)
192{
193 int printed;
194
195 if (ops->locked.ins == NULL)
196 return ins__raw_scnprintf(ins, bf, size, ops);
197
198 printed = scnprintf(bf, size, "%-6.6s ", ins->name);
199 return printed + ins__scnprintf(ops->locked.ins, bf + printed,
200 size - printed, ops->locked.ops);
201}
202
203static void lock__delete(struct ins_operands *ops)
204{
205 free(ops->locked.ops);
206 free(ops->target.raw);
207 free(ops->target.name);
208}
209
210static struct ins_ops lock_ops = {
211 .free = lock__delete,
212 .parse = lock__parse,
213 .scnprintf = lock__scnprintf,
214};
215
216static int mov__parse(struct ins_operands *ops)
217{
218 char *s = strchr(ops->raw, ','), *target, *comment, prev;
219
220 if (s == NULL)
221 return -1;
222
223 *s = '\0';
224 ops->source.raw = strdup(ops->raw);
225 *s = ',';
226
227 if (ops->source.raw == NULL)
228 return -1;
229
230 target = ++s;
231
232 while (s[0] != '\0' && !isspace(s[0]))
233 ++s;
234 prev = *s;
235 *s = '\0';
236
237 ops->target.raw = strdup(target);
238 *s = prev;
239
240 if (ops->target.raw == NULL)
241 goto out_free_source;
242
243 comment = strchr(s, '#');
244 if (comment == NULL)
245 return 0;
246
247 while (comment[0] != '\0' && isspace(comment[0]))
248 ++comment;
249
250 comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
251 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
252
253 return 0;
254
255out_free_source:
256 free(ops->source.raw);
257 ops->source.raw = NULL;
258 return -1;
259}
260
261static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
262 struct ins_operands *ops)
263{
264 return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
265 ops->source.name ?: ops->source.raw,
266 ops->target.name ?: ops->target.raw);
267}
268
269static struct ins_ops mov_ops = {
270 .parse = mov__parse,
271 .scnprintf = mov__scnprintf,
272};
273
274static int dec__parse(struct ins_operands *ops)
275{
276 char *target, *comment, *s, prev;
277
278 target = s = ops->raw;
279
280 while (s[0] != '\0' && !isspace(s[0]))
281 ++s;
282 prev = *s;
283 *s = '\0';
284
285 ops->target.raw = strdup(target);
286 *s = prev;
287
288 if (ops->target.raw == NULL)
289 return -1;
290
291 comment = strchr(s, '#');
292 if (comment == NULL)
293 return 0;
294
295 while (comment[0] != '\0' && isspace(comment[0]))
296 ++comment;
297
298 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
299
300 return 0;
301}
302
303static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
304 struct ins_operands *ops)
305{
306 return scnprintf(bf, size, "%-6.6s %s", ins->name,
307 ops->target.name ?: ops->target.raw);
308}
309
310static struct ins_ops dec_ops = {
311 .parse = dec__parse,
312 .scnprintf = dec__scnprintf,
313};
314
315static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
316 struct ins_operands *ops __used)
317{
318 return scnprintf(bf, size, "%-6.6s", "nop");
319}
320
321static struct ins_ops nop_ops = {
322 .scnprintf = nop__scnprintf,
323};
324
325/*
326 * Must be sorted by name!
327 */
328static struct ins instructions[] = {
329 { .name = "add", .ops = &mov_ops, },
330 { .name = "addl", .ops = &mov_ops, },
331 { .name = "addq", .ops = &mov_ops, },
332 { .name = "addw", .ops = &mov_ops, },
333 { .name = "and", .ops = &mov_ops, },
334 { .name = "bts", .ops = &mov_ops, },
335 { .name = "call", .ops = &call_ops, },
336 { .name = "callq", .ops = &call_ops, },
337 { .name = "cmp", .ops = &mov_ops, },
338 { .name = "cmpb", .ops = &mov_ops, },
339 { .name = "cmpl", .ops = &mov_ops, },
340 { .name = "cmpq", .ops = &mov_ops, },
341 { .name = "cmpw", .ops = &mov_ops, },
342 { .name = "cmpxch", .ops = &mov_ops, },
343 { .name = "dec", .ops = &dec_ops, },
344 { .name = "decl", .ops = &dec_ops, },
345 { .name = "imul", .ops = &mov_ops, },
346 { .name = "inc", .ops = &dec_ops, },
347 { .name = "incl", .ops = &dec_ops, },
348 { .name = "ja", .ops = &jump_ops, },
349 { .name = "jae", .ops = &jump_ops, },
350 { .name = "jb", .ops = &jump_ops, },
351 { .name = "jbe", .ops = &jump_ops, },
352 { .name = "jc", .ops = &jump_ops, },
353 { .name = "jcxz", .ops = &jump_ops, },
354 { .name = "je", .ops = &jump_ops, },
355 { .name = "jecxz", .ops = &jump_ops, },
356 { .name = "jg", .ops = &jump_ops, },
357 { .name = "jge", .ops = &jump_ops, },
358 { .name = "jl", .ops = &jump_ops, },
359 { .name = "jle", .ops = &jump_ops, },
360 { .name = "jmp", .ops = &jump_ops, },
361 { .name = "jmpq", .ops = &jump_ops, },
362 { .name = "jna", .ops = &jump_ops, },
363 { .name = "jnae", .ops = &jump_ops, },
364 { .name = "jnb", .ops = &jump_ops, },
365 { .name = "jnbe", .ops = &jump_ops, },
366 { .name = "jnc", .ops = &jump_ops, },
367 { .name = "jne", .ops = &jump_ops, },
368 { .name = "jng", .ops = &jump_ops, },
369 { .name = "jnge", .ops = &jump_ops, },
370 { .name = "jnl", .ops = &jump_ops, },
371 { .name = "jnle", .ops = &jump_ops, },
372 { .name = "jno", .ops = &jump_ops, },
373 { .name = "jnp", .ops = &jump_ops, },
374 { .name = "jns", .ops = &jump_ops, },
375 { .name = "jnz", .ops = &jump_ops, },
376 { .name = "jo", .ops = &jump_ops, },
377 { .name = "jp", .ops = &jump_ops, },
378 { .name = "jpe", .ops = &jump_ops, },
379 { .name = "jpo", .ops = &jump_ops, },
380 { .name = "jrcxz", .ops = &jump_ops, },
381 { .name = "js", .ops = &jump_ops, },
382 { .name = "jz", .ops = &jump_ops, },
383 { .name = "lea", .ops = &mov_ops, },
384 { .name = "lock", .ops = &lock_ops, },
385 { .name = "mov", .ops = &mov_ops, },
386 { .name = "movb", .ops = &mov_ops, },
387 { .name = "movdqa",.ops = &mov_ops, },
388 { .name = "movl", .ops = &mov_ops, },
389 { .name = "movq", .ops = &mov_ops, },
390 { .name = "movslq", .ops = &mov_ops, },
391 { .name = "movzbl", .ops = &mov_ops, },
392 { .name = "movzwl", .ops = &mov_ops, },
393 { .name = "nop", .ops = &nop_ops, },
394 { .name = "nopl", .ops = &nop_ops, },
395 { .name = "nopw", .ops = &nop_ops, },
396 { .name = "or", .ops = &mov_ops, },
397 { .name = "orl", .ops = &mov_ops, },
398 { .name = "test", .ops = &mov_ops, },
399 { .name = "testb", .ops = &mov_ops, },
400 { .name = "testl", .ops = &mov_ops, },
401 { .name = "xadd", .ops = &mov_ops, },
402};
403
404static int ins__cmp(const void *name, const void *insp)
405{
406 const struct ins *ins = insp;
407
408 return strcmp(name, ins->name);
409}
410
411static struct ins *ins__find(const char *name)
412{
413 const int nmemb = ARRAY_SIZE(instructions);
414
415 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
416}
417
21int symbol__annotate_init(struct map *map __used, struct symbol *sym) 418int symbol__annotate_init(struct map *map __used, struct symbol *sym)
22{ 419{
23 struct annotation *notes = symbol__annotation(sym); 420 struct annotation *notes = symbol__annotation(sym);
@@ -28,7 +425,7 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
28int symbol__alloc_hist(struct symbol *sym) 425int symbol__alloc_hist(struct symbol *sym)
29{ 426{
30 struct annotation *notes = symbol__annotation(sym); 427 struct annotation *notes = symbol__annotation(sym);
31 const size_t size = sym->end - sym->start + 1; 428 const size_t size = symbol__size(sym);
32 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); 429 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
33 430
34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 431 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
@@ -78,31 +475,110 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
78 return 0; 475 return 0;
79} 476}
80 477
81static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) 478static void disasm_line__init_ins(struct disasm_line *dl)
479{
480 dl->ins = ins__find(dl->name);
481
482 if (dl->ins == NULL)
483 return;
484
485 if (!dl->ins->ops)
486 return;
487
488 if (dl->ins->ops->parse)
489 dl->ins->ops->parse(&dl->ops);
490}
491
492static int disasm_line__parse(char *line, char **namep, char **rawp)
493{
494 char *name = line, tmp;
495
496 while (isspace(name[0]))
497 ++name;
498
499 if (name[0] == '\0')
500 return -1;
501
502 *rawp = name + 1;
503
504 while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
505 ++*rawp;
506
507 tmp = (*rawp)[0];
508 (*rawp)[0] = '\0';
509 *namep = strdup(name);
510
511 if (*namep == NULL)
512 goto out_free_name;
513
514 (*rawp)[0] = tmp;
515
516 if ((*rawp)[0] != '\0') {
517 (*rawp)++;
518 while (isspace((*rawp)[0]))
519 ++(*rawp);
520 }
521
522 return 0;
523
524out_free_name:
525 free(*namep);
526 *namep = NULL;
527 return -1;
528}
529
530static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
82{ 531{
83 struct objdump_line *self = malloc(sizeof(*self) + privsize); 532 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
84 533
85 if (self != NULL) { 534 if (dl != NULL) {
86 self->offset = offset; 535 dl->offset = offset;
87 self->line = line; 536 dl->line = strdup(line);
537 if (dl->line == NULL)
538 goto out_delete;
539
540 if (offset != -1) {
541 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
542 goto out_free_line;
543
544 disasm_line__init_ins(dl);
545 }
88 } 546 }
89 547
90 return self; 548 return dl;
549
550out_free_line:
551 free(dl->line);
552out_delete:
553 free(dl);
554 return NULL;
555}
556
557void disasm_line__free(struct disasm_line *dl)
558{
559 free(dl->line);
560 free(dl->name);
561 if (dl->ins && dl->ins->ops->free)
562 dl->ins->ops->free(&dl->ops);
563 else
564 ins__delete(&dl->ops);
565 free(dl);
91} 566}
92 567
93void objdump_line__free(struct objdump_line *self) 568int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
94{ 569{
95 free(self->line); 570 if (raw || !dl->ins)
96 free(self); 571 return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);
572
573 return ins__scnprintf(dl->ins, bf, size, &dl->ops);
97} 574}
98 575
99static void objdump__add_line(struct list_head *head, struct objdump_line *line) 576static void disasm__add(struct list_head *head, struct disasm_line *line)
100{ 577{
101 list_add_tail(&line->node, head); 578 list_add_tail(&line->node, head);
102} 579}
103 580
104struct objdump_line *objdump__get_next_ip_line(struct list_head *head, 581struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
105 struct objdump_line *pos)
106{ 582{
107 list_for_each_entry_continue(pos, head, node) 583 list_for_each_entry_continue(pos, head, node)
108 if (pos->offset >= 0) 584 if (pos->offset >= 0)
@@ -111,15 +587,14 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
111 return NULL; 587 return NULL;
112} 588}
113 589
114static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, 590static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
115 int evidx, u64 len, int min_pcnt, 591 int evidx, u64 len, int min_pcnt, int printed,
116 int printed, int max_lines, 592 int max_lines, struct disasm_line *queue)
117 struct objdump_line *queue)
118{ 593{
119 static const char *prev_line; 594 static const char *prev_line;
120 static const char *prev_color; 595 static const char *prev_color;
121 596
122 if (oline->offset != -1) { 597 if (dl->offset != -1) {
123 const char *path = NULL; 598 const char *path = NULL;
124 unsigned int hits = 0; 599 unsigned int hits = 0;
125 double percent = 0.0; 600 double percent = 0.0;
@@ -127,10 +602,11 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
127 struct annotation *notes = symbol__annotation(sym); 602 struct annotation *notes = symbol__annotation(sym);
128 struct source_line *src_line = notes->src->lines; 603 struct source_line *src_line = notes->src->lines;
129 struct sym_hist *h = annotation__histogram(notes, evidx); 604 struct sym_hist *h = annotation__histogram(notes, evidx);
130 s64 offset = oline->offset; 605 s64 offset = dl->offset;
131 struct objdump_line *next; 606 const u64 addr = start + offset;
607 struct disasm_line *next;
132 608
133 next = objdump__get_next_ip_line(&notes->src->source, oline); 609 next = disasm__get_next_ip_line(&notes->src->source, dl);
134 610
135 while (offset < (s64)len && 611 while (offset < (s64)len &&
136 (next == NULL || offset < next->offset)) { 612 (next == NULL || offset < next->offset)) {
@@ -155,9 +631,9 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
155 631
156 if (queue != NULL) { 632 if (queue != NULL) {
157 list_for_each_entry_from(queue, &notes->src->source, node) { 633 list_for_each_entry_from(queue, &notes->src->source, node) {
158 if (queue == oline) 634 if (queue == dl)
159 break; 635 break;
160 objdump_line__print(queue, sym, evidx, len, 636 disasm_line__print(queue, sym, start, evidx, len,
161 0, 0, 1, NULL); 637 0, 0, 1, NULL);
162 } 638 }
163 } 639 }
@@ -180,17 +656,18 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
180 656
181 color_fprintf(stdout, color, " %7.2f", percent); 657 color_fprintf(stdout, color, " %7.2f", percent);
182 printf(" : "); 658 printf(" : ");
183 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line); 659 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr);
660 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
184 } else if (max_lines && printed >= max_lines) 661 } else if (max_lines && printed >= max_lines)
185 return 1; 662 return 1;
186 else { 663 else {
187 if (queue) 664 if (queue)
188 return -1; 665 return -1;
189 666
190 if (!*oline->line) 667 if (!*dl->line)
191 printf(" :\n"); 668 printf(" :\n");
192 else 669 else
193 printf(" : %s\n", oline->line); 670 printf(" : %s\n", dl->line);
194 } 671 }
195 672
196 return 0; 673 return 0;
@@ -200,8 +677,8 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
200 FILE *file, size_t privsize) 677 FILE *file, size_t privsize)
201{ 678{
202 struct annotation *notes = symbol__annotation(sym); 679 struct annotation *notes = symbol__annotation(sym);
203 struct objdump_line *objdump_line; 680 struct disasm_line *dl;
204 char *line = NULL, *tmp, *tmp2, *c; 681 char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
205 size_t line_len; 682 size_t line_len;
206 s64 line_ip, offset = -1; 683 s64 line_ip, offset = -1;
207 684
@@ -219,6 +696,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
219 *c = 0; 696 *c = 0;
220 697
221 line_ip = -1; 698 line_ip = -1;
699 parsed_line = line;
222 700
223 /* 701 /*
224 * Strip leading spaces: 702 * Strip leading spaces:
@@ -246,14 +724,17 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
246 offset = line_ip - start; 724 offset = line_ip - start;
247 if (offset < 0 || (u64)line_ip > end) 725 if (offset < 0 || (u64)line_ip > end)
248 offset = -1; 726 offset = -1;
727 else
728 parsed_line = tmp2 + 1;
249 } 729 }
250 730
251 objdump_line = objdump_line__new(offset, line, privsize); 731 dl = disasm_line__new(offset, parsed_line, privsize);
252 if (objdump_line == NULL) { 732 free(line);
253 free(line); 733
734 if (dl == NULL)
254 return -1; 735 return -1;
255 } 736
256 objdump__add_line(&notes->src->source, objdump_line); 737 disasm__add(&notes->src->source, dl);
257 738
258 return 0; 739 return 0;
259} 740}
@@ -476,7 +957,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
476{ 957{
477 struct annotation *notes = symbol__annotation(sym); 958 struct annotation *notes = symbol__annotation(sym);
478 struct sym_hist *h = annotation__histogram(notes, evidx); 959 struct sym_hist *h = annotation__histogram(notes, evidx);
479 u64 len = sym->end - sym->start, offset; 960 u64 len = symbol__size(sym), offset;
480 961
481 for (offset = 0; offset < len; ++offset) 962 for (offset = 0; offset < len; ++offset)
482 if (h->addr[offset] != 0) 963 if (h->addr[offset] != 0)
@@ -492,7 +973,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
492 struct dso *dso = map->dso; 973 struct dso *dso = map->dso;
493 const char *filename = dso->long_name, *d_filename; 974 const char *filename = dso->long_name, *d_filename;
494 struct annotation *notes = symbol__annotation(sym); 975 struct annotation *notes = symbol__annotation(sym);
495 struct objdump_line *pos, *queue = NULL; 976 struct disasm_line *pos, *queue = NULL;
977 u64 start = map__rip_2objdump(map, sym->start);
496 int printed = 2, queue_len = 0; 978 int printed = 2, queue_len = 0;
497 int more = 0; 979 int more = 0;
498 u64 len; 980 u64 len;
@@ -502,7 +984,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
502 else 984 else
503 d_filename = basename(filename); 985 d_filename = basename(filename);
504 986
505 len = sym->end - sym->start; 987 len = symbol__size(sym);
506 988
507 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 989 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
508 printf("------------------------------------------------\n"); 990 printf("------------------------------------------------\n");
@@ -516,8 +998,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
516 queue_len = 0; 998 queue_len = 0;
517 } 999 }
518 1000
519 switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, 1001 switch (disasm_line__print(pos, sym, start, evidx, len,
520 printed, max_lines, queue)) { 1002 min_pcnt, printed, max_lines,
1003 queue)) {
521 case 0: 1004 case 0:
522 ++printed; 1005 ++printed;
523 if (context) { 1006 if (context) {
@@ -561,7 +1044,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
561{ 1044{
562 struct annotation *notes = symbol__annotation(sym); 1045 struct annotation *notes = symbol__annotation(sym);
563 struct sym_hist *h = annotation__histogram(notes, evidx); 1046 struct sym_hist *h = annotation__histogram(notes, evidx);
564 int len = sym->end - sym->start, offset; 1047 int len = symbol__size(sym), offset;
565 1048
566 h->sum = 0; 1049 h->sum = 0;
567 for (offset = 0; offset < len; ++offset) { 1050 for (offset = 0; offset < len; ++offset) {
@@ -570,14 +1053,42 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
570 } 1053 }
571} 1054}
572 1055
573void objdump_line_list__purge(struct list_head *head) 1056void disasm__purge(struct list_head *head)
574{ 1057{
575 struct objdump_line *pos, *n; 1058 struct disasm_line *pos, *n;
576 1059
577 list_for_each_entry_safe(pos, n, head, node) { 1060 list_for_each_entry_safe(pos, n, head, node) {
578 list_del(&pos->node); 1061 list_del(&pos->node);
579 objdump_line__free(pos); 1062 disasm_line__free(pos);
1063 }
1064}
1065
1066static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
1067{
1068 size_t printed;
1069
1070 if (dl->offset == -1)
1071 return fprintf(fp, "%s\n", dl->line);
1072
1073 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
1074
1075 if (dl->ops.raw[0] != '\0') {
1076 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
1077 dl->ops.raw);
580 } 1078 }
1079
1080 return printed + fprintf(fp, "\n");
1081}
1082
1083size_t disasm__fprintf(struct list_head *head, FILE *fp)
1084{
1085 struct disasm_line *pos;
1086 size_t printed = 0;
1087
1088 list_for_each_entry(pos, head, node)
1089 printed += disasm_line__fprintf(pos, fp);
1090
1091 return printed;
581} 1092}
582 1093
583int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 1094int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
@@ -592,7 +1103,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
592 if (symbol__annotate(sym, map, 0) < 0) 1103 if (symbol__annotate(sym, map, 0) < 0)
593 return -1; 1104 return -1;
594 1105
595 len = sym->end - sym->start; 1106 len = symbol__size(sym);
596 1107
597 if (print_lines) { 1108 if (print_lines) {
598 symbol__get_source_line(sym, map, evidx, &source_line, 1109 symbol__get_source_line(sym, map, evidx, &source_line,
@@ -605,7 +1116,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
605 if (print_lines) 1116 if (print_lines)
606 symbol__free_source_line(sym, len); 1117 symbol__free_source_line(sym, len);
607 1118
608 objdump_line_list__purge(&symbol__annotation(sym)->src->source); 1119 disasm__purge(&symbol__annotation(sym)->src->source);
609 1120
610 return 0; 1121 return 0;
611} 1122}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index efa5dc82bfae..78a5692dd718 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -2,20 +2,69 @@
2#define __PERF_ANNOTATE_H 2#define __PERF_ANNOTATE_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h>
5#include "types.h" 6#include "types.h"
6#include "symbol.h" 7#include "symbol.h"
7#include <linux/list.h> 8#include <linux/list.h>
8#include <linux/rbtree.h> 9#include <linux/rbtree.h>
9 10
10struct objdump_line { 11struct ins;
11 struct list_head node; 12
12 s64 offset; 13struct ins_operands {
13 char *line; 14 char *raw;
15 struct {
16 char *raw;
17 char *name;
18 u64 addr;
19 u64 offset;
20 } target;
21 union {
22 struct {
23 char *raw;
24 char *name;
25 u64 addr;
26 } source;
27 struct {
28 struct ins *ins;
29 struct ins_operands *ops;
30 } locked;
31 };
14}; 32};
15 33
16void objdump_line__free(struct objdump_line *self); 34struct ins_ops {
17struct objdump_line *objdump__get_next_ip_line(struct list_head *head, 35 void (*free)(struct ins_operands *ops);
18 struct objdump_line *pos); 36 int (*parse)(struct ins_operands *ops);
37 int (*scnprintf)(struct ins *ins, char *bf, size_t size,
38 struct ins_operands *ops);
39};
40
41struct ins {
42 const char *name;
43 struct ins_ops *ops;
44};
45
46bool ins__is_jump(const struct ins *ins);
47bool ins__is_call(const struct ins *ins);
48int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
49
50struct disasm_line {
51 struct list_head node;
52 s64 offset;
53 char *line;
54 char *name;
55 struct ins *ins;
56 struct ins_operands ops;
57};
58
59static inline bool disasm_line__has_offset(const struct disasm_line *dl)
60{
61 return dl->ops.target.offset != UINT64_MAX;
62}
63
64void disasm_line__free(struct disasm_line *dl);
65struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
66int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
67size_t disasm__fprintf(struct list_head *head, FILE *fp);
19 68
20struct sym_hist { 69struct sym_hist {
21 u64 sum; 70 u64 sum;
@@ -32,7 +81,7 @@ struct source_line {
32 * 81 *
33 * @histogram: Array of addr hit histograms per event being monitored 82 * @histogram: Array of addr hit histograms per event being monitored
34 * @lines: If 'print_lines' is specified, per source code line percentages 83 * @lines: If 'print_lines' is specified, per source code line percentages
35 * @source: source parsed from objdump -dS 84 * @source: source parsed from a disassembler like objdump -dS
36 * 85 *
37 * lines is allocated, percentages calculated and all sorted by percentage 86 * lines is allocated, percentages calculated and all sorted by percentage
38 * when the annotation is about to be presented, so the percentages are for 87 * when the annotation is about to be presented, so the percentages are for
@@ -82,7 +131,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
82 int context); 131 int context);
83void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 132void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
84void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 133void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
85void objdump_line_list__purge(struct list_head *head); 134void disasm__purge(struct list_head *head);
86 135
87int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 136int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
88 bool print_lines, bool full_paths, int min_pcnt, 137 bool print_lines, bool full_paths, int min_pcnt,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index dff9c7a725f4..fd9a5944b627 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -65,6 +65,8 @@ struct perf_tool build_id__mark_dso_hit_ops = {
65 .mmap = perf_event__process_mmap, 65 .mmap = perf_event__process_mmap,
66 .fork = perf_event__process_task, 66 .fork = perf_event__process_task,
67 .exit = perf_event__exit_del_thread, 67 .exit = perf_event__exit_del_thread,
68 .attr = perf_event__process_attr,
69 .build_id = perf_event__process_build_id,
68}; 70};
69 71
70char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 72char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 8dd224df3e54..cff18c617d13 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -33,7 +33,7 @@ extern int pager_use_color;
33 33
34extern int use_browser; 34extern int use_browser;
35 35
36#ifdef NO_NEWT_SUPPORT 36#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
37static inline void setup_browser(bool fallback_to_pager) 37static inline void setup_browser(bool fallback_to_pager)
38{ 38{
39 if (fallback_to_pager) 39 if (fallback_to_pager)
@@ -43,19 +43,29 @@ static inline void exit_browser(bool wait_for_ok __used) {}
43#else 43#else
44void setup_browser(bool fallback_to_pager); 44void setup_browser(bool fallback_to_pager);
45void exit_browser(bool wait_for_ok); 45void exit_browser(bool wait_for_ok);
46
47#ifdef NO_NEWT_SUPPORT
48static inline int ui__init(void)
49{
50 return -1;
51}
52static inline void ui__exit(bool wait_for_ok __used) {}
53#else
54int ui__init(void);
55void ui__exit(bool wait_for_ok);
46#endif 56#endif
47 57
48#ifdef NO_GTK2_SUPPORT 58#ifdef NO_GTK2_SUPPORT
49static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager) 59static inline int perf_gtk__init(void)
50{ 60{
51 if (fallback_to_pager) 61 return -1;
52 setup_pager();
53} 62}
54static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {} 63static inline void perf_gtk__exit(bool wait_for_ok __used) {}
55#else 64#else
56void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager); 65int perf_gtk__init(void);
57void perf_gtk_exit_browser(bool wait_for_ok); 66void perf_gtk__exit(bool wait_for_ok);
58#endif 67#endif
68#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
59 69
60char *alias_lookup(const char *alias); 70char *alias_lookup(const char *alias);
61int split_cmdline(char *cmdline, const char ***argv); 71int split_cmdline(char *cmdline, const char ***argv);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 9f7106a8d9a4..3a6bff47614f 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -18,6 +18,8 @@
18#include "util.h" 18#include "util.h"
19#include "callchain.h" 19#include "callchain.h"
20 20
21__thread struct callchain_cursor callchain_cursor;
22
21bool ip_callchain__valid(struct ip_callchain *chain, 23bool ip_callchain__valid(struct ip_callchain *chain,
22 const union perf_event *event) 24 const union perf_event *event)
23{ 25{
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 7f9c0f1ae3a9..3bdb407f9cd9 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -76,6 +76,8 @@ struct callchain_cursor {
76 struct callchain_cursor_node *curr; 76 struct callchain_cursor_node *curr;
77}; 77};
78 78
79extern __thread struct callchain_cursor callchain_cursor;
80
79static inline void callchain_init(struct callchain_root *root) 81static inline void callchain_init(struct callchain_root *root)
80{ 82{
81 INIT_LIST_HEAD(&root->node.siblings); 83 INIT_LIST_HEAD(&root->node.siblings);
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 0deac6a14b65..6faa3a18bfbd 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -120,7 +120,7 @@ static char *parse_value(void)
120 120
121static inline int iskeychar(int c) 121static inline int iskeychar(int c)
122{ 122{
123 return isalnum(c) || c == '-'; 123 return isalnum(c) || c == '-' || c == '_';
124} 124}
125 125
126static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 126static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 26817daa2961..efb1fce259a4 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -11,6 +11,7 @@
11#include "event.h" 11#include "event.h"
12#include "debug.h" 12#include "debug.h"
13#include "util.h" 13#include "util.h"
14#include "target.h"
14 15
15int verbose; 16int verbose;
16bool dump_trace = false, quiet = false; 17bool dump_trace = false, quiet = false;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index f2ce88d04f54..6bebe7f0a20c 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -26,7 +26,7 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,
26#else 26#else
27extern char ui_helpline__last_msg[]; 27extern char ui_helpline__last_msg[];
28int ui_helpline__show_help(const char *format, va_list ap); 28int ui_helpline__show_help(const char *format, va_list ap);
29#include "ui/progress.h" 29#include "../ui/progress.h"
30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
31#endif 31#endif
32 32
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 1986d8051bd1..7400fb3fc50c 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -11,6 +11,7 @@
11#include <poll.h> 11#include <poll.h>
12#include "cpumap.h" 12#include "cpumap.h"
13#include "thread_map.h" 13#include "thread_map.h"
14#include "target.h"
14#include "evlist.h" 15#include "evlist.h"
15#include "evsel.h" 16#include "evsel.h"
16#include <unistd.h> 17#include <unistd.h>
@@ -158,6 +159,17 @@ out_delete_partial_list:
158 return -1; 159 return -1;
159} 160}
160 161
162int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
163 struct perf_event_attr *attrs, size_t nr_attrs)
164{
165 size_t i;
166
167 for (i = 0; i < nr_attrs; i++)
168 event_attr_init(attrs + i);
169
170 return perf_evlist__add_attrs(evlist, attrs, nr_attrs);
171}
172
161static int trace_event__id(const char *evname) 173static int trace_event__id(const char *evname)
162{ 174{
163 char *filename, *colon; 175 char *filename, *colon;
@@ -262,7 +274,8 @@ void perf_evlist__disable(struct perf_evlist *evlist)
262 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 274 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
263 list_for_each_entry(pos, &evlist->entries, node) { 275 list_for_each_entry(pos, &evlist->entries, node) {
264 for (thread = 0; thread < evlist->threads->nr; thread++) 276 for (thread = 0; thread < evlist->threads->nr; thread++)
265 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE); 277 ioctl(FD(pos, cpu, thread),
278 PERF_EVENT_IOC_DISABLE, 0);
266 } 279 }
267 } 280 }
268} 281}
@@ -275,7 +288,8 @@ void perf_evlist__enable(struct perf_evlist *evlist)
275 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 288 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
276 list_for_each_entry(pos, &evlist->entries, node) { 289 list_for_each_entry(pos, &evlist->entries, node) {
277 for (thread = 0; thread < evlist->threads->nr; thread++) 290 for (thread = 0; thread < evlist->threads->nr; thread++)
278 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE); 291 ioctl(FD(pos, cpu, thread),
292 PERF_EVENT_IOC_ENABLE, 0);
279 } 293 }
280 } 294 }
281} 295}
@@ -599,18 +613,21 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
599 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 613 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
600} 614}
601 615
602int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, 616int perf_evlist__create_maps(struct perf_evlist *evlist,
603 const char *target_tid, uid_t uid, const char *cpu_list) 617 struct perf_target *target)
604{ 618{
605 evlist->threads = thread_map__new_str(target_pid, target_tid, uid); 619 evlist->threads = thread_map__new_str(target->pid, target->tid,
620 target->uid);
606 621
607 if (evlist->threads == NULL) 622 if (evlist->threads == NULL)
608 return -1; 623 return -1;
609 624
610 if (uid != UINT_MAX || (cpu_list == NULL && target_tid)) 625 if (perf_target__has_task(target))
626 evlist->cpus = cpu_map__dummy_new();
627 else if (!perf_target__has_cpu(target) && !target->uses_mmap)
611 evlist->cpus = cpu_map__dummy_new(); 628 evlist->cpus = cpu_map__dummy_new();
612 else 629 else
613 evlist->cpus = cpu_map__new(cpu_list); 630 evlist->cpus = cpu_map__new(target->cpu_list);
614 631
615 if (evlist->cpus == NULL) 632 if (evlist->cpus == NULL)
616 goto out_delete_threads; 633 goto out_delete_threads;
@@ -827,7 +844,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
827 exit(-1); 844 exit(-1);
828 } 845 }
829 846
830 if (!opts->system_wide && !opts->target_tid && !opts->target_pid) 847 if (perf_target__none(&opts->target))
831 evlist->threads->map[0] = evlist->workload.pid; 848 evlist->threads->map[0] = evlist->workload.pid;
832 849
833 close(child_ready_pipe[1]); 850 close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 21f1c9e57f13..989bee9624c2 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -54,6 +54,8 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
54int perf_evlist__add_default(struct perf_evlist *evlist); 54int perf_evlist__add_default(struct perf_evlist *evlist);
55int perf_evlist__add_attrs(struct perf_evlist *evlist, 55int perf_evlist__add_attrs(struct perf_evlist *evlist,
56 struct perf_event_attr *attrs, size_t nr_attrs); 56 struct perf_event_attr *attrs, size_t nr_attrs);
57int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
58 struct perf_event_attr *attrs, size_t nr_attrs);
57int perf_evlist__add_tracepoints(struct perf_evlist *evlist, 59int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
58 const char *tracepoints[], size_t nr_tracepoints); 60 const char *tracepoints[], size_t nr_tracepoints);
59int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, 61int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
@@ -62,6 +64,8 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
62 64
63#define perf_evlist__add_attrs_array(evlist, array) \ 65#define perf_evlist__add_attrs_array(evlist, array) \
64 perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) 66 perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array))
67#define perf_evlist__add_default_attrs(evlist, array) \
68 __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))
65 69
66#define perf_evlist__add_tracepoints_array(evlist, array) \ 70#define perf_evlist__add_tracepoints_array(evlist, array) \
67 perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) 71 perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array))
@@ -106,8 +110,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
106 evlist->threads = threads; 110 evlist->threads = threads;
107} 111}
108 112
109int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, 113int perf_evlist__create_maps(struct perf_evlist *evlist,
110 const char *tid, uid_t uid, const char *cpu_list); 114 struct perf_target *target);
111void perf_evlist__delete_maps(struct perf_evlist *evlist); 115void perf_evlist__delete_maps(struct perf_evlist *evlist);
112int perf_evlist__set_filters(struct perf_evlist *evlist); 116int perf_evlist__set_filters(struct perf_evlist *evlist);
113 117
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8c13dbcb84b9..9f6cebd798ee 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -14,6 +14,8 @@
14#include "util.h" 14#include "util.h"
15#include "cpumap.h" 15#include "cpumap.h"
16#include "thread_map.h" 16#include "thread_map.h"
17#include "target.h"
18#include "../../include/linux/perf_event.h"
17 19
18#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 20#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
19#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) 21#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
@@ -63,12 +65,102 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
63 return evsel; 65 return evsel;
64} 66}
65 67
68static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
69 "cycles",
70 "instructions",
71 "cache-references",
72 "cache-misses",
73 "branches",
74 "branch-misses",
75 "bus-cycles",
76 "stalled-cycles-frontend",
77 "stalled-cycles-backend",
78 "ref-cycles",
79};
80
81const char *__perf_evsel__hw_name(u64 config)
82{
83 if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
84 return perf_evsel__hw_names[config];
85
86 return "unknown-hardware";
87}
88
89static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
90{
91 int colon = 0;
92 struct perf_event_attr *attr = &evsel->attr;
93 int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(attr->config));
94 bool exclude_guest_default = false;
95
96#define MOD_PRINT(context, mod) do { \
97 if (!attr->exclude_##context) { \
98 if (!colon) colon = r++; \
99 r += scnprintf(bf + r, size - r, "%c", mod); \
100 } } while(0)
101
102 if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv) {
103 MOD_PRINT(kernel, 'k');
104 MOD_PRINT(user, 'u');
105 MOD_PRINT(hv, 'h');
106 exclude_guest_default = true;
107 }
108
109 if (attr->precise_ip) {
110 if (!colon)
111 colon = r++;
112 r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp");
113 exclude_guest_default = true;
114 }
115
116 if (attr->exclude_host || attr->exclude_guest == exclude_guest_default) {
117 MOD_PRINT(host, 'H');
118 MOD_PRINT(guest, 'G');
119 }
120#undef MOD_PRINT
121 if (colon)
122 bf[colon] = ':';
123 return r;
124}
125
126int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
127{
128 int ret;
129
130 switch (evsel->attr.type) {
131 case PERF_TYPE_RAW:
132 ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
133 break;
134
135 case PERF_TYPE_HARDWARE:
136 ret = perf_evsel__hw_name(evsel, bf, size);
137 break;
138 default:
139 /*
140 * FIXME
141 *
142 * This is the minimal perf_evsel__name so that we can
143 * reconstruct event names taking into account event modifiers.
144 *
145 * The old event_name uses it now for raw anr hw events, so that
146 * we don't drag all the parsing stuff into the python binding.
147 *
148 * On the next devel cycle the rest of the event naming will be
149 * brought here.
150 */
151 return 0;
152 }
153
154 return ret;
155}
156
66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, 157void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
67 struct perf_evsel *first) 158 struct perf_evsel *first)
68{ 159{
69 struct perf_event_attr *attr = &evsel->attr; 160 struct perf_event_attr *attr = &evsel->attr;
70 int track = !evsel->idx; /* only the first counter needs these */ 161 int track = !evsel->idx; /* only the first counter needs these */
71 162
163 attr->disabled = 1;
72 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 164 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
73 attr->inherit = !opts->no_inherit; 165 attr->inherit = !opts->no_inherit;
74 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 166 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -106,15 +198,15 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
106 if (opts->call_graph) 198 if (opts->call_graph)
107 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 199 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
108 200
109 if (opts->system_wide) 201 if (perf_target__has_cpu(&opts->target))
110 attr->sample_type |= PERF_SAMPLE_CPU; 202 attr->sample_type |= PERF_SAMPLE_CPU;
111 203
112 if (opts->period) 204 if (opts->period)
113 attr->sample_type |= PERF_SAMPLE_PERIOD; 205 attr->sample_type |= PERF_SAMPLE_PERIOD;
114 206
115 if (!opts->sample_id_all_missing && 207 if (!opts->sample_id_all_missing &&
116 (opts->sample_time || opts->system_wide || 208 (opts->sample_time || !opts->no_inherit ||
117 !opts->no_inherit || opts->cpu_list)) 209 perf_target__has_cpu(&opts->target)))
118 attr->sample_type |= PERF_SAMPLE_TIME; 210 attr->sample_type |= PERF_SAMPLE_TIME;
119 211
120 if (opts->raw_samples) { 212 if (opts->raw_samples) {
@@ -135,9 +227,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
135 attr->mmap = track; 227 attr->mmap = track;
136 attr->comm = track; 228 attr->comm = track;
137 229
138 if (!opts->target_pid && !opts->target_tid && !opts->system_wide && 230 if (perf_target__none(&opts->target) &&
139 (!opts->group || evsel == first)) { 231 (!opts->group || evsel == first)) {
140 attr->disabled = 1;
141 attr->enable_on_exec = 1; 232 attr->enable_on_exec = 1;
142 } 233 }
143} 234}
@@ -403,16 +494,24 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel,
403} 494}
404 495
405static int perf_event__parse_id_sample(const union perf_event *event, u64 type, 496static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
406 struct perf_sample *sample) 497 struct perf_sample *sample,
498 bool swapped)
407{ 499{
408 const u64 *array = event->sample.array; 500 const u64 *array = event->sample.array;
501 union u64_swap u;
409 502
410 array += ((event->header.size - 503 array += ((event->header.size -
411 sizeof(event->header)) / sizeof(u64)) - 1; 504 sizeof(event->header)) / sizeof(u64)) - 1;
412 505
413 if (type & PERF_SAMPLE_CPU) { 506 if (type & PERF_SAMPLE_CPU) {
414 u32 *p = (u32 *)array; 507 u.val64 = *array;
415 sample->cpu = *p; 508 if (swapped) {
509 /* undo swap of u64, then swap on individual u32s */
510 u.val64 = bswap_64(u.val64);
511 u.val32[0] = bswap_32(u.val32[0]);
512 }
513
514 sample->cpu = u.val32[0];
416 array--; 515 array--;
417 } 516 }
418 517
@@ -432,9 +531,16 @@ static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
432 } 531 }
433 532
434 if (type & PERF_SAMPLE_TID) { 533 if (type & PERF_SAMPLE_TID) {
435 u32 *p = (u32 *)array; 534 u.val64 = *array;
436 sample->pid = p[0]; 535 if (swapped) {
437 sample->tid = p[1]; 536 /* undo swap of u64, then swap on individual u32s */
537 u.val64 = bswap_64(u.val64);
538 u.val32[0] = bswap_32(u.val32[0]);
539 u.val32[1] = bswap_32(u.val32[1]);
540 }
541
542 sample->pid = u.val32[0];
543 sample->tid = u.val32[1];
438 } 544 }
439 545
440 return 0; 546 return 0;
@@ -461,10 +567,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
461 * used for cross-endian analysis. See git commit 65014ab3 567 * used for cross-endian analysis. See git commit 65014ab3
462 * for why this goofiness is needed. 568 * for why this goofiness is needed.
463 */ 569 */
464 union { 570 union u64_swap u;
465 u64 val64;
466 u32 val32[2];
467 } u;
468 571
469 memset(data, 0, sizeof(*data)); 572 memset(data, 0, sizeof(*data));
470 data->cpu = data->pid = data->tid = -1; 573 data->cpu = data->pid = data->tid = -1;
@@ -474,7 +577,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
474 if (event->header.type != PERF_RECORD_SAMPLE) { 577 if (event->header.type != PERF_RECORD_SAMPLE) {
475 if (!sample_id_all) 578 if (!sample_id_all)
476 return 0; 579 return 0;
477 return perf_event__parse_id_sample(event, type, data); 580 return perf_event__parse_id_sample(event, type, data, swapped);
478 } 581 }
479 582
480 array = event->sample.array; 583 array = event->sample.array;
@@ -607,10 +710,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
607 * used for cross-endian analysis. See git commit 65014ab3 710 * used for cross-endian analysis. See git commit 65014ab3
608 * for why this goofiness is needed. 711 * for why this goofiness is needed.
609 */ 712 */
610 union { 713 union u64_swap u;
611 u64 val64;
612 u32 val32[2];
613 } u;
614 714
615 array = event->sample.array; 715 array = event->sample.array;
616 716
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3d6b3e4cb66b..4ba8b564e6f4 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -83,6 +83,9 @@ void 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 struct perf_evsel *first);
85 85
86const char* __perf_evsel__hw_name(u64 config);
87int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size);
88
86int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 89int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
87int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 90int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
88int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 91int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4c7c2d73251f..e909d43cf542 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -31,21 +31,16 @@ static const char **header_argv;
31 31
32int perf_header__push_event(u64 id, const char *name) 32int perf_header__push_event(u64 id, const char *name)
33{ 33{
34 struct perf_trace_event_type *nevents;
35
34 if (strlen(name) > MAX_EVENT_NAME) 36 if (strlen(name) > MAX_EVENT_NAME)
35 pr_warning("Event %s will be truncated\n", name); 37 pr_warning("Event %s will be truncated\n", name);
36 38
37 if (!events) { 39 nevents = realloc(events, (event_count + 1) * sizeof(*events));
38 events = malloc(sizeof(struct perf_trace_event_type)); 40 if (nevents == NULL)
39 if (events == NULL) 41 return -ENOMEM;
40 return -ENOMEM; 42 events = nevents;
41 } else {
42 struct perf_trace_event_type *nevents;
43 43
44 nevents = realloc(events, (event_count + 1) * sizeof(*events));
45 if (nevents == NULL)
46 return -ENOMEM;
47 events = nevents;
48 }
49 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 44 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
50 events[event_count].event_id = id; 45 events[event_count].event_id = id;
51 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 46 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
@@ -296,7 +291,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
296 if (mkdir_p(filename, 0755)) 291 if (mkdir_p(filename, 0755))
297 goto out_free; 292 goto out_free;
298 293
299 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id); 294 snprintf(filename + len, size - len, "/%s", sbuild_id);
300 295
301 if (access(filename, F_OK)) { 296 if (access(filename, F_OK)) {
302 if (is_kallsyms) { 297 if (is_kallsyms) {
@@ -442,7 +437,7 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with
442 return ret; 437 return ret;
443} 438}
444 439
445static int write_trace_info(int fd, struct perf_header *h __used, 440static int write_tracing_data(int fd, struct perf_header *h __used,
446 struct perf_evlist *evlist) 441 struct perf_evlist *evlist)
447{ 442{
448 return read_tracing_data(fd, &evlist->entries); 443 return read_tracing_data(fd, &evlist->entries);
@@ -1477,7 +1472,7 @@ out:
1477 return err; 1472 return err;
1478} 1473}
1479 1474
1480static int process_trace_info(struct perf_file_section *section __unused, 1475static int process_tracing_data(struct perf_file_section *section __unused,
1481 struct perf_header *ph __unused, 1476 struct perf_header *ph __unused,
1482 int feat __unused, int fd) 1477 int feat __unused, int fd)
1483{ 1478{
@@ -1513,11 +1508,11 @@ struct feature_ops {
1513 .full_only = true } 1508 .full_only = true }
1514 1509
1515/* feature_ops not implemented: */ 1510/* feature_ops not implemented: */
1516#define print_trace_info NULL 1511#define print_tracing_data NULL
1517#define print_build_id NULL 1512#define print_build_id NULL
1518 1513
1519static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { 1514static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1520 FEAT_OPP(HEADER_TRACE_INFO, trace_info), 1515 FEAT_OPP(HEADER_TRACING_DATA, tracing_data),
1521 FEAT_OPP(HEADER_BUILD_ID, build_id), 1516 FEAT_OPP(HEADER_BUILD_ID, build_id),
1522 FEAT_OPA(HEADER_HOSTNAME, hostname), 1517 FEAT_OPA(HEADER_HOSTNAME, hostname),
1523 FEAT_OPA(HEADER_OSRELEASE, osrelease), 1518 FEAT_OPA(HEADER_OSRELEASE, osrelease),
@@ -1947,7 +1942,6 @@ int perf_file_header__read(struct perf_file_header *header,
1947 else 1942 else
1948 return -1; 1943 return -1;
1949 } else if (ph->needs_swap) { 1944 } else if (ph->needs_swap) {
1950 unsigned int i;
1951 /* 1945 /*
1952 * feature bitmap is declared as an array of unsigned longs -- 1946 * feature bitmap is declared as an array of unsigned longs --
1953 * not good since its size can differ between the host that 1947 * not good since its size can differ between the host that
@@ -1963,14 +1957,17 @@ int perf_file_header__read(struct perf_file_header *header,
1963 * file), punt and fallback to the original behavior -- 1957 * file), punt and fallback to the original behavior --
1964 * clearing all feature bits and setting buildid. 1958 * clearing all feature bits and setting buildid.
1965 */ 1959 */
1966 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) 1960 mem_bswap_64(&header->adds_features,
1967 header->adds_features[i] = bswap_64(header->adds_features[i]); 1961 BITS_TO_U64(HEADER_FEAT_BITS));
1968 1962
1969 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { 1963 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
1970 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) { 1964 /* unswap as u64 */
1971 header->adds_features[i] = bswap_64(header->adds_features[i]); 1965 mem_bswap_64(&header->adds_features,
1972 header->adds_features[i] = bswap_32(header->adds_features[i]); 1966 BITS_TO_U64(HEADER_FEAT_BITS));
1973 } 1967
1968 /* unswap as u32 */
1969 mem_bswap_32(&header->adds_features,
1970 BITS_TO_U32(HEADER_FEAT_BITS));
1974 } 1971 }
1975 1972
1976 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { 1973 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
@@ -2096,6 +2093,35 @@ static int read_attr(int fd, struct perf_header *ph,
2096 return ret <= 0 ? -1 : 0; 2093 return ret <= 0 ? -1 : 0;
2097} 2094}
2098 2095
2096static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel)
2097{
2098 struct event_format *event = trace_find_event(evsel->attr.config);
2099 char bf[128];
2100
2101 if (event == NULL)
2102 return -1;
2103
2104 snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name);
2105 evsel->name = strdup(bf);
2106 if (event->name == NULL)
2107 return -1;
2108
2109 return 0;
2110}
2111
2112static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist)
2113{
2114 struct perf_evsel *pos;
2115
2116 list_for_each_entry(pos, &evlist->entries, node) {
2117 if (pos->attr.type == PERF_TYPE_TRACEPOINT &&
2118 perf_evsel__set_tracepoint_name(pos))
2119 return -1;
2120 }
2121
2122 return 0;
2123}
2124
2099int perf_session__read_header(struct perf_session *session, int fd) 2125int perf_session__read_header(struct perf_session *session, int fd)
2100{ 2126{
2101 struct perf_header *header = &session->header; 2127 struct perf_header *header = &session->header;
@@ -2177,6 +2203,9 @@ int perf_session__read_header(struct perf_session *session, int fd)
2177 2203
2178 lseek(fd, header->data_offset, SEEK_SET); 2204 lseek(fd, header->data_offset, SEEK_SET);
2179 2205
2206 if (perf_evlist__set_tracepoint_names(session->evlist))
2207 goto out_delete_evlist;
2208
2180 header->frozen = 1; 2209 header->frozen = 1;
2181 return 0; 2210 return 0;
2182out_errno: 2211out_errno:
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 21a6be09c129..2d42b3e1826f 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -12,7 +12,7 @@
12enum { 12enum {
13 HEADER_RESERVED = 0, /* always cleared */ 13 HEADER_RESERVED = 0, /* always cleared */
14 HEADER_FIRST_FEATURE = 1, 14 HEADER_FIRST_FEATURE = 1,
15 HEADER_TRACE_INFO = 1, 15 HEADER_TRACING_DATA = 1,
16 HEADER_BUILD_ID, 16 HEADER_BUILD_ID,
17 17
18 HEADER_HOSTNAME, 18 HEADER_HOSTNAME,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 9f6d630d5316..514e2a4b367d 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -378,7 +378,7 @@ void hist_entry__free(struct hist_entry *he)
378 * collapse the histogram 378 * collapse the histogram
379 */ 379 */
380 380
381static bool hists__collapse_insert_entry(struct hists *hists, 381static bool hists__collapse_insert_entry(struct hists *hists __used,
382 struct rb_root *root, 382 struct rb_root *root,
383 struct hist_entry *he) 383 struct hist_entry *he)
384{ 384{
@@ -397,8 +397,9 @@ static bool hists__collapse_insert_entry(struct hists *hists,
397 iter->period += he->period; 397 iter->period += he->period;
398 iter->nr_events += he->nr_events; 398 iter->nr_events += he->nr_events;
399 if (symbol_conf.use_callchain) { 399 if (symbol_conf.use_callchain) {
400 callchain_cursor_reset(&hists->callchain_cursor); 400 callchain_cursor_reset(&callchain_cursor);
401 callchain_merge(&hists->callchain_cursor, iter->callchain, 401 callchain_merge(&callchain_cursor,
402 iter->callchain,
402 he->callchain); 403 he->callchain);
403 } 404 }
404 hist_entry__free(he); 405 hist_entry__free(he);
@@ -599,7 +600,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
599 if (chain->ms.sym) 600 if (chain->ms.sym)
600 ret += fprintf(fp, "%s\n", chain->ms.sym->name); 601 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
601 else 602 else
602 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip); 603 ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
603 604
604 return ret; 605 return ret;
605} 606}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 2cae9df40e04..34bb556d6219 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -67,8 +67,6 @@ struct hists {
67 struct events_stats stats; 67 struct events_stats stats;
68 u64 event_stream; 68 u64 event_stream;
69 u16 col_len[HISTC_NR_COLS]; 69 u16 col_len[HISTC_NR_COLS];
70 /* Best would be to reuse the session callchain cursor */
71 struct callchain_cursor callchain_cursor;
72}; 70};
73 71
74struct hist_entry *__hists__add_entry(struct hists *self, 72struct hist_entry *__hists__add_entry(struct hists *self,
@@ -138,7 +136,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
138#define K_LEFT -1 136#define K_LEFT -1
139#define K_RIGHT -2 137#define K_RIGHT -2
140#else 138#else
141#include "ui/keysyms.h" 139#include "../ui/keysyms.h"
142int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 140int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
143 void(*timer)(void *arg), void *arg, int delay_secs); 141 void(*timer)(void *arg), void *arg, int delay_secs);
144 142
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index f1584833bd22..587a230d2075 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -8,6 +8,8 @@
8#define BITS_PER_LONG __WORDSIZE 8#define BITS_PER_LONG __WORDSIZE
9#define BITS_PER_BYTE 8 9#define BITS_PER_BYTE 8
10#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 10#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
11#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
12#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
11 13
12#define for_each_set_bit(bit, addr, size) \ 14#define for_each_set_bit(bit, addr, size) \
13 for ((bit) = find_first_bit((addr), (size)); \ 15 for ((bit) = find_first_bit((addr), (size)); \
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
index 1915de20dcac..3322b8446e89 100644
--- a/tools/perf/util/pager.c
+++ b/tools/perf/util/pager.c
@@ -57,6 +57,10 @@ void setup_pager(void)
57 } 57 }
58 if (!pager) 58 if (!pager)
59 pager = getenv("PAGER"); 59 pager = getenv("PAGER");
60 if (!pager) {
61 if (!access("/usr/bin/pager", X_OK))
62 pager = "/usr/bin/pager";
63 }
60 if (!pager) 64 if (!pager)
61 pager = "less"; 65 pager = "less";
62 else if (!*pager || !strcmp(pager, "cat")) 66 else if (!*pager || !strcmp(pager, "cat"))
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
new file mode 100644
index 000000000000..76b98e2a587d
--- /dev/null
+++ b/tools/perf/util/parse-events-test.c
@@ -0,0 +1,625 @@
1
2#include "parse-events.h"
3#include "evsel.h"
4#include "evlist.h"
5#include "sysfs.h"
6#include "../../../include/linux/hw_breakpoint.h"
7
8#define TEST_ASSERT_VAL(text, cond) \
9do { \
10 if (!(cond)) { \
11 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
12 return -1; \
13 } \
14} while (0)
15
16static int test__checkevent_tracepoint(struct perf_evlist *evlist)
17{
18 struct perf_evsel *evsel = list_entry(evlist->entries.next,
19 struct perf_evsel, node);
20
21 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
22 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
23 TEST_ASSERT_VAL("wrong sample_type",
24 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
25 evsel->attr.sample_type);
26 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
27 return 0;
28}
29
30static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
31{
32 struct perf_evsel *evsel;
33
34 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
35
36 list_for_each_entry(evsel, &evlist->entries, node) {
37 TEST_ASSERT_VAL("wrong type",
38 PERF_TYPE_TRACEPOINT == evsel->attr.type);
39 TEST_ASSERT_VAL("wrong sample_type",
40 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
41 == evsel->attr.sample_type);
42 TEST_ASSERT_VAL("wrong sample_period",
43 1 == evsel->attr.sample_period);
44 }
45 return 0;
46}
47
48static int test__checkevent_raw(struct perf_evlist *evlist)
49{
50 struct perf_evsel *evsel = list_entry(evlist->entries.next,
51 struct perf_evsel, node);
52
53 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
54 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
55 TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
56 return 0;
57}
58
59static int test__checkevent_numeric(struct perf_evlist *evlist)
60{
61 struct perf_evsel *evsel = list_entry(evlist->entries.next,
62 struct perf_evsel, node);
63
64 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
65 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
66 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
67 return 0;
68}
69
70static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
71{
72 struct perf_evsel *evsel = list_entry(evlist->entries.next,
73 struct perf_evsel, node);
74
75 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
76 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
77 TEST_ASSERT_VAL("wrong config",
78 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
79 return 0;
80}
81
82static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
83{
84 struct perf_evsel *evsel = list_entry(evlist->entries.next,
85 struct perf_evsel, node);
86
87 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
88 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
89 TEST_ASSERT_VAL("wrong config",
90 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
91 TEST_ASSERT_VAL("wrong period",
92 100000 == evsel->attr.sample_period);
93 TEST_ASSERT_VAL("wrong config1",
94 0 == evsel->attr.config1);
95 TEST_ASSERT_VAL("wrong config2",
96 1 == evsel->attr.config2);
97 return 0;
98}
99
100static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
101{
102 struct perf_evsel *evsel = list_entry(evlist->entries.next,
103 struct perf_evsel, node);
104
105 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
106 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
107 TEST_ASSERT_VAL("wrong config",
108 PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
109 return 0;
110}
111
112static int test__checkevent_genhw(struct perf_evlist *evlist)
113{
114 struct perf_evsel *evsel = list_entry(evlist->entries.next,
115 struct perf_evsel, node);
116
117 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
118 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
119 TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
120 return 0;
121}
122
123static int test__checkevent_breakpoint(struct perf_evlist *evlist)
124{
125 struct perf_evsel *evsel = list_entry(evlist->entries.next,
126 struct perf_evsel, node);
127
128 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
129 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
130 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
131 TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
132 evsel->attr.bp_type);
133 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
134 evsel->attr.bp_len);
135 return 0;
136}
137
138static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
139{
140 struct perf_evsel *evsel = list_entry(evlist->entries.next,
141 struct perf_evsel, node);
142
143 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
144 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
145 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
146 TEST_ASSERT_VAL("wrong bp_type",
147 HW_BREAKPOINT_X == evsel->attr.bp_type);
148 TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
149 return 0;
150}
151
152static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
153{
154 struct perf_evsel *evsel = list_entry(evlist->entries.next,
155 struct perf_evsel, node);
156
157 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
158 TEST_ASSERT_VAL("wrong type",
159 PERF_TYPE_BREAKPOINT == evsel->attr.type);
160 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
161 TEST_ASSERT_VAL("wrong bp_type",
162 HW_BREAKPOINT_R == evsel->attr.bp_type);
163 TEST_ASSERT_VAL("wrong bp_len",
164 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
165 return 0;
166}
167
168static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
169{
170 struct perf_evsel *evsel = list_entry(evlist->entries.next,
171 struct perf_evsel, node);
172
173 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
174 TEST_ASSERT_VAL("wrong type",
175 PERF_TYPE_BREAKPOINT == evsel->attr.type);
176 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
177 TEST_ASSERT_VAL("wrong bp_type",
178 HW_BREAKPOINT_W == evsel->attr.bp_type);
179 TEST_ASSERT_VAL("wrong bp_len",
180 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
181 return 0;
182}
183
184static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
185{
186 struct perf_evsel *evsel = list_entry(evlist->entries.next,
187 struct perf_evsel, node);
188
189 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
190 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
191 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
192 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
193
194 return test__checkevent_tracepoint(evlist);
195}
196
197static int
198test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
199{
200 struct perf_evsel *evsel;
201
202 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
203
204 list_for_each_entry(evsel, &evlist->entries, node) {
205 TEST_ASSERT_VAL("wrong exclude_user",
206 !evsel->attr.exclude_user);
207 TEST_ASSERT_VAL("wrong exclude_kernel",
208 evsel->attr.exclude_kernel);
209 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
210 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
211 }
212
213 return test__checkevent_tracepoint_multi(evlist);
214}
215
216static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
217{
218 struct perf_evsel *evsel = list_entry(evlist->entries.next,
219 struct perf_evsel, node);
220
221 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
222 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
223 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
224 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
225
226 return test__checkevent_raw(evlist);
227}
228
229static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
230{
231 struct perf_evsel *evsel = list_entry(evlist->entries.next,
232 struct perf_evsel, node);
233
234 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
235 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
236 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
237 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
238
239 return test__checkevent_numeric(evlist);
240}
241
242static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
243{
244 struct perf_evsel *evsel = list_entry(evlist->entries.next,
245 struct perf_evsel, node);
246
247 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
248 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
249 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
250 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
251
252 return test__checkevent_symbolic_name(evlist);
253}
254
255static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
256{
257 struct perf_evsel *evsel = list_entry(evlist->entries.next,
258 struct perf_evsel, node);
259
260 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
261 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
262
263 return test__checkevent_symbolic_name(evlist);
264}
265
266static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
267{
268 struct perf_evsel *evsel = list_entry(evlist->entries.next,
269 struct perf_evsel, node);
270
271 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
272 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
273
274 return test__checkevent_symbolic_name(evlist);
275}
276
277static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
278{
279 struct perf_evsel *evsel = list_entry(evlist->entries.next,
280 struct perf_evsel, node);
281
282 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
283 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
284 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
285 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
286
287 return test__checkevent_symbolic_alias(evlist);
288}
289
290static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
291{
292 struct perf_evsel *evsel = list_entry(evlist->entries.next,
293 struct perf_evsel, node);
294
295 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
296 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
297 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
298 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
299
300 return test__checkevent_genhw(evlist);
301}
302
303static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
304{
305 struct perf_evsel *evsel = list_entry(evlist->entries.next,
306 struct perf_evsel, node);
307
308 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
309 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
310 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
311 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
312
313 return test__checkevent_breakpoint(evlist);
314}
315
316static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
317{
318 struct perf_evsel *evsel = list_entry(evlist->entries.next,
319 struct perf_evsel, node);
320
321 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
322 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
323 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
324 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
325
326 return test__checkevent_breakpoint_x(evlist);
327}
328
329static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
330{
331 struct perf_evsel *evsel = list_entry(evlist->entries.next,
332 struct perf_evsel, node);
333
334 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
335 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
336 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
337 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
338
339 return test__checkevent_breakpoint_r(evlist);
340}
341
342static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
343{
344 struct perf_evsel *evsel = list_entry(evlist->entries.next,
345 struct perf_evsel, node);
346
347 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
348 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
349 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
350 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
351
352 return test__checkevent_breakpoint_w(evlist);
353}
354
355static int test__checkevent_pmu(struct perf_evlist *evlist)
356{
357
358 struct perf_evsel *evsel = list_entry(evlist->entries.next,
359 struct perf_evsel, node);
360
361 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
362 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
363 TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config);
364 TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1);
365 TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2);
366 TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period);
367
368 return 0;
369}
370
371static int test__checkevent_list(struct perf_evlist *evlist)
372{
373 struct perf_evsel *evsel;
374
375 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
376
377 /* r1 */
378 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
379 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
380 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
381 TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
382 TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
383 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
384 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
385 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
386 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
387
388 /* syscalls:sys_enter_open:k */
389 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
390 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
391 TEST_ASSERT_VAL("wrong sample_type",
392 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
393 evsel->attr.sample_type);
394 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
395 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
396 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
397 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
398 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
399
400 /* 1:1:hp */
401 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
402 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
403 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
404 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
405 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
406 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
407 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
408
409 return 0;
410}
411
412static int test__checkevent_pmu_name(struct perf_evlist *evlist)
413{
414 struct perf_evsel *evsel;
415
416 /* cpu/config=1,name=krava1/u */
417 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
418 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
419 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
420 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
421 TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
422
423 /* cpu/config=2/" */
424 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
425 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
426 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
427 TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
428 TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2"));
429
430 return 0;
431}
432
433struct test__event_st {
434 const char *name;
435 __u32 type;
436 int (*check)(struct perf_evlist *evlist);
437};
438
439static struct test__event_st test__events[] = {
440 [0] = {
441 .name = "syscalls:sys_enter_open",
442 .check = test__checkevent_tracepoint,
443 },
444 [1] = {
445 .name = "syscalls:*",
446 .check = test__checkevent_tracepoint_multi,
447 },
448 [2] = {
449 .name = "r1a",
450 .check = test__checkevent_raw,
451 },
452 [3] = {
453 .name = "1:1",
454 .check = test__checkevent_numeric,
455 },
456 [4] = {
457 .name = "instructions",
458 .check = test__checkevent_symbolic_name,
459 },
460 [5] = {
461 .name = "cycles/period=100000,config2/",
462 .check = test__checkevent_symbolic_name_config,
463 },
464 [6] = {
465 .name = "faults",
466 .check = test__checkevent_symbolic_alias,
467 },
468 [7] = {
469 .name = "L1-dcache-load-miss",
470 .check = test__checkevent_genhw,
471 },
472 [8] = {
473 .name = "mem:0",
474 .check = test__checkevent_breakpoint,
475 },
476 [9] = {
477 .name = "mem:0:x",
478 .check = test__checkevent_breakpoint_x,
479 },
480 [10] = {
481 .name = "mem:0:r",
482 .check = test__checkevent_breakpoint_r,
483 },
484 [11] = {
485 .name = "mem:0:w",
486 .check = test__checkevent_breakpoint_w,
487 },
488 [12] = {
489 .name = "syscalls:sys_enter_open:k",
490 .check = test__checkevent_tracepoint_modifier,
491 },
492 [13] = {
493 .name = "syscalls:*:u",
494 .check = test__checkevent_tracepoint_multi_modifier,
495 },
496 [14] = {
497 .name = "r1a:kp",
498 .check = test__checkevent_raw_modifier,
499 },
500 [15] = {
501 .name = "1:1:hp",
502 .check = test__checkevent_numeric_modifier,
503 },
504 [16] = {
505 .name = "instructions:h",
506 .check = test__checkevent_symbolic_name_modifier,
507 },
508 [17] = {
509 .name = "faults:u",
510 .check = test__checkevent_symbolic_alias_modifier,
511 },
512 [18] = {
513 .name = "L1-dcache-load-miss:kp",
514 .check = test__checkevent_genhw_modifier,
515 },
516 [19] = {
517 .name = "mem:0:u",
518 .check = test__checkevent_breakpoint_modifier,
519 },
520 [20] = {
521 .name = "mem:0:x:k",
522 .check = test__checkevent_breakpoint_x_modifier,
523 },
524 [21] = {
525 .name = "mem:0:r:hp",
526 .check = test__checkevent_breakpoint_r_modifier,
527 },
528 [22] = {
529 .name = "mem:0:w:up",
530 .check = test__checkevent_breakpoint_w_modifier,
531 },
532 [23] = {
533 .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
534 .check = test__checkevent_list,
535 },
536 [24] = {
537 .name = "instructions:G",
538 .check = test__checkevent_exclude_host_modifier,
539 },
540 [25] = {
541 .name = "instructions:H",
542 .check = test__checkevent_exclude_guest_modifier,
543 },
544};
545
546#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
547
548static struct test__event_st test__events_pmu[] = {
549 [0] = {
550 .name = "cpu/config=10,config1,config2=3,period=1000/u",
551 .check = test__checkevent_pmu,
552 },
553 [1] = {
554 .name = "cpu/config=1,name=krava/u,cpu/config=2/u",
555 .check = test__checkevent_pmu_name,
556 },
557};
558
559#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \
560 sizeof(struct test__event_st))
561
562static int test(struct test__event_st *e)
563{
564 struct perf_evlist *evlist;
565 int ret;
566
567 evlist = perf_evlist__new(NULL, NULL);
568 if (evlist == NULL)
569 return -ENOMEM;
570
571 ret = parse_events(evlist, e->name, 0);
572 if (ret) {
573 pr_debug("failed to parse event '%s', err %d\n",
574 e->name, ret);
575 return ret;
576 }
577
578 ret = e->check(evlist);
579 perf_evlist__delete(evlist);
580
581 return ret;
582}
583
584static int test_events(struct test__event_st *events, unsigned cnt)
585{
586 int ret = 0;
587 unsigned i;
588
589 for (i = 0; i < cnt; i++) {
590 struct test__event_st *e = &events[i];
591
592 pr_debug("running test %d '%s'\n", i, e->name);
593 ret = test(e);
594 if (ret)
595 break;
596 }
597
598 return ret;
599}
600
601static int test_pmu(void)
602{
603 struct stat st;
604 char path[PATH_MAX];
605 int ret;
606
607 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/",
608 sysfs_find_mountpoint());
609
610 ret = stat(path, &st);
611 if (ret)
612 pr_debug("ommiting PMU cpu tests\n");
613 return !ret;
614}
615
616int parse_events__test(void)
617{
618 int ret;
619
620 ret = test_events(test__events, TEST__EVENTS_CNT);
621 if (!ret && test_pmu())
622 ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT);
623
624 return ret;
625}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5b3a0ef4e232..05dbc8b3c767 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -23,8 +23,10 @@ struct event_symbol {
23 const char *alias; 23 const char *alias;
24}; 24};
25 25
26int parse_events_parse(struct list_head *list, struct list_head *list_tmp, 26#ifdef PARSER_DEBUG
27 int *idx); 27extern int parse_events_debug;
28#endif
29int parse_events_parse(struct list_head *list, int *idx);
28 30
29#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 31#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
30#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 32#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -60,19 +62,6 @@ static struct event_symbol event_symbols[] = {
60#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 62#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
61#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 63#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
62 64
63static const char *hw_event_names[PERF_COUNT_HW_MAX] = {
64 "cycles",
65 "instructions",
66 "cache-references",
67 "cache-misses",
68 "branches",
69 "branch-misses",
70 "bus-cycles",
71 "stalled-cycles-frontend",
72 "stalled-cycles-backend",
73 "ref-cycles",
74};
75
76static const char *sw_event_names[PERF_COUNT_SW_MAX] = { 65static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
77 "cpu-clock", 66 "cpu-clock",
78 "task-clock", 67 "task-clock",
@@ -298,6 +287,16 @@ const char *event_name(struct perf_evsel *evsel)
298 u64 config = evsel->attr.config; 287 u64 config = evsel->attr.config;
299 int type = evsel->attr.type; 288 int type = evsel->attr.type;
300 289
290 if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) {
291 /*
292 * XXX minimal fix, see comment on perf_evsen__name, this static buffer
293 * will go away together with event_name in the next devel cycle.
294 */
295 static char bf[128];
296 perf_evsel__name(evsel, bf, sizeof(bf));
297 return bf;
298 }
299
301 if (evsel->name) 300 if (evsel->name)
302 return evsel->name; 301 return evsel->name;
303 302
@@ -315,9 +314,7 @@ const char *__event_name(int type, u64 config)
315 314
316 switch (type) { 315 switch (type) {
317 case PERF_TYPE_HARDWARE: 316 case PERF_TYPE_HARDWARE:
318 if (config < PERF_COUNT_HW_MAX && hw_event_names[config]) 317 return __perf_evsel__hw_name(config);
319 return hw_event_names[config];
320 return "unknown-hardware";
321 318
322 case PERF_TYPE_HW_CACHE: { 319 case PERF_TYPE_HW_CACHE: {
323 u8 cache_type, cache_op, cache_result; 320 u8 cache_type, cache_op, cache_result;
@@ -355,20 +352,30 @@ const char *__event_name(int type, u64 config)
355 return "unknown"; 352 return "unknown";
356} 353}
357 354
358static int add_event(struct list_head *list, int *idx, 355static int add_event(struct list_head **_list, int *idx,
359 struct perf_event_attr *attr, char *name) 356 struct perf_event_attr *attr, char *name)
360{ 357{
361 struct perf_evsel *evsel; 358 struct perf_evsel *evsel;
359 struct list_head *list = *_list;
360
361 if (!list) {
362 list = malloc(sizeof(*list));
363 if (!list)
364 return -ENOMEM;
365 INIT_LIST_HEAD(list);
366 }
362 367
363 event_attr_init(attr); 368 event_attr_init(attr);
364 369
365 evsel = perf_evsel__new(attr, (*idx)++); 370 evsel = perf_evsel__new(attr, (*idx)++);
366 if (!evsel) 371 if (!evsel) {
372 free(list);
367 return -ENOMEM; 373 return -ENOMEM;
368 374 }
369 list_add_tail(&evsel->node, list);
370 375
371 evsel->name = strdup(name); 376 evsel->name = strdup(name);
377 list_add_tail(&evsel->node, list);
378 *_list = list;
372 return 0; 379 return 0;
373} 380}
374 381
@@ -390,7 +397,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
390 return -1; 397 return -1;
391} 398}
392 399
393int parse_events_add_cache(struct list_head *list, int *idx, 400int parse_events_add_cache(struct list_head **list, int *idx,
394 char *type, char *op_result1, char *op_result2) 401 char *type, char *op_result1, char *op_result2)
395{ 402{
396 struct perf_event_attr attr; 403 struct perf_event_attr attr;
@@ -451,7 +458,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
451 return add_event(list, idx, &attr, name); 458 return add_event(list, idx, &attr, name);
452} 459}
453 460
454static int add_tracepoint(struct list_head *list, int *idx, 461static int add_tracepoint(struct list_head **list, int *idx,
455 char *sys_name, char *evt_name) 462 char *sys_name, char *evt_name)
456{ 463{
457 struct perf_event_attr attr; 464 struct perf_event_attr attr;
@@ -488,7 +495,7 @@ static int add_tracepoint(struct list_head *list, int *idx,
488 return add_event(list, idx, &attr, name); 495 return add_event(list, idx, &attr, name);
489} 496}
490 497
491static int add_tracepoint_multi(struct list_head *list, int *idx, 498static int add_tracepoint_multi(struct list_head **list, int *idx,
492 char *sys_name, char *evt_name) 499 char *sys_name, char *evt_name)
493{ 500{
494 char evt_path[MAXPATHLEN]; 501 char evt_path[MAXPATHLEN];
@@ -519,7 +526,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx,
519 return ret; 526 return ret;
520} 527}
521 528
522int parse_events_add_tracepoint(struct list_head *list, int *idx, 529int parse_events_add_tracepoint(struct list_head **list, int *idx,
523 char *sys, char *event) 530 char *sys, char *event)
524{ 531{
525 int ret; 532 int ret;
@@ -563,7 +570,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
563 return 0; 570 return 0;
564} 571}
565 572
566int parse_events_add_breakpoint(struct list_head *list, int *idx, 573int parse_events_add_breakpoint(struct list_head **list, int *idx,
567 void *ptr, char *type) 574 void *ptr, char *type)
568{ 575{
569 struct perf_event_attr attr; 576 struct perf_event_attr attr;
@@ -593,17 +600,27 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
593static int config_term(struct perf_event_attr *attr, 600static int config_term(struct perf_event_attr *attr,
594 struct parse_events__term *term) 601 struct parse_events__term *term)
595{ 602{
596 switch (term->type) { 603#define CHECK_TYPE_VAL(type) \
604do { \
605 if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val) \
606 return -EINVAL; \
607} while (0)
608
609 switch (term->type_term) {
597 case PARSE_EVENTS__TERM_TYPE_CONFIG: 610 case PARSE_EVENTS__TERM_TYPE_CONFIG:
611 CHECK_TYPE_VAL(NUM);
598 attr->config = term->val.num; 612 attr->config = term->val.num;
599 break; 613 break;
600 case PARSE_EVENTS__TERM_TYPE_CONFIG1: 614 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
615 CHECK_TYPE_VAL(NUM);
601 attr->config1 = term->val.num; 616 attr->config1 = term->val.num;
602 break; 617 break;
603 case PARSE_EVENTS__TERM_TYPE_CONFIG2: 618 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
619 CHECK_TYPE_VAL(NUM);
604 attr->config2 = term->val.num; 620 attr->config2 = term->val.num;
605 break; 621 break;
606 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: 622 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
623 CHECK_TYPE_VAL(NUM);
607 attr->sample_period = term->val.num; 624 attr->sample_period = term->val.num;
608 break; 625 break;
609 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: 626 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
@@ -612,10 +629,15 @@ static int config_term(struct perf_event_attr *attr,
612 * attr->branch_sample_type = term->val.num; 629 * attr->branch_sample_type = term->val.num;
613 */ 630 */
614 break; 631 break;
632 case PARSE_EVENTS__TERM_TYPE_NAME:
633 CHECK_TYPE_VAL(STR);
634 break;
615 default: 635 default:
616 return -EINVAL; 636 return -EINVAL;
617 } 637 }
638
618 return 0; 639 return 0;
640#undef CHECK_TYPE_VAL
619} 641}
620 642
621static int config_attr(struct perf_event_attr *attr, 643static int config_attr(struct perf_event_attr *attr,
@@ -630,7 +652,7 @@ static int config_attr(struct perf_event_attr *attr,
630 return 0; 652 return 0;
631} 653}
632 654
633int parse_events_add_numeric(struct list_head *list, int *idx, 655int parse_events_add_numeric(struct list_head **list, int *idx,
634 unsigned long type, unsigned long config, 656 unsigned long type, unsigned long config,
635 struct list_head *head_config) 657 struct list_head *head_config)
636{ 658{
@@ -648,7 +670,24 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
648 (char *) __event_name(type, config)); 670 (char *) __event_name(type, config));
649} 671}
650 672
651int parse_events_add_pmu(struct list_head *list, int *idx, 673static int parse_events__is_name_term(struct parse_events__term *term)
674{
675 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
676}
677
678static char *pmu_event_name(struct perf_event_attr *attr,
679 struct list_head *head_terms)
680{
681 struct parse_events__term *term;
682
683 list_for_each_entry(term, head_terms, list)
684 if (parse_events__is_name_term(term))
685 return term->val.str;
686
687 return (char *) __event_name(PERF_TYPE_RAW, attr->config);
688}
689
690int parse_events_add_pmu(struct list_head **list, int *idx,
652 char *name, struct list_head *head_config) 691 char *name, struct list_head *head_config)
653{ 692{
654 struct perf_event_attr attr; 693 struct perf_event_attr attr;
@@ -669,7 +708,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
669 if (perf_pmu__config(pmu, &attr, head_config)) 708 if (perf_pmu__config(pmu, &attr, head_config))
670 return -EINVAL; 709 return -EINVAL;
671 710
672 return add_event(list, idx, &attr, (char *) "pmu"); 711 return add_event(list, idx, &attr,
712 pmu_event_name(&attr, head_config));
673} 713}
674 714
675void parse_events_update_lists(struct list_head *list_event, 715void parse_events_update_lists(struct list_head *list_event,
@@ -681,7 +721,7 @@ void parse_events_update_lists(struct list_head *list_event,
681 * list, for next event definition. 721 * list, for next event definition.
682 */ 722 */
683 list_splice_tail(list_event, list_all); 723 list_splice_tail(list_event, list_all);
684 INIT_LIST_HEAD(list_event); 724 free(list_event);
685} 725}
686 726
687int parse_events_modifier(struct list_head *list, char *str) 727int parse_events_modifier(struct list_head *list, char *str)
@@ -756,10 +796,14 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
756 796
757 buffer = parse_events__scan_string(str); 797 buffer = parse_events__scan_string(str);
758 798
759 ret = parse_events_parse(&list, &list_tmp, &idx); 799#ifdef PARSER_DEBUG
800 parse_events_debug = 1;
801#endif
802 ret = parse_events_parse(&list, &idx);
760 803
761 parse_events__flush_buffer(buffer); 804 parse_events__flush_buffer(buffer);
762 parse_events__delete_buffer(buffer); 805 parse_events__delete_buffer(buffer);
806 parse_events_lex_destroy();
763 807
764 if (!ret) { 808 if (!ret) {
765 int entries = idx - evlist->nr_entries; 809 int entries = idx - evlist->nr_entries;
@@ -1015,11 +1059,12 @@ void print_events(const char *event_glob)
1015 1059
1016int parse_events__is_hardcoded_term(struct parse_events__term *term) 1060int parse_events__is_hardcoded_term(struct parse_events__term *term)
1017{ 1061{
1018 return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX; 1062 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
1019} 1063}
1020 1064
1021int parse_events__new_term(struct parse_events__term **_term, int type, 1065static int new_term(struct parse_events__term **_term, int type_val,
1022 char *config, char *str, long num) 1066 int type_term, char *config,
1067 char *str, long num)
1023{ 1068{
1024 struct parse_events__term *term; 1069 struct parse_events__term *term;
1025 1070
@@ -1028,15 +1073,11 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
1028 return -ENOMEM; 1073 return -ENOMEM;
1029 1074
1030 INIT_LIST_HEAD(&term->list); 1075 INIT_LIST_HEAD(&term->list);
1031 term->type = type; 1076 term->type_val = type_val;
1077 term->type_term = type_term;
1032 term->config = config; 1078 term->config = config;
1033 1079
1034 switch (type) { 1080 switch (type_val) {
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: 1081 case PARSE_EVENTS__TERM_TYPE_NUM:
1041 term->val.num = num; 1082 term->val.num = num;
1042 break; 1083 break;
@@ -1051,6 +1092,20 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
1051 return 0; 1092 return 0;
1052} 1093}
1053 1094
1095int parse_events__term_num(struct parse_events__term **term,
1096 int type_term, char *config, long num)
1097{
1098 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1099 config, NULL, num);
1100}
1101
1102int parse_events__term_str(struct parse_events__term **term,
1103 int type_term, char *config, char *str)
1104{
1105 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1106 config, str, 0);
1107}
1108
1054void parse_events__free_terms(struct list_head *terms) 1109void parse_events__free_terms(struct list_head *terms)
1055{ 1110{
1056 struct parse_events__term *term, *h; 1111 struct parse_events__term *term, *h;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ca069f893381..8cac57ab4ee6 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,7 +4,11 @@
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
6 6
7#include <linux/list.h>
8#include <stdbool.h>
9#include "types.h"
7#include "../../../include/linux/perf_event.h" 10#include "../../../include/linux/perf_event.h"
11#include "types.h"
8 12
9struct list_head; 13struct list_head;
10struct perf_evsel; 14struct perf_evsel;
@@ -34,16 +38,18 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
34#define EVENTS_HELP_MAX (128*1024) 38#define EVENTS_HELP_MAX (128*1024)
35 39
36enum { 40enum {
41 PARSE_EVENTS__TERM_TYPE_NUM,
42 PARSE_EVENTS__TERM_TYPE_STR,
43};
44
45enum {
46 PARSE_EVENTS__TERM_TYPE_USER,
37 PARSE_EVENTS__TERM_TYPE_CONFIG, 47 PARSE_EVENTS__TERM_TYPE_CONFIG,
38 PARSE_EVENTS__TERM_TYPE_CONFIG1, 48 PARSE_EVENTS__TERM_TYPE_CONFIG1,
39 PARSE_EVENTS__TERM_TYPE_CONFIG2, 49 PARSE_EVENTS__TERM_TYPE_CONFIG2,
50 PARSE_EVENTS__TERM_TYPE_NAME,
40 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, 51 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
41 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 52 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}; 53};
48 54
49struct parse_events__term { 55struct parse_events__term {
@@ -52,35 +58,34 @@ struct parse_events__term {
52 char *str; 58 char *str;
53 long num; 59 long num;
54 } val; 60 } val;
55 int type; 61 int type_val;
56 62 int type_term;
57 struct list_head list; 63 struct list_head list;
58}; 64};
59 65
60int parse_events__is_hardcoded_term(struct parse_events__term *term); 66int parse_events__is_hardcoded_term(struct parse_events__term *term);
61int parse_events__new_term(struct parse_events__term **term, int type, 67int parse_events__term_num(struct parse_events__term **_term,
62 char *config, char *str, long num); 68 int type_term, char *config, long num);
69int parse_events__term_str(struct parse_events__term **_term,
70 int type_term, char *config, char *str);
63void parse_events__free_terms(struct list_head *terms); 71void parse_events__free_terms(struct list_head *terms);
64int parse_events_modifier(struct list_head *list __used, char *str __used); 72int parse_events_modifier(struct list_head *list, char *str);
65int parse_events_add_tracepoint(struct list_head *list, int *idx, 73int parse_events_add_tracepoint(struct list_head **list, int *idx,
66 char *sys, char *event); 74 char *sys, char *event);
67int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config, 75int parse_events_add_numeric(struct list_head **list, int *idx,
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, 76 unsigned long type, unsigned long config,
72 struct list_head *head_config); 77 struct list_head *head_config);
73int parse_events_add_cache(struct list_head *list, int *idx, 78int parse_events_add_cache(struct list_head **list, int *idx,
74 char *type, char *op_result1, char *op_result2); 79 char *type, char *op_result1, char *op_result2);
75int parse_events_add_breakpoint(struct list_head *list, int *idx, 80int parse_events_add_breakpoint(struct list_head **list, int *idx,
76 void *ptr, char *type); 81 void *ptr, char *type);
77int parse_events_add_pmu(struct list_head *list, int *idx, 82int parse_events_add_pmu(struct list_head **list, int *idx,
78 char *pmu , struct list_head *head_config); 83 char *pmu , struct list_head *head_config);
79void parse_events_update_lists(struct list_head *list_event, 84void parse_events_update_lists(struct list_head *list_event,
80 struct list_head *list_all); 85 struct list_head *list_all);
81void parse_events_error(struct list_head *list_all, 86void parse_events_error(struct list_head *list_all,
82 struct list_head *list_event,
83 int *idx, char const *msg); 87 int *idx, char const *msg);
88int parse_events__test(void);
84 89
85void print_events(const char *event_glob); 90void print_events(const char *event_glob);
86void print_events_type(u8 type); 91void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 05d766e3ecb5..618a8e788399 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -1,5 +1,6 @@
1 1
2%option prefix="parse_events_" 2%option prefix="parse_events_"
3%option stack
3 4
4%{ 5%{
5#include <errno.h> 6#include <errno.h>
@@ -50,11 +51,13 @@ static int term(int type)
50 51
51%} 52%}
52 53
54%x mem
55
53num_dec [0-9]+ 56num_dec [0-9]+
54num_hex 0x[a-fA-F0-9]+ 57num_hex 0x[a-fA-F0-9]+
55num_raw_hex [a-fA-F0-9]+ 58num_raw_hex [a-fA-F0-9]+
56name [a-zA-Z_*?][a-zA-Z0-9_*?]* 59name [a-zA-Z_*?][a-zA-Z0-9_*?]*
57modifier_event [ukhp]{1,5} 60modifier_event [ukhpGH]{1,8}
58modifier_bp [rwx] 61modifier_bp [rwx]
59 62
60%% 63%%
@@ -102,16 +105,16 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
102config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); } 105config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
103config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); } 106config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
104config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } 107config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
108name { return term(PARSE_EVENTS__TERM_TYPE_NAME); }
105period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } 109period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
106branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } 110branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
107 111
108mem: { return PE_PREFIX_MEM; } 112mem: { BEGIN(mem); return PE_PREFIX_MEM; }
109r{num_raw_hex} { return raw(); } 113r{num_raw_hex} { return raw(); }
110{num_dec} { return value(10); } 114{num_dec} { return value(10); }
111{num_hex} { return value(16); } 115{num_hex} { return value(16); }
112 116
113{modifier_event} { return str(PE_MODIFIER_EVENT); } 117{modifier_event} { return str(PE_MODIFIER_EVENT); }
114{modifier_bp} { return str(PE_MODIFIER_BP); }
115{name} { return str(PE_NAME); } 118{name} { return str(PE_NAME); }
116"/" { return '/'; } 119"/" { return '/'; }
117- { return '-'; } 120- { return '-'; }
@@ -119,6 +122,25 @@ r{num_raw_hex} { return raw(); }
119: { return ':'; } 122: { return ':'; }
120= { return '='; } 123= { return '='; }
121 124
125<mem>{
126{modifier_bp} { return str(PE_MODIFIER_BP); }
127: { return ':'; }
128{num_dec} { return value(10); }
129{num_hex} { return value(16); }
130 /*
131 * We need to separate 'mem:' scanner part, in order to get specific
132 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
133 * and we'd need to parse it manually. During the escape from <mem>
134 * state we need to put the escaping char back, so we dont miss it.
135 */
136. { unput(*parse_events_text); BEGIN(INITIAL); }
137 /*
138 * We destroy the scanner after reaching EOF,
139 * but anyway just to be sure get back to INIT state.
140 */
141<<EOF>> { BEGIN(INITIAL); }
142}
143
122%% 144%%
123 145
124int parse_events_wrap(void) 146int parse_events_wrap(void)
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d9637da7333c..362cc59332ae 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,7 +1,6 @@
1 1
2%name-prefix "parse_events_" 2%name-prefix "parse_events_"
3%parse-param {struct list_head *list_all} 3%parse-param {struct list_head *list_all}
4%parse-param {struct list_head *list_event}
5%parse-param {int *idx} 4%parse-param {int *idx}
6 5
7%{ 6%{
@@ -41,6 +40,14 @@ do { \
41%type <str> PE_MODIFIER_BP 40%type <str> PE_MODIFIER_BP
42%type <head> event_config 41%type <head> event_config
43%type <term> event_term 42%type <term> event_term
43%type <head> event_pmu
44%type <head> event_legacy_symbol
45%type <head> event_legacy_cache
46%type <head> event_legacy_mem
47%type <head> event_legacy_tracepoint
48%type <head> event_legacy_numeric
49%type <head> event_legacy_raw
50%type <head> event_def
44 51
45%union 52%union
46{ 53{
@@ -62,13 +69,13 @@ event_def PE_MODIFIER_EVENT
62 * (there could be more events added for multiple tracepoint 69 * (there could be more events added for multiple tracepoint
63 * definitions via '*?'. 70 * definitions via '*?'.
64 */ 71 */
65 ABORT_ON(parse_events_modifier(list_event, $2)); 72 ABORT_ON(parse_events_modifier($1, $2));
66 parse_events_update_lists(list_event, list_all); 73 parse_events_update_lists($1, list_all);
67} 74}
68| 75|
69event_def 76event_def
70{ 77{
71 parse_events_update_lists(list_event, list_all); 78 parse_events_update_lists($1, list_all);
72} 79}
73 80
74event_def: event_pmu | 81event_def: event_pmu |
@@ -82,71 +89,102 @@ event_def: event_pmu |
82event_pmu: 89event_pmu:
83PE_NAME '/' event_config '/' 90PE_NAME '/' event_config '/'
84{ 91{
85 ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3)); 92 struct list_head *list = NULL;
93
94 ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));
86 parse_events__free_terms($3); 95 parse_events__free_terms($3);
96 $$ = list;
87} 97}
88 98
89event_legacy_symbol: 99event_legacy_symbol:
90PE_VALUE_SYM '/' event_config '/' 100PE_VALUE_SYM '/' event_config '/'
91{ 101{
102 struct list_head *list = NULL;
92 int type = $1 >> 16; 103 int type = $1 >> 16;
93 int config = $1 & 255; 104 int config = $1 & 255;
94 105
95 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3)); 106 ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));
96 parse_events__free_terms($3); 107 parse_events__free_terms($3);
108 $$ = list;
97} 109}
98| 110|
99PE_VALUE_SYM sep_slash_dc 111PE_VALUE_SYM sep_slash_dc
100{ 112{
113 struct list_head *list = NULL;
101 int type = $1 >> 16; 114 int type = $1 >> 16;
102 int config = $1 & 255; 115 int config = $1 & 255;
103 116
104 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL)); 117 ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL));
118 $$ = list;
105} 119}
106 120
107event_legacy_cache: 121event_legacy_cache:
108PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 122PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
109{ 123{
110 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5)); 124 struct list_head *list = NULL;
125
126 ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5));
127 $$ = list;
111} 128}
112| 129|
113PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 130PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
114{ 131{
115 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL)); 132 struct list_head *list = NULL;
133
134 ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL));
135 $$ = list;
116} 136}
117| 137|
118PE_NAME_CACHE_TYPE 138PE_NAME_CACHE_TYPE
119{ 139{
120 ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL)); 140 struct list_head *list = NULL;
141
142 ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL));
143 $$ = list;
121} 144}
122 145
123event_legacy_mem: 146event_legacy_mem:
124PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 147PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
125{ 148{
126 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4)); 149 struct list_head *list = NULL;
150
151 ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4));
152 $$ = list;
127} 153}
128| 154|
129PE_PREFIX_MEM PE_VALUE sep_dc 155PE_PREFIX_MEM PE_VALUE sep_dc
130{ 156{
131 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL)); 157 struct list_head *list = NULL;
158
159 ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL));
160 $$ = list;
132} 161}
133 162
134event_legacy_tracepoint: 163event_legacy_tracepoint:
135PE_NAME ':' PE_NAME 164PE_NAME ':' PE_NAME
136{ 165{
137 ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3)); 166 struct list_head *list = NULL;
167
168 ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3));
169 $$ = list;
138} 170}
139 171
140event_legacy_numeric: 172event_legacy_numeric:
141PE_VALUE ':' PE_VALUE 173PE_VALUE ':' PE_VALUE
142{ 174{
143 ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL)); 175 struct list_head *list = NULL;
176
177 ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL));
178 $$ = list;
144} 179}
145 180
146event_legacy_raw: 181event_legacy_raw:
147PE_RAW 182PE_RAW
148{ 183{
149 ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL)); 184 struct list_head *list = NULL;
185
186 ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL));
187 $$ = list;
150} 188}
151 189
152event_config: 190event_config:
@@ -176,8 +214,8 @@ PE_NAME '=' PE_NAME
176{ 214{
177 struct parse_events__term *term; 215 struct parse_events__term *term;
178 216
179 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR, 217 ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER,
180 $1, $3, 0)); 218 $1, $3));
181 $$ = term; 219 $$ = term;
182} 220}
183| 221|
@@ -185,8 +223,8 @@ PE_NAME '=' PE_VALUE
185{ 223{
186 struct parse_events__term *term; 224 struct parse_events__term *term;
187 225
188 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, 226 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
189 $1, NULL, $3)); 227 $1, $3));
190 $$ = term; 228 $$ = term;
191} 229}
192| 230|
@@ -194,8 +232,16 @@ PE_NAME
194{ 232{
195 struct parse_events__term *term; 233 struct parse_events__term *term;
196 234
197 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, 235 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
198 $1, NULL, 1)); 236 $1, 1));
237 $$ = term;
238}
239|
240PE_TERM '=' PE_NAME
241{
242 struct parse_events__term *term;
243
244 ABORT_ON(parse_events__term_str(&term, $1, NULL, $3));
199 $$ = term; 245 $$ = term;
200} 246}
201| 247|
@@ -203,7 +249,7 @@ PE_TERM '=' PE_VALUE
203{ 249{
204 struct parse_events__term *term; 250 struct parse_events__term *term;
205 251
206 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3)); 252 ABORT_ON(parse_events__term_num(&term, $1, NULL, $3));
207 $$ = term; 253 $$ = term;
208} 254}
209| 255|
@@ -211,7 +257,7 @@ PE_TERM
211{ 257{
212 struct parse_events__term *term; 258 struct parse_events__term *term;
213 259
214 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1)); 260 ABORT_ON(parse_events__term_num(&term, $1, NULL, 1));
215 $$ = term; 261 $$ = term;
216} 262}
217 263
@@ -222,7 +268,6 @@ sep_slash_dc: '/' | ':' |
222%% 268%%
223 269
224void parse_events_error(struct list_head *list_all __used, 270void parse_events_error(struct list_head *list_all __used,
225 struct list_head *list_event __used,
226 int *idx __used, 271 int *idx __used,
227 char const *msg __used) 272 char const *msg __used)
228{ 273{
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index cb08a118e811..a119a5371699 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -225,7 +225,7 @@ static int pmu_config_term(struct list_head *formats,
225 if (parse_events__is_hardcoded_term(term)) 225 if (parse_events__is_hardcoded_term(term))
226 return 0; 226 return 0;
227 227
228 if (term->type != PARSE_EVENTS__TERM_TYPE_NUM) 228 if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
229 return -EINVAL; 229 return -EINVAL;
230 230
231 format = pmu_find_format(formats, term->config); 231 format = pmu_find_format(formats, term->config);
@@ -246,6 +246,11 @@ static int pmu_config_term(struct list_head *formats,
246 return -EINVAL; 246 return -EINVAL;
247 } 247 }
248 248
249 /*
250 * XXX If we ever decide to go with string values for
251 * non-hardcoded terms, here's the place to translate
252 * them into value.
253 */
249 *vp |= pmu_format_value(format->bits, term->val.num); 254 *vp |= pmu_format_value(format->bits, term->val.num);
250 return 0; 255 return 0;
251} 256}
@@ -253,9 +258,9 @@ static int pmu_config_term(struct list_head *formats,
253static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, 258static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
254 struct list_head *head_terms) 259 struct list_head *head_terms)
255{ 260{
256 struct parse_events__term *term, *h; 261 struct parse_events__term *term;
257 262
258 list_for_each_entry_safe(term, h, head_terms, list) 263 list_for_each_entry(term, head_terms, list)
259 if (pmu_config_term(formats, attr, term)) 264 if (pmu_config_term(formats, attr, term))
260 return -EINVAL; 265 return -EINVAL;
261 266
@@ -324,49 +329,58 @@ static struct test_format {
324/* Simulated users input. */ 329/* Simulated users input. */
325static struct parse_events__term test_terms[] = { 330static struct parse_events__term test_terms[] = {
326 { 331 {
327 .config = (char *) "krava01", 332 .config = (char *) "krava01",
328 .val.num = 15, 333 .val.num = 15,
329 .type = PARSE_EVENTS__TERM_TYPE_NUM, 334 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
335 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
330 }, 336 },
331 { 337 {
332 .config = (char *) "krava02", 338 .config = (char *) "krava02",
333 .val.num = 170, 339 .val.num = 170,
334 .type = PARSE_EVENTS__TERM_TYPE_NUM, 340 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
341 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
335 }, 342 },
336 { 343 {
337 .config = (char *) "krava03", 344 .config = (char *) "krava03",
338 .val.num = 1, 345 .val.num = 1,
339 .type = PARSE_EVENTS__TERM_TYPE_NUM, 346 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
347 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
340 }, 348 },
341 { 349 {
342 .config = (char *) "krava11", 350 .config = (char *) "krava11",
343 .val.num = 27, 351 .val.num = 27,
344 .type = PARSE_EVENTS__TERM_TYPE_NUM, 352 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
353 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
345 }, 354 },
346 { 355 {
347 .config = (char *) "krava12", 356 .config = (char *) "krava12",
348 .val.num = 1, 357 .val.num = 1,
349 .type = PARSE_EVENTS__TERM_TYPE_NUM, 358 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
359 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
350 }, 360 },
351 { 361 {
352 .config = (char *) "krava13", 362 .config = (char *) "krava13",
353 .val.num = 2, 363 .val.num = 2,
354 .type = PARSE_EVENTS__TERM_TYPE_NUM, 364 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
365 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
355 }, 366 },
356 { 367 {
357 .config = (char *) "krava21", 368 .config = (char *) "krava21",
358 .val.num = 119, 369 .val.num = 119,
359 .type = PARSE_EVENTS__TERM_TYPE_NUM, 370 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
371 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
360 }, 372 },
361 { 373 {
362 .config = (char *) "krava22", 374 .config = (char *) "krava22",
363 .val.num = 11, 375 .val.num = 11,
364 .type = PARSE_EVENTS__TERM_TYPE_NUM, 376 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
377 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
365 }, 378 },
366 { 379 {
367 .config = (char *) "krava23", 380 .config = (char *) "krava23",
368 .val.num = 2, 381 .val.num = 2,
369 .type = PARSE_EVENTS__TERM_TYPE_NUM, 382 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
383 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
370 }, 384 },
371}; 385};
372#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) 386#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8a8ee64e72d1..0dda25d82d06 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -44,6 +44,7 @@
44#include "trace-event.h" /* For __unused */ 44#include "trace-event.h" /* For __unused */
45#include "probe-event.h" 45#include "probe-event.h"
46#include "probe-finder.h" 46#include "probe-finder.h"
47#include "session.h"
47 48
48#define MAX_CMDLEN 256 49#define MAX_CMDLEN 256
49#define MAX_PROBE_ARGS 128 50#define MAX_PROBE_ARGS 128
@@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
70} 71}
71 72
72static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 73static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
74static int convert_name_to_addr(struct perf_probe_event *pev,
75 const char *exec);
73static struct machine machine; 76static struct machine machine;
74 77
75/* Initialize symbol maps and path of vmlinux/modules */ 78/* Initialize symbol maps and path of vmlinux/modules */
@@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)
170 return (dso) ? dso->long_name : NULL; 173 return (dso) ? dso->long_name : NULL;
171} 174}
172 175
176static int init_user_exec(void)
177{
178 int ret = 0;
179
180 symbol_conf.try_vmlinux_path = false;
181 symbol_conf.sort_by_name = true;
182 ret = symbol__init();
183
184 if (ret < 0)
185 pr_debug("Failed to init symbol map.\n");
186
187 return ret;
188}
189
190static int convert_to_perf_probe_point(struct probe_trace_point *tp,
191 struct perf_probe_point *pp)
192{
193 pp->function = strdup(tp->symbol);
194
195 if (pp->function == NULL)
196 return -ENOMEM;
197
198 pp->offset = tp->offset;
199 pp->retprobe = tp->retprobe;
200
201 return 0;
202}
203
173#ifdef DWARF_SUPPORT 204#ifdef DWARF_SUPPORT
174/* Open new debuginfo of given module */ 205/* Open new debuginfo of given module */
175static struct debuginfo *open_debuginfo(const char *module) 206static struct debuginfo *open_debuginfo(const char *module)
@@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
224 if (ret <= 0) { 255 if (ret <= 0) {
225 pr_debug("Failed to find corresponding probes from " 256 pr_debug("Failed to find corresponding probes from "
226 "debuginfo. Use kprobe event information.\n"); 257 "debuginfo. Use kprobe event information.\n");
227 pp->function = strdup(tp->symbol); 258 return convert_to_perf_probe_point(tp, pp);
228 if (pp->function == NULL)
229 return -ENOMEM;
230 pp->offset = tp->offset;
231 } 259 }
232 pp->retprobe = tp->retprobe; 260 pp->retprobe = tp->retprobe;
233 261
@@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
275 int max_tevs, const char *target) 303 int max_tevs, const char *target)
276{ 304{
277 bool need_dwarf = perf_probe_event_need_dwarf(pev); 305 bool need_dwarf = perf_probe_event_need_dwarf(pev);
278 struct debuginfo *dinfo = open_debuginfo(target); 306 struct debuginfo *dinfo;
279 int ntevs, ret = 0; 307 int ntevs, ret = 0;
280 308
309 if (pev->uprobes) {
310 if (need_dwarf) {
311 pr_warning("Debuginfo-analysis is not yet supported"
312 " with -x/--exec option.\n");
313 return -ENOSYS;
314 }
315 return convert_name_to_addr(pev, target);
316 }
317
318 dinfo = open_debuginfo(target);
319
281 if (!dinfo) { 320 if (!dinfo) {
282 if (need_dwarf) { 321 if (need_dwarf) {
283 pr_warning("Failed to open debuginfo file.\n"); 322 pr_warning("Failed to open debuginfo file.\n");
@@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
603 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); 642 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
604 return -ENOENT; 643 return -ENOENT;
605 } 644 }
606 pp->function = strdup(tp->symbol);
607 if (pp->function == NULL)
608 return -ENOMEM;
609 pp->offset = tp->offset;
610 pp->retprobe = tp->retprobe;
611 645
612 return 0; 646 return convert_to_perf_probe_point(tp, pp);
613} 647}
614 648
615static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 649static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
616 struct probe_trace_event **tevs __unused, 650 struct probe_trace_event **tevs __unused,
617 int max_tevs __unused, const char *mod __unused) 651 int max_tevs __unused, const char *target)
618{ 652{
619 if (perf_probe_event_need_dwarf(pev)) { 653 if (perf_probe_event_need_dwarf(pev)) {
620 pr_warning("Debuginfo-analysis is not supported.\n"); 654 pr_warning("Debuginfo-analysis is not supported.\n");
621 return -ENOSYS; 655 return -ENOSYS;
622 } 656 }
657
658 if (pev->uprobes)
659 return convert_name_to_addr(pev, target);
660
623 return 0; 661 return 0;
624} 662}
625 663
@@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
1341 if (buf == NULL) 1379 if (buf == NULL)
1342 return NULL; 1380 return NULL;
1343 1381
1344 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", 1382 if (tev->uprobes)
1345 tp->retprobe ? 'r' : 'p', 1383 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
1346 tev->group, tev->event, 1384 tp->retprobe ? 'r' : 'p',
1347 tp->module ?: "", tp->module ? ":" : "", 1385 tev->group, tev->event,
1348 tp->symbol, tp->offset); 1386 tp->module, tp->symbol);
1387 else
1388 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
1389 tp->retprobe ? 'r' : 'p',
1390 tev->group, tev->event,
1391 tp->module ?: "", tp->module ? ":" : "",
1392 tp->symbol, tp->offset);
1393
1349 if (len <= 0) 1394 if (len <= 0)
1350 goto error; 1395 goto error;
1351 1396
@@ -1364,7 +1409,7 @@ error:
1364} 1409}
1365 1410
1366static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1411static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1367 struct perf_probe_event *pev) 1412 struct perf_probe_event *pev, bool is_kprobe)
1368{ 1413{
1369 char buf[64] = ""; 1414 char buf[64] = "";
1370 int i, ret; 1415 int i, ret;
@@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1376 return -ENOMEM; 1421 return -ENOMEM;
1377 1422
1378 /* Convert trace_point to probe_point */ 1423 /* Convert trace_point to probe_point */
1379 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); 1424 if (is_kprobe)
1425 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1426 else
1427 ret = convert_to_perf_probe_point(&tev->point, &pev->point);
1428
1380 if (ret < 0) 1429 if (ret < 0)
1381 return ret; 1430 return ret;
1382 1431
@@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1472 memset(tev, 0, sizeof(*tev)); 1521 memset(tev, 0, sizeof(*tev));
1473} 1522}
1474 1523
1475static int open_kprobe_events(bool readwrite) 1524static void print_warn_msg(const char *file, bool is_kprobe)
1525{
1526
1527 if (errno == ENOENT) {
1528 const char *config;
1529
1530 if (!is_kprobe)
1531 config = "CONFIG_UPROBE_EVENTS";
1532 else
1533 config = "CONFIG_KPROBE_EVENTS";
1534
1535 pr_warning("%s file does not exist - please rebuild kernel"
1536 " with %s.\n", file, config);
1537 } else
1538 pr_warning("Failed to open %s file: %s\n", file,
1539 strerror(errno));
1540}
1541
1542static int open_probe_events(const char *trace_file, bool readwrite,
1543 bool is_kprobe)
1476{ 1544{
1477 char buf[PATH_MAX]; 1545 char buf[PATH_MAX];
1478 const char *__debugfs; 1546 const char *__debugfs;
@@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)
1484 return -ENOENT; 1552 return -ENOENT;
1485 } 1553 }
1486 1554
1487 ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); 1555 ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
1488 if (ret >= 0) { 1556 if (ret >= 0) {
1489 pr_debug("Opening %s write=%d\n", buf, readwrite); 1557 pr_debug("Opening %s write=%d\n", buf, readwrite);
1490 if (readwrite && !probe_event_dry_run) 1558 if (readwrite && !probe_event_dry_run)
1491 ret = open(buf, O_RDWR, O_APPEND); 1559 ret = open(buf, O_RDWR, O_APPEND);
1492 else 1560 else
1493 ret = open(buf, O_RDONLY, 0); 1561 ret = open(buf, O_RDONLY, 0);
1494 }
1495 1562
1496 if (ret < 0) { 1563 if (ret < 0)
1497 if (errno == ENOENT) 1564 print_warn_msg(buf, is_kprobe);
1498 pr_warning("kprobe_events file does not exist - please"
1499 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
1500 else
1501 pr_warning("Failed to open kprobe_events file: %s\n",
1502 strerror(errno));
1503 } 1565 }
1504 return ret; 1566 return ret;
1505} 1567}
1506 1568
1507/* Get raw string list of current kprobe_events */ 1569static int open_kprobe_events(bool readwrite)
1570{
1571 return open_probe_events("tracing/kprobe_events", readwrite, true);
1572}
1573
1574static int open_uprobe_events(bool readwrite)
1575{
1576 return open_probe_events("tracing/uprobe_events", readwrite, false);
1577}
1578
1579/* Get raw string list of current kprobe_events or uprobe_events */
1508static struct strlist *get_probe_trace_command_rawlist(int fd) 1580static struct strlist *get_probe_trace_command_rawlist(int fd)
1509{ 1581{
1510 int ret, idx; 1582 int ret, idx;
@@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
1569 return ret; 1641 return ret;
1570} 1642}
1571 1643
1572/* List up current perf-probe events */ 1644static int __show_perf_probe_events(int fd, bool is_kprobe)
1573int show_perf_probe_events(void)
1574{ 1645{
1575 int fd, ret; 1646 int ret = 0;
1576 struct probe_trace_event tev; 1647 struct probe_trace_event tev;
1577 struct perf_probe_event pev; 1648 struct perf_probe_event pev;
1578 struct strlist *rawlist; 1649 struct strlist *rawlist;
1579 struct str_node *ent; 1650 struct str_node *ent;
1580 1651
1581 setup_pager();
1582 ret = init_vmlinux();
1583 if (ret < 0)
1584 return ret;
1585
1586 memset(&tev, 0, sizeof(tev)); 1652 memset(&tev, 0, sizeof(tev));
1587 memset(&pev, 0, sizeof(pev)); 1653 memset(&pev, 0, sizeof(pev));
1588 1654
1589 fd = open_kprobe_events(false);
1590 if (fd < 0)
1591 return fd;
1592
1593 rawlist = get_probe_trace_command_rawlist(fd); 1655 rawlist = get_probe_trace_command_rawlist(fd);
1594 close(fd);
1595 if (!rawlist) 1656 if (!rawlist)
1596 return -ENOENT; 1657 return -ENOENT;
1597 1658
1598 strlist__for_each(ent, rawlist) { 1659 strlist__for_each(ent, rawlist) {
1599 ret = parse_probe_trace_command(ent->s, &tev); 1660 ret = parse_probe_trace_command(ent->s, &tev);
1600 if (ret >= 0) { 1661 if (ret >= 0) {
1601 ret = convert_to_perf_probe_event(&tev, &pev); 1662 ret = convert_to_perf_probe_event(&tev, &pev,
1663 is_kprobe);
1602 if (ret >= 0) 1664 if (ret >= 0)
1603 ret = show_perf_probe_event(&pev); 1665 ret = show_perf_probe_event(&pev);
1604 } 1666 }
@@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)
1612 return ret; 1674 return ret;
1613} 1675}
1614 1676
1677/* List up current perf-probe events */
1678int show_perf_probe_events(void)
1679{
1680 int fd, ret;
1681
1682 setup_pager();
1683 fd = open_kprobe_events(false);
1684
1685 if (fd < 0)
1686 return fd;
1687
1688 ret = init_vmlinux();
1689 if (ret < 0)
1690 return ret;
1691
1692 ret = __show_perf_probe_events(fd, true);
1693 close(fd);
1694
1695 fd = open_uprobe_events(false);
1696 if (fd >= 0) {
1697 ret = __show_perf_probe_events(fd, false);
1698 close(fd);
1699 }
1700
1701 return ret;
1702}
1703
1615/* Get current perf-probe event names */ 1704/* Get current perf-probe event names */
1616static struct strlist *get_probe_trace_event_names(int fd, bool include_group) 1705static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
1617{ 1706{
@@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1717 const char *event, *group; 1806 const char *event, *group;
1718 struct strlist *namelist; 1807 struct strlist *namelist;
1719 1808
1720 fd = open_kprobe_events(true); 1809 if (pev->uprobes)
1810 fd = open_uprobe_events(true);
1811 else
1812 fd = open_kprobe_events(true);
1813
1721 if (fd < 0) 1814 if (fd < 0)
1722 return fd; 1815 return fd;
1723 /* Get current event names */ 1816 /* Get current event names */
@@ -1829,6 +1922,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1829 tev->point.offset = pev->point.offset; 1922 tev->point.offset = pev->point.offset;
1830 tev->point.retprobe = pev->point.retprobe; 1923 tev->point.retprobe = pev->point.retprobe;
1831 tev->nargs = pev->nargs; 1924 tev->nargs = pev->nargs;
1925 tev->uprobes = pev->uprobes;
1926
1832 if (tev->nargs) { 1927 if (tev->nargs) {
1833 tev->args = zalloc(sizeof(struct probe_trace_arg) 1928 tev->args = zalloc(sizeof(struct probe_trace_arg)
1834 * tev->nargs); 1929 * tev->nargs);
@@ -1859,6 +1954,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1859 } 1954 }
1860 } 1955 }
1861 1956
1957 if (pev->uprobes)
1958 return 1;
1959
1862 /* Currently just checking function name from symbol map */ 1960 /* Currently just checking function name from symbol map */
1863 sym = __find_kernel_function_by_name(tev->point.symbol, NULL); 1961 sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1864 if (!sym) { 1962 if (!sym) {
@@ -1894,12 +1992,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1894 int i, j, ret; 1992 int i, j, ret;
1895 struct __event_package *pkgs; 1993 struct __event_package *pkgs;
1896 1994
1995 ret = 0;
1897 pkgs = zalloc(sizeof(struct __event_package) * npevs); 1996 pkgs = zalloc(sizeof(struct __event_package) * npevs);
1997
1898 if (pkgs == NULL) 1998 if (pkgs == NULL)
1899 return -ENOMEM; 1999 return -ENOMEM;
1900 2000
1901 /* Init vmlinux path */ 2001 if (!pevs->uprobes)
1902 ret = init_vmlinux(); 2002 /* Init vmlinux path */
2003 ret = init_vmlinux();
2004 else
2005 ret = init_user_exec();
2006
1903 if (ret < 0) { 2007 if (ret < 0) {
1904 free(pkgs); 2008 free(pkgs);
1905 return ret; 2009 return ret;
@@ -1971,23 +2075,15 @@ error:
1971 return ret; 2075 return ret;
1972} 2076}
1973 2077
1974static int del_trace_probe_event(int fd, const char *group, 2078static int del_trace_probe_event(int fd, const char *buf,
1975 const char *event, struct strlist *namelist) 2079 struct strlist *namelist)
1976{ 2080{
1977 char buf[128];
1978 struct str_node *ent, *n; 2081 struct str_node *ent, *n;
1979 int found = 0, ret = 0; 2082 int ret = -1;
1980
1981 ret = e_snprintf(buf, 128, "%s:%s", group, event);
1982 if (ret < 0) {
1983 pr_err("Failed to copy event.\n");
1984 return ret;
1985 }
1986 2083
1987 if (strpbrk(buf, "*?")) { /* Glob-exp */ 2084 if (strpbrk(buf, "*?")) { /* Glob-exp */
1988 strlist__for_each_safe(ent, n, namelist) 2085 strlist__for_each_safe(ent, n, namelist)
1989 if (strglobmatch(ent->s, buf)) { 2086 if (strglobmatch(ent->s, buf)) {
1990 found++;
1991 ret = __del_trace_probe_event(fd, ent); 2087 ret = __del_trace_probe_event(fd, ent);
1992 if (ret < 0) 2088 if (ret < 0)
1993 break; 2089 break;
@@ -1996,40 +2092,43 @@ static int del_trace_probe_event(int fd, const char *group,
1996 } else { 2092 } else {
1997 ent = strlist__find(namelist, buf); 2093 ent = strlist__find(namelist, buf);
1998 if (ent) { 2094 if (ent) {
1999 found++;
2000 ret = __del_trace_probe_event(fd, ent); 2095 ret = __del_trace_probe_event(fd, ent);
2001 if (ret >= 0) 2096 if (ret >= 0)
2002 strlist__remove(namelist, ent); 2097 strlist__remove(namelist, ent);
2003 } 2098 }
2004 } 2099 }
2005 if (found == 0 && ret >= 0)
2006 pr_info("Info: Event \"%s\" does not exist.\n", buf);
2007 2100
2008 return ret; 2101 return ret;
2009} 2102}
2010 2103
2011int del_perf_probe_events(struct strlist *dellist) 2104int del_perf_probe_events(struct strlist *dellist)
2012{ 2105{
2013 int fd, ret = 0; 2106 int ret = -1, ufd = -1, kfd = -1;
2107 char buf[128];
2014 const char *group, *event; 2108 const char *group, *event;
2015 char *p, *str; 2109 char *p, *str;
2016 struct str_node *ent; 2110 struct str_node *ent;
2017 struct strlist *namelist; 2111 struct strlist *namelist = NULL, *unamelist = NULL;
2018
2019 fd = open_kprobe_events(true);
2020 if (fd < 0)
2021 return fd;
2022 2112
2023 /* Get current event names */ 2113 /* Get current event names */
2024 namelist = get_probe_trace_event_names(fd, true); 2114 kfd = open_kprobe_events(true);
2025 if (namelist == NULL) 2115 if (kfd < 0)
2026 return -EINVAL; 2116 return kfd;
2117
2118 namelist = get_probe_trace_event_names(kfd, true);
2119 ufd = open_uprobe_events(true);
2120
2121 if (ufd >= 0)
2122 unamelist = get_probe_trace_event_names(ufd, true);
2123
2124 if (namelist == NULL && unamelist == NULL)
2125 goto error;
2027 2126
2028 strlist__for_each(ent, dellist) { 2127 strlist__for_each(ent, dellist) {
2029 str = strdup(ent->s); 2128 str = strdup(ent->s);
2030 if (str == NULL) { 2129 if (str == NULL) {
2031 ret = -ENOMEM; 2130 ret = -ENOMEM;
2032 break; 2131 goto error;
2033 } 2132 }
2034 pr_debug("Parsing: %s\n", str); 2133 pr_debug("Parsing: %s\n", str);
2035 p = strchr(str, ':'); 2134 p = strchr(str, ':');
@@ -2041,17 +2140,42 @@ int del_perf_probe_events(struct strlist *dellist)
2041 group = "*"; 2140 group = "*";
2042 event = str; 2141 event = str;
2043 } 2142 }
2143
2144 ret = e_snprintf(buf, 128, "%s:%s", group, event);
2145 if (ret < 0) {
2146 pr_err("Failed to copy event.");
2147 free(str);
2148 goto error;
2149 }
2150
2044 pr_debug("Group: %s, Event: %s\n", group, event); 2151 pr_debug("Group: %s, Event: %s\n", group, event);
2045 ret = del_trace_probe_event(fd, group, event, namelist); 2152
2153 if (namelist)
2154 ret = del_trace_probe_event(kfd, buf, namelist);
2155
2156 if (unamelist && ret != 0)
2157 ret = del_trace_probe_event(ufd, buf, unamelist);
2158
2159 if (ret != 0)
2160 pr_info("Info: Event \"%s\" does not exist.\n", buf);
2161
2046 free(str); 2162 free(str);
2047 if (ret < 0)
2048 break;
2049 } 2163 }
2050 strlist__delete(namelist); 2164
2051 close(fd); 2165error:
2166 if (kfd >= 0) {
2167 strlist__delete(namelist);
2168 close(kfd);
2169 }
2170
2171 if (ufd >= 0) {
2172 strlist__delete(unamelist);
2173 close(ufd);
2174 }
2052 2175
2053 return ret; 2176 return ret;
2054} 2177}
2178
2055/* TODO: don't use a global variable for filter ... */ 2179/* TODO: don't use a global variable for filter ... */
2056static struct strfilter *available_func_filter; 2180static struct strfilter *available_func_filter;
2057 2181
@@ -2068,30 +2192,152 @@ static int filter_available_functions(struct map *map __unused,
2068 return 1; 2192 return 1;
2069} 2193}
2070 2194
2071int show_available_funcs(const char *target, struct strfilter *_filter) 2195static int __show_available_funcs(struct map *map)
2196{
2197 if (map__load(map, filter_available_functions)) {
2198 pr_err("Failed to load map.\n");
2199 return -EINVAL;
2200 }
2201 if (!dso__sorted_by_name(map->dso, map->type))
2202 dso__sort_by_name(map->dso, map->type);
2203
2204 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2205 return 0;
2206}
2207
2208static int available_kernel_funcs(const char *module)
2072{ 2209{
2073 struct map *map; 2210 struct map *map;
2074 int ret; 2211 int ret;
2075 2212
2076 setup_pager();
2077
2078 ret = init_vmlinux(); 2213 ret = init_vmlinux();
2079 if (ret < 0) 2214 if (ret < 0)
2080 return ret; 2215 return ret;
2081 2216
2082 map = kernel_get_module_map(target); 2217 map = kernel_get_module_map(module);
2083 if (!map) { 2218 if (!map) {
2084 pr_err("Failed to find %s map.\n", (target) ? : "kernel"); 2219 pr_err("Failed to find %s map.\n", (module) ? : "kernel");
2085 return -EINVAL; 2220 return -EINVAL;
2086 } 2221 }
2222 return __show_available_funcs(map);
2223}
2224
2225static int available_user_funcs(const char *target)
2226{
2227 struct map *map;
2228 int ret;
2229
2230 ret = init_user_exec();
2231 if (ret < 0)
2232 return ret;
2233
2234 map = dso__new_map(target);
2235 ret = __show_available_funcs(map);
2236 dso__delete(map->dso);
2237 map__delete(map);
2238 return ret;
2239}
2240
2241int show_available_funcs(const char *target, struct strfilter *_filter,
2242 bool user)
2243{
2244 setup_pager();
2087 available_func_filter = _filter; 2245 available_func_filter = _filter;
2246
2247 if (!user)
2248 return available_kernel_funcs(target);
2249
2250 return available_user_funcs(target);
2251}
2252
2253/*
2254 * uprobe_events only accepts address:
2255 * Convert function and any offset to address
2256 */
2257static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2258{
2259 struct perf_probe_point *pp = &pev->point;
2260 struct symbol *sym;
2261 struct map *map = NULL;
2262 char *function = NULL, *name = NULL;
2263 int ret = -EINVAL;
2264 unsigned long long vaddr = 0;
2265
2266 if (!pp->function) {
2267 pr_warning("No function specified for uprobes");
2268 goto out;
2269 }
2270
2271 function = strdup(pp->function);
2272 if (!function) {
2273 pr_warning("Failed to allocate memory by strdup.\n");
2274 ret = -ENOMEM;
2275 goto out;
2276 }
2277
2278 name = realpath(exec, NULL);
2279 if (!name) {
2280 pr_warning("Cannot find realpath for %s.\n", exec);
2281 goto out;
2282 }
2283 map = dso__new_map(name);
2284 if (!map) {
2285 pr_warning("Cannot find appropriate DSO for %s.\n", exec);
2286 goto out;
2287 }
2288 available_func_filter = strfilter__new(function, NULL);
2088 if (map__load(map, filter_available_functions)) { 2289 if (map__load(map, filter_available_functions)) {
2089 pr_err("Failed to load map.\n"); 2290 pr_err("Failed to load map.\n");
2090 return -EINVAL; 2291 goto out;
2091 } 2292 }
2092 if (!dso__sorted_by_name(map->dso, map->type))
2093 dso__sort_by_name(map->dso, map->type);
2094 2293
2095 dso__fprintf_symbols_by_name(map->dso, map->type, stdout); 2294 sym = map__find_symbol_by_name(map, function, NULL);
2096 return 0; 2295 if (!sym) {
2296 pr_warning("Cannot find %s in DSO %s\n", function, exec);
2297 goto out;
2298 }
2299
2300 if (map->start > sym->start)
2301 vaddr = map->start;
2302 vaddr += sym->start + pp->offset + map->pgoff;
2303 pp->offset = 0;
2304
2305 if (!pev->event) {
2306 pev->event = function;
2307 function = NULL;
2308 }
2309 if (!pev->group) {
2310 char *ptr1, *ptr2;
2311
2312 pev->group = zalloc(sizeof(char *) * 64);
2313 ptr1 = strdup(basename(exec));
2314 if (ptr1) {
2315 ptr2 = strpbrk(ptr1, "-._");
2316 if (ptr2)
2317 *ptr2 = '\0';
2318 e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
2319 ptr1);
2320 free(ptr1);
2321 }
2322 }
2323 free(pp->function);
2324 pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
2325 if (!pp->function) {
2326 ret = -ENOMEM;
2327 pr_warning("Failed to allocate memory by zalloc.\n");
2328 goto out;
2329 }
2330 e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
2331 ret = 0;
2332
2333out:
2334 if (map) {
2335 dso__delete(map->dso);
2336 map__delete(map);
2337 }
2338 if (function)
2339 free(function);
2340 if (name)
2341 free(name);
2342 return ret;
2097} 2343}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index a7dee835f49c..f9f3de8b4220 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,7 +7,7 @@
7 7
8extern bool probe_event_dry_run; 8extern bool probe_event_dry_run;
9 9
10/* kprobe-tracer tracing point */ 10/* kprobe-tracer and uprobe-tracer tracing point */
11struct probe_trace_point { 11struct probe_trace_point {
12 char *symbol; /* Base symbol */ 12 char *symbol; /* Base symbol */
13 char *module; /* Module name */ 13 char *module; /* Module name */
@@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
21 long offset; /* Offset value */ 21 long offset; /* Offset value */
22}; 22};
23 23
24/* kprobe-tracer tracing argument */ 24/* kprobe-tracer and uprobe-tracer tracing argument */
25struct probe_trace_arg { 25struct probe_trace_arg {
26 char *name; /* Argument name */ 26 char *name; /* Argument name */
27 char *value; /* Base value */ 27 char *value; /* Base value */
@@ -29,12 +29,13 @@ struct probe_trace_arg {
29 struct probe_trace_arg_ref *ref; /* Referencing offset */ 29 struct probe_trace_arg_ref *ref; /* Referencing offset */
30}; 30};
31 31
32/* kprobe-tracer tracing event (point + arg) */ 32/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
33struct probe_trace_event { 33struct probe_trace_event {
34 char *event; /* Event name */ 34 char *event; /* Event name */
35 char *group; /* Group name */ 35 char *group; /* Group name */
36 struct probe_trace_point point; /* Trace point */ 36 struct probe_trace_point point; /* Trace point */
37 int nargs; /* Number of args */ 37 int nargs; /* Number of args */
38 bool uprobes; /* uprobes only */
38 struct probe_trace_arg *args; /* Arguments */ 39 struct probe_trace_arg *args; /* Arguments */
39}; 40};
40 41
@@ -70,6 +71,7 @@ struct perf_probe_event {
70 char *group; /* Group name */ 71 char *group; /* Group name */
71 struct perf_probe_point point; /* Probe point */ 72 struct perf_probe_point point; /* Probe point */
72 int nargs; /* Number of arguments */ 73 int nargs; /* Number of arguments */
74 bool uprobes;
73 struct perf_probe_arg *args; /* Arguments */ 75 struct perf_probe_arg *args; /* Arguments */
74}; 76};
75 77
@@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
129extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 131extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
130 int max_probe_points, const char *module, 132 int max_probe_points, const char *module,
131 struct strfilter *filter, bool externs); 133 struct strfilter *filter, bool externs);
132extern int show_available_funcs(const char *module, struct strfilter *filter); 134extern int show_available_funcs(const char *module, struct strfilter *filter,
133 135 bool user);
134 136
135/* Maximum index number of event-name postfix */ 137/* Maximum index number of event-name postfix */
136#define MAX_EVENT_INDEX 1024 138#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e30749e38a9b..4c1b3d72a1d2 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -56,7 +56,7 @@ INTERP my_perl;
56#define FTRACE_MAX_EVENT \ 56#define FTRACE_MAX_EVENT \
57 ((1 << (sizeof(unsigned short) * 8)) - 1) 57 ((1 << (sizeof(unsigned short) * 8)) - 1)
58 58
59struct event *events[FTRACE_MAX_EVENT]; 59struct event_format *events[FTRACE_MAX_EVENT];
60 60
61extern struct scripting_context *scripting_context; 61extern struct scripting_context *scripting_context;
62 62
@@ -181,7 +181,7 @@ static void define_flag_field(const char *ev_name,
181 LEAVE; 181 LEAVE;
182} 182}
183 183
184static void define_event_symbols(struct event *event, 184static void define_event_symbols(struct event_format *event,
185 const char *ev_name, 185 const char *ev_name,
186 struct print_arg *args) 186 struct print_arg *args)
187{ 187{
@@ -209,6 +209,8 @@ static void define_event_symbols(struct event *event,
209 define_symbolic_values(args->symbol.symbols, ev_name, 209 define_symbolic_values(args->symbol.symbols, ev_name,
210 cur_field_name); 210 cur_field_name);
211 break; 211 break;
212 case PRINT_BSTRING:
213 case PRINT_DYNAMIC_ARRAY:
212 case PRINT_STRING: 214 case PRINT_STRING:
213 break; 215 break;
214 case PRINT_TYPE: 216 case PRINT_TYPE:
@@ -220,7 +222,9 @@ static void define_event_symbols(struct event *event,
220 define_event_symbols(event, ev_name, args->op.left); 222 define_event_symbols(event, ev_name, args->op.left);
221 define_event_symbols(event, ev_name, args->op.right); 223 define_event_symbols(event, ev_name, args->op.right);
222 break; 224 break;
225 case PRINT_FUNC:
223 default: 226 default:
227 pr_err("Unsupported print arg type\n");
224 /* we should warn... */ 228 /* we should warn... */
225 return; 229 return;
226 } 230 }
@@ -229,10 +233,10 @@ static void define_event_symbols(struct event *event,
229 define_event_symbols(event, ev_name, args->next); 233 define_event_symbols(event, ev_name, args->next);
230} 234}
231 235
232static inline struct event *find_cache_event(int type) 236static inline struct event_format *find_cache_event(int type)
233{ 237{
234 static char ev_name[256]; 238 static char ev_name[256];
235 struct event *event; 239 struct event_format *event;
236 240
237 if (events[type]) 241 if (events[type])
238 return events[type]; 242 return events[type];
@@ -258,7 +262,7 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,
258 static char handler[256]; 262 static char handler[256];
259 unsigned long long val; 263 unsigned long long val;
260 unsigned long s, ns; 264 unsigned long s, ns;
261 struct event *event; 265 struct event_format *event;
262 int type; 266 int type;
263 int pid; 267 int pid;
264 int cpu = sample->cpu; 268 int cpu = sample->cpu;
@@ -446,7 +450,7 @@ static int perl_stop_script(void)
446 450
447static int perl_generate_script(const char *outfile) 451static int perl_generate_script(const char *outfile)
448{ 452{
449 struct event *event = NULL; 453 struct event_format *event = NULL;
450 struct format_field *f; 454 struct format_field *f;
451 char fname[PATH_MAX]; 455 char fname[PATH_MAX];
452 int not_first, count; 456 int not_first, count;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index c2623c6f9b51..acb9795286c4 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -37,7 +37,7 @@ PyMODINIT_FUNC initperf_trace_context(void);
37#define FTRACE_MAX_EVENT \ 37#define FTRACE_MAX_EVENT \
38 ((1 << (sizeof(unsigned short) * 8)) - 1) 38 ((1 << (sizeof(unsigned short) * 8)) - 1)
39 39
40struct event *events[FTRACE_MAX_EVENT]; 40struct event_format *events[FTRACE_MAX_EVENT];
41 41
42#define MAX_FIELDS 64 42#define MAX_FIELDS 64
43#define N_COMMON_FIELDS 7 43#define N_COMMON_FIELDS 7
@@ -136,7 +136,7 @@ static void define_field(enum print_arg_type field_type,
136 Py_DECREF(t); 136 Py_DECREF(t);
137} 137}
138 138
139static void define_event_symbols(struct event *event, 139static void define_event_symbols(struct event_format *event,
140 const char *ev_name, 140 const char *ev_name,
141 struct print_arg *args) 141 struct print_arg *args)
142{ 142{
@@ -178,6 +178,10 @@ static void define_event_symbols(struct event *event,
178 define_event_symbols(event, ev_name, args->op.right); 178 define_event_symbols(event, ev_name, args->op.right);
179 break; 179 break;
180 default: 180 default:
181 /* gcc warns for these? */
182 case PRINT_BSTRING:
183 case PRINT_DYNAMIC_ARRAY:
184 case PRINT_FUNC:
181 /* we should warn... */ 185 /* we should warn... */
182 return; 186 return;
183 } 187 }
@@ -186,10 +190,10 @@ static void define_event_symbols(struct event *event,
186 define_event_symbols(event, ev_name, args->next); 190 define_event_symbols(event, ev_name, args->next);
187} 191}
188 192
189static inline struct event *find_cache_event(int type) 193static inline struct event_format *find_cache_event(int type)
190{ 194{
191 static char ev_name[256]; 195 static char ev_name[256];
192 struct event *event; 196 struct event_format *event;
193 197
194 if (events[type]) 198 if (events[type])
195 return events[type]; 199 return events[type];
@@ -216,7 +220,7 @@ static void python_process_event(union perf_event *pevent __unused,
216 struct format_field *field; 220 struct format_field *field;
217 unsigned long long val; 221 unsigned long long val;
218 unsigned long s, ns; 222 unsigned long s, ns;
219 struct event *event; 223 struct event_format *event;
220 unsigned n = 0; 224 unsigned n = 0;
221 int type; 225 int type;
222 int pid; 226 int pid;
@@ -436,7 +440,7 @@ out:
436 440
437static int python_generate_script(const char *outfile) 441static int python_generate_script(const char *outfile)
438{ 442{
439 struct event *event = NULL; 443 struct event_format *event = NULL;
440 struct format_field *f; 444 struct format_field *f;
441 char fname[PATH_MAX]; 445 char fname[PATH_MAX];
442 int not_first, count; 446 int not_first, count;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1efd3bee6336..c3e399bcf18d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -288,7 +288,8 @@ struct branch_info *machine__resolve_bstack(struct machine *self,
288 return bi; 288 return bi;
289} 289}
290 290
291int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, 291int machine__resolve_callchain(struct machine *self,
292 struct perf_evsel *evsel __used,
292 struct thread *thread, 293 struct thread *thread,
293 struct ip_callchain *chain, 294 struct ip_callchain *chain,
294 struct symbol **parent) 295 struct symbol **parent)
@@ -297,7 +298,12 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
297 unsigned int i; 298 unsigned int i;
298 int err; 299 int err;
299 300
300 callchain_cursor_reset(&evsel->hists.callchain_cursor); 301 callchain_cursor_reset(&callchain_cursor);
302
303 if (chain->nr > PERF_MAX_STACK_DEPTH) {
304 pr_warning("corrupted callchain. skipping...\n");
305 return 0;
306 }
301 307
302 for (i = 0; i < chain->nr; i++) { 308 for (i = 0; i < chain->nr; i++) {
303 u64 ip; 309 u64 ip;
@@ -317,7 +323,14 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
317 case PERF_CONTEXT_USER: 323 case PERF_CONTEXT_USER:
318 cpumode = PERF_RECORD_MISC_USER; break; 324 cpumode = PERF_RECORD_MISC_USER; break;
319 default: 325 default:
320 break; 326 pr_debug("invalid callchain context: "
327 "%"PRId64"\n", (s64) ip);
328 /*
329 * It seems the callchain is corrupted.
330 * Discard all.
331 */
332 callchain_cursor_reset(&callchain_cursor);
333 return 0;
321 } 334 }
322 continue; 335 continue;
323 } 336 }
@@ -333,7 +346,7 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
333 break; 346 break;
334 } 347 }
335 348
336 err = callchain_cursor_append(&evsel->hists.callchain_cursor, 349 err = callchain_cursor_append(&callchain_cursor,
337 ip, al.map, al.sym); 350 ip, al.map, al.sym);
338 if (err) 351 if (err)
339 return err; 352 return err;
@@ -429,6 +442,16 @@ static void perf_tool__fill_defaults(struct perf_tool *tool)
429 tool->finished_round = process_finished_round_stub; 442 tool->finished_round = process_finished_round_stub;
430 } 443 }
431} 444}
445
446void mem_bswap_32(void *src, int byte_size)
447{
448 u32 *m = src;
449 while (byte_size > 0) {
450 *m = bswap_32(*m);
451 byte_size -= sizeof(u32);
452 ++m;
453 }
454}
432 455
433void mem_bswap_64(void *src, int byte_size) 456void mem_bswap_64(void *src, int byte_size)
434{ 457{
@@ -441,37 +464,65 @@ void mem_bswap_64(void *src, int byte_size)
441 } 464 }
442} 465}
443 466
444static void perf_event__all64_swap(union perf_event *event) 467static void swap_sample_id_all(union perf_event *event, void *data)
468{
469 void *end = (void *) event + event->header.size;
470 int size = end - data;
471
472 BUG_ON(size % sizeof(u64));
473 mem_bswap_64(data, size);
474}
475
476static void perf_event__all64_swap(union perf_event *event,
477 bool sample_id_all __used)
445{ 478{
446 struct perf_event_header *hdr = &event->header; 479 struct perf_event_header *hdr = &event->header;
447 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); 480 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
448} 481}
449 482
450static void perf_event__comm_swap(union perf_event *event) 483static void perf_event__comm_swap(union perf_event *event, bool sample_id_all)
451{ 484{
452 event->comm.pid = bswap_32(event->comm.pid); 485 event->comm.pid = bswap_32(event->comm.pid);
453 event->comm.tid = bswap_32(event->comm.tid); 486 event->comm.tid = bswap_32(event->comm.tid);
487
488 if (sample_id_all) {
489 void *data = &event->comm.comm;
490
491 data += ALIGN(strlen(data) + 1, sizeof(u64));
492 swap_sample_id_all(event, data);
493 }
454} 494}
455 495
456static void perf_event__mmap_swap(union perf_event *event) 496static void perf_event__mmap_swap(union perf_event *event,
497 bool sample_id_all)
457{ 498{
458 event->mmap.pid = bswap_32(event->mmap.pid); 499 event->mmap.pid = bswap_32(event->mmap.pid);
459 event->mmap.tid = bswap_32(event->mmap.tid); 500 event->mmap.tid = bswap_32(event->mmap.tid);
460 event->mmap.start = bswap_64(event->mmap.start); 501 event->mmap.start = bswap_64(event->mmap.start);
461 event->mmap.len = bswap_64(event->mmap.len); 502 event->mmap.len = bswap_64(event->mmap.len);
462 event->mmap.pgoff = bswap_64(event->mmap.pgoff); 503 event->mmap.pgoff = bswap_64(event->mmap.pgoff);
504
505 if (sample_id_all) {
506 void *data = &event->mmap.filename;
507
508 data += ALIGN(strlen(data) + 1, sizeof(u64));
509 swap_sample_id_all(event, data);
510 }
463} 511}
464 512
465static void perf_event__task_swap(union perf_event *event) 513static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
466{ 514{
467 event->fork.pid = bswap_32(event->fork.pid); 515 event->fork.pid = bswap_32(event->fork.pid);
468 event->fork.tid = bswap_32(event->fork.tid); 516 event->fork.tid = bswap_32(event->fork.tid);
469 event->fork.ppid = bswap_32(event->fork.ppid); 517 event->fork.ppid = bswap_32(event->fork.ppid);
470 event->fork.ptid = bswap_32(event->fork.ptid); 518 event->fork.ptid = bswap_32(event->fork.ptid);
471 event->fork.time = bswap_64(event->fork.time); 519 event->fork.time = bswap_64(event->fork.time);
520
521 if (sample_id_all)
522 swap_sample_id_all(event, &event->fork + 1);
472} 523}
473 524
474static void perf_event__read_swap(union perf_event *event) 525static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
475{ 526{
476 event->read.pid = bswap_32(event->read.pid); 527 event->read.pid = bswap_32(event->read.pid);
477 event->read.tid = bswap_32(event->read.tid); 528 event->read.tid = bswap_32(event->read.tid);
@@ -479,6 +530,41 @@ static void perf_event__read_swap(union perf_event *event)
479 event->read.time_enabled = bswap_64(event->read.time_enabled); 530 event->read.time_enabled = bswap_64(event->read.time_enabled);
480 event->read.time_running = bswap_64(event->read.time_running); 531 event->read.time_running = bswap_64(event->read.time_running);
481 event->read.id = bswap_64(event->read.id); 532 event->read.id = bswap_64(event->read.id);
533
534 if (sample_id_all)
535 swap_sample_id_all(event, &event->read + 1);
536}
537
538static u8 revbyte(u8 b)
539{
540 int rev = (b >> 4) | ((b & 0xf) << 4);
541 rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2);
542 rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1);
543 return (u8) rev;
544}
545
546/*
547 * XXX this is hack in attempt to carry flags bitfield
548 * throught endian village. ABI says:
549 *
550 * Bit-fields are allocated from right to left (least to most significant)
551 * on little-endian implementations and from left to right (most to least
552 * significant) on big-endian implementations.
553 *
554 * The above seems to be byte specific, so we need to reverse each
555 * byte of the bitfield. 'Internet' also says this might be implementation
556 * specific and we probably need proper fix and carry perf_event_attr
557 * bitfield flags in separate data file FEAT_ section. Thought this seems
558 * to work for now.
559 */
560static void swap_bitfield(u8 *p, unsigned len)
561{
562 unsigned i;
563
564 for (i = 0; i < len; i++) {
565 *p = revbyte(*p);
566 p++;
567 }
482} 568}
483 569
484/* exported for swapping attributes in file header */ 570/* exported for swapping attributes in file header */
@@ -494,9 +580,12 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
494 attr->bp_type = bswap_32(attr->bp_type); 580 attr->bp_type = bswap_32(attr->bp_type);
495 attr->bp_addr = bswap_64(attr->bp_addr); 581 attr->bp_addr = bswap_64(attr->bp_addr);
496 attr->bp_len = bswap_64(attr->bp_len); 582 attr->bp_len = bswap_64(attr->bp_len);
583
584 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
497} 585}
498 586
499static void perf_event__hdr_attr_swap(union perf_event *event) 587static void perf_event__hdr_attr_swap(union perf_event *event,
588 bool sample_id_all __used)
500{ 589{
501 size_t size; 590 size_t size;
502 591
@@ -507,18 +596,21 @@ static void perf_event__hdr_attr_swap(union perf_event *event)
507 mem_bswap_64(event->attr.id, size); 596 mem_bswap_64(event->attr.id, size);
508} 597}
509 598
510static void perf_event__event_type_swap(union perf_event *event) 599static void perf_event__event_type_swap(union perf_event *event,
600 bool sample_id_all __used)
511{ 601{
512 event->event_type.event_type.event_id = 602 event->event_type.event_type.event_id =
513 bswap_64(event->event_type.event_type.event_id); 603 bswap_64(event->event_type.event_type.event_id);
514} 604}
515 605
516static void perf_event__tracing_data_swap(union perf_event *event) 606static void perf_event__tracing_data_swap(union perf_event *event,
607 bool sample_id_all __used)
517{ 608{
518 event->tracing_data.size = bswap_32(event->tracing_data.size); 609 event->tracing_data.size = bswap_32(event->tracing_data.size);
519} 610}
520 611
521typedef void (*perf_event__swap_op)(union perf_event *event); 612typedef void (*perf_event__swap_op)(union perf_event *event,
613 bool sample_id_all);
522 614
523static perf_event__swap_op perf_event__swap_ops[] = { 615static perf_event__swap_op perf_event__swap_ops[] = {
524 [PERF_RECORD_MMAP] = perf_event__mmap_swap, 616 [PERF_RECORD_MMAP] = perf_event__mmap_swap,
@@ -952,6 +1044,15 @@ static int perf_session__process_user_event(struct perf_session *session, union
952 } 1044 }
953} 1045}
954 1046
1047static void event_swap(union perf_event *event, bool sample_id_all)
1048{
1049 perf_event__swap_op swap;
1050
1051 swap = perf_event__swap_ops[event->header.type];
1052 if (swap)
1053 swap(event, sample_id_all);
1054}
1055
955static int perf_session__process_event(struct perf_session *session, 1056static int perf_session__process_event(struct perf_session *session,
956 union perf_event *event, 1057 union perf_event *event,
957 struct perf_tool *tool, 1058 struct perf_tool *tool,
@@ -960,9 +1061,8 @@ static int perf_session__process_event(struct perf_session *session,
960 struct perf_sample sample; 1061 struct perf_sample sample;
961 int ret; 1062 int ret;
962 1063
963 if (session->header.needs_swap && 1064 if (session->header.needs_swap)
964 perf_event__swap_ops[event->header.type]) 1065 event_swap(event, session->sample_id_all);
965 perf_event__swap_ops[event->header.type](event);
966 1066
967 if (event->header.type >= PERF_RECORD_HEADER_MAX) 1067 if (event->header.type >= PERF_RECORD_HEADER_MAX)
968 return -EINVAL; 1068 return -EINVAL;
@@ -1064,8 +1164,9 @@ volatile int session_done;
1064static int __perf_session__process_pipe_events(struct perf_session *self, 1164static int __perf_session__process_pipe_events(struct perf_session *self,
1065 struct perf_tool *tool) 1165 struct perf_tool *tool)
1066{ 1166{
1067 union perf_event event; 1167 union perf_event *event;
1068 uint32_t size; 1168 uint32_t size, cur_size = 0;
1169 void *buf = NULL;
1069 int skip = 0; 1170 int skip = 0;
1070 u64 head; 1171 u64 head;
1071 int err; 1172 int err;
@@ -1074,8 +1175,14 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
1074 perf_tool__fill_defaults(tool); 1175 perf_tool__fill_defaults(tool);
1075 1176
1076 head = 0; 1177 head = 0;
1178 cur_size = sizeof(union perf_event);
1179
1180 buf = malloc(cur_size);
1181 if (!buf)
1182 return -errno;
1077more: 1183more:
1078 err = readn(self->fd, &event, sizeof(struct perf_event_header)); 1184 event = buf;
1185 err = readn(self->fd, event, sizeof(struct perf_event_header));
1079 if (err <= 0) { 1186 if (err <= 0) {
1080 if (err == 0) 1187 if (err == 0)
1081 goto done; 1188 goto done;
@@ -1085,13 +1192,23 @@ more:
1085 } 1192 }
1086 1193
1087 if (self->header.needs_swap) 1194 if (self->header.needs_swap)
1088 perf_event_header__bswap(&event.header); 1195 perf_event_header__bswap(&event->header);
1089 1196
1090 size = event.header.size; 1197 size = event->header.size;
1091 if (size == 0) 1198 if (size == 0)
1092 size = 8; 1199 size = 8;
1093 1200
1094 p = &event; 1201 if (size > cur_size) {
1202 void *new = realloc(buf, size);
1203 if (!new) {
1204 pr_err("failed to allocate memory to read event\n");
1205 goto out_err;
1206 }
1207 buf = new;
1208 cur_size = size;
1209 event = buf;
1210 }
1211 p = event;
1095 p += sizeof(struct perf_event_header); 1212 p += sizeof(struct perf_event_header);
1096 1213
1097 if (size - sizeof(struct perf_event_header)) { 1214 if (size - sizeof(struct perf_event_header)) {
@@ -1107,17 +1224,11 @@ more:
1107 } 1224 }
1108 } 1225 }
1109 1226
1110 if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) { 1227 if ((skip = perf_session__process_event(self, event, tool, head)) < 0) {
1111 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1228 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1112 head, event.header.size, event.header.type); 1229 head, event->header.size, event->header.type);
1113 /* 1230 err = -EINVAL;
1114 * assume we lost track of the stream, check alignment, and 1231 goto out_err;
1115 * increment a single u64 in the hope to catch on again 'soon'.
1116 */
1117 if (unlikely(head & 7))
1118 head &= ~7ULL;
1119
1120 size = 8;
1121 } 1232 }
1122 1233
1123 head += size; 1234 head += size;
@@ -1130,6 +1241,7 @@ more:
1130done: 1241done:
1131 err = 0; 1242 err = 0;
1132out_err: 1243out_err:
1244 free(buf);
1133 perf_session__warn_about_errors(self, tool); 1245 perf_session__warn_about_errors(self, tool);
1134 perf_session_free_sample_buffers(self); 1246 perf_session_free_sample_buffers(self);
1135 return err; 1247 return err;
@@ -1226,17 +1338,11 @@ more:
1226 1338
1227 if (size == 0 || 1339 if (size == 0 ||
1228 perf_session__process_event(session, event, tool, file_pos) < 0) { 1340 perf_session__process_event(session, event, tool, file_pos) < 0) {
1229 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1341 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1230 file_offset + head, event->header.size, 1342 file_offset + head, event->header.size,
1231 event->header.type); 1343 event->header.type);
1232 /* 1344 err = -EINVAL;
1233 * assume we lost track of the stream, check alignment, and 1345 goto out_err;
1234 * increment a single u64 in the hope to catch on again 'soon'.
1235 */
1236 if (unlikely(head & 7))
1237 head &= ~7ULL;
1238
1239 size = 8;
1240 } 1346 }
1241 1347
1242 head += size; 1348 head += size;
@@ -1388,7 +1494,6 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1388 int print_sym, int print_dso, int print_symoffset) 1494 int print_sym, int print_dso, int print_symoffset)
1389{ 1495{
1390 struct addr_location al; 1496 struct addr_location al;
1391 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
1392 struct callchain_cursor_node *node; 1497 struct callchain_cursor_node *node;
1393 1498
1394 if (perf_event__preprocess_sample(event, machine, &al, sample, 1499 if (perf_event__preprocess_sample(event, machine, &al, sample,
@@ -1406,10 +1511,10 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1406 error("Failed to resolve callchain. Skipping\n"); 1511 error("Failed to resolve callchain. Skipping\n");
1407 return; 1512 return;
1408 } 1513 }
1409 callchain_cursor_commit(cursor); 1514 callchain_cursor_commit(&callchain_cursor);
1410 1515
1411 while (1) { 1516 while (1) {
1412 node = callchain_cursor_current(cursor); 1517 node = callchain_cursor_current(&callchain_cursor);
1413 if (!node) 1518 if (!node)
1414 break; 1519 break;
1415 1520
@@ -1420,12 +1525,12 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1420 } 1525 }
1421 if (print_dso) { 1526 if (print_dso) {
1422 printf(" ("); 1527 printf(" (");
1423 map__fprintf_dsoname(al.map, stdout); 1528 map__fprintf_dsoname(node->map, stdout);
1424 printf(")"); 1529 printf(")");
1425 } 1530 }
1426 printf("\n"); 1531 printf("\n");
1427 1532
1428 callchain_cursor_advance(cursor); 1533 callchain_cursor_advance(&callchain_cursor);
1429 } 1534 }
1430 1535
1431 } else { 1536 } else {
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 7a5434c00565..0c702e3f0a36 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -80,6 +80,7 @@ struct branch_info *machine__resolve_bstack(struct machine *self,
80bool perf_session__has_traces(struct perf_session *self, const char *msg); 80bool perf_session__has_traces(struct perf_session *self, const char *msg);
81 81
82void mem_bswap_64(void *src, int byte_size); 82void mem_bswap_64(void *src, int byte_size);
83void mem_bswap_32(void *src, int byte_size);
83void perf_event__attr_swap(struct perf_event_attr *attr); 84void perf_event__attr_swap(struct perf_event_attr *attr);
84 85
85int perf_session__create_kernel_maps(struct perf_session *self); 86int perf_session__create_kernel_maps(struct perf_session *self);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c0a028c3ebaf..3e2e5ea0f03f 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -323,6 +323,7 @@ struct dso *dso__new(const char *name)
323 dso->sorted_by_name = 0; 323 dso->sorted_by_name = 0;
324 dso->has_build_id = 0; 324 dso->has_build_id = 0;
325 dso->kernel = DSO_TYPE_USER; 325 dso->kernel = DSO_TYPE_USER;
326 dso->needs_swap = DSO_SWAP__UNSET;
326 INIT_LIST_HEAD(&dso->node); 327 INIT_LIST_HEAD(&dso->node);
327 } 328 }
328 329
@@ -977,8 +978,9 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
977 * And always look at the original dso, not at debuginfo packages, that 978 * And always look at the original dso, not at debuginfo packages, that
978 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 979 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
979 */ 980 */
980static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map, 981static int
981 symbol_filter_t filter) 982dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map,
983 symbol_filter_t filter)
982{ 984{
983 uint32_t nr_rel_entries, idx; 985 uint32_t nr_rel_entries, idx;
984 GElf_Sym sym; 986 GElf_Sym sym;
@@ -993,10 +995,7 @@ static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
993 char sympltname[1024]; 995 char sympltname[1024];
994 Elf *elf; 996 Elf *elf;
995 int nr = 0, symidx, fd, err = 0; 997 int nr = 0, symidx, fd, err = 0;
996 char name[PATH_MAX];
997 998
998 snprintf(name, sizeof(name), "%s%s",
999 symbol_conf.symfs, dso->long_name);
1000 fd = open(name, O_RDONLY); 999 fd = open(name, O_RDONLY);
1001 if (fd < 0) 1000 if (fd < 0)
1002 goto out; 1001 goto out;
@@ -1158,6 +1157,33 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
1158 return -1; 1157 return -1;
1159} 1158}
1160 1159
1160static int dso__swap_init(struct dso *dso, unsigned char eidata)
1161{
1162 static unsigned int const endian = 1;
1163
1164 dso->needs_swap = DSO_SWAP__NO;
1165
1166 switch (eidata) {
1167 case ELFDATA2LSB:
1168 /* We are big endian, DSO is little endian. */
1169 if (*(unsigned char const *)&endian != 1)
1170 dso->needs_swap = DSO_SWAP__YES;
1171 break;
1172
1173 case ELFDATA2MSB:
1174 /* We are little endian, DSO is big endian. */
1175 if (*(unsigned char const *)&endian != 0)
1176 dso->needs_swap = DSO_SWAP__YES;
1177 break;
1178
1179 default:
1180 pr_err("unrecognized DSO data encoding %d\n", eidata);
1181 return -EINVAL;
1182 }
1183
1184 return 0;
1185}
1186
1161static int dso__load_sym(struct dso *dso, struct map *map, const char *name, 1187static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1162 int fd, symbol_filter_t filter, int kmodule, 1188 int fd, symbol_filter_t filter, int kmodule,
1163 int want_symtab) 1189 int want_symtab)
@@ -1189,6 +1215,9 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1189 goto out_elf_end; 1215 goto out_elf_end;
1190 } 1216 }
1191 1217
1218 if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
1219 goto out_elf_end;
1220
1192 /* Always reject images with a mismatched build-id: */ 1221 /* Always reject images with a mismatched build-id: */
1193 if (dso->has_build_id) { 1222 if (dso->has_build_id) {
1194 u8 build_id[BUILD_ID_SIZE]; 1223 u8 build_id[BUILD_ID_SIZE];
@@ -1274,7 +1303,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1274 if (opdsec && sym.st_shndx == opdidx) { 1303 if (opdsec && sym.st_shndx == opdidx) {
1275 u32 offset = sym.st_value - opdshdr.sh_addr; 1304 u32 offset = sym.st_value - opdshdr.sh_addr;
1276 u64 *opd = opddata->d_buf + offset; 1305 u64 *opd = opddata->d_buf + offset;
1277 sym.st_value = *opd; 1306 sym.st_value = DSO__SWAP(dso, u64, *opd);
1278 sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 1307 sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
1279 } 1308 }
1280 1309
@@ -1703,8 +1732,9 @@ restart:
1703 continue; 1732 continue;
1704 1733
1705 if (ret > 0) { 1734 if (ret > 0) {
1706 int nr_plt = dso__synthesize_plt_symbols(dso, map, 1735 int nr_plt;
1707 filter); 1736
1737 nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter);
1708 if (nr_plt > 0) 1738 if (nr_plt > 0)
1709 ret += nr_plt; 1739 ret += nr_plt;
1710 break; 1740 break;
@@ -2784,3 +2814,14 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
2784 2814
2785 return ret; 2815 return ret;
2786} 2816}
2817
2818struct map *dso__new_map(const char *name)
2819{
2820 struct map *map = NULL;
2821 struct dso *dso = dso__new(name);
2822
2823 if (dso)
2824 map = map__new2(0, dso, MAP__FUNCTION);
2825
2826 return map;
2827}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ac49ef208a5f..af0752b1aca1 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -9,6 +9,7 @@
9#include <linux/list.h> 9#include <linux/list.h>
10#include <linux/rbtree.h> 10#include <linux/rbtree.h>
11#include <stdio.h> 11#include <stdio.h>
12#include <byteswap.h>
12 13
13#ifdef HAVE_CPLUS_DEMANGLE 14#ifdef HAVE_CPLUS_DEMANGLE
14extern char *cplus_demangle(const char *, int); 15extern char *cplus_demangle(const char *, int);
@@ -65,6 +66,11 @@ struct symbol {
65 66
66void symbol__delete(struct symbol *sym); 67void symbol__delete(struct symbol *sym);
67 68
69static inline size_t symbol__size(const struct symbol *sym)
70{
71 return sym->end - sym->start + 1;
72}
73
68struct strlist; 74struct strlist;
69 75
70struct symbol_conf { 76struct symbol_conf {
@@ -155,11 +161,18 @@ enum dso_kernel_type {
155 DSO_TYPE_GUEST_KERNEL 161 DSO_TYPE_GUEST_KERNEL
156}; 162};
157 163
164enum dso_swap_type {
165 DSO_SWAP__UNSET,
166 DSO_SWAP__NO,
167 DSO_SWAP__YES,
168};
169
158struct dso { 170struct dso {
159 struct list_head node; 171 struct list_head node;
160 struct rb_root symbols[MAP__NR_TYPES]; 172 struct rb_root symbols[MAP__NR_TYPES];
161 struct rb_root symbol_names[MAP__NR_TYPES]; 173 struct rb_root symbol_names[MAP__NR_TYPES];
162 enum dso_kernel_type kernel; 174 enum dso_kernel_type kernel;
175 enum dso_swap_type needs_swap;
163 u8 adjust_symbols:1; 176 u8 adjust_symbols:1;
164 u8 has_build_id:1; 177 u8 has_build_id:1;
165 u8 hit:1; 178 u8 hit:1;
@@ -177,6 +190,28 @@ struct dso {
177 char name[0]; 190 char name[0];
178}; 191};
179 192
193#define DSO__SWAP(dso, type, val) \
194({ \
195 type ____r = val; \
196 BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \
197 if (dso->needs_swap == DSO_SWAP__YES) { \
198 switch (sizeof(____r)) { \
199 case 2: \
200 ____r = bswap_16(val); \
201 break; \
202 case 4: \
203 ____r = bswap_32(val); \
204 break; \
205 case 8: \
206 ____r = bswap_64(val); \
207 break; \
208 default: \
209 BUG_ON(1); \
210 } \
211 } \
212 ____r; \
213})
214
180struct dso *dso__new(const char *name); 215struct dso *dso__new(const char *name);
181void dso__delete(struct dso *dso); 216void dso__delete(struct dso *dso);
182 217
@@ -237,6 +272,7 @@ void dso__set_long_name(struct dso *dso, char *name);
237void dso__set_build_id(struct dso *dso, void *build_id); 272void dso__set_build_id(struct dso *dso, void *build_id);
238void dso__read_running_kernel_build_id(struct dso *dso, 273void dso__read_running_kernel_build_id(struct dso *dso,
239 struct machine *machine); 274 struct machine *machine);
275struct map *dso__new_map(const char *name);
240struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, 276struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
241 u64 addr); 277 u64 addr);
242struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 278struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
new file mode 100644
index 000000000000..1064d5b148ad
--- /dev/null
+++ b/tools/perf/util/target.c
@@ -0,0 +1,142 @@
1/*
2 * Helper functions for handling target threads/cpus
3 *
4 * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@lge.com>
5 *
6 * Released under the GPL v2.
7 */
8
9#include "target.h"
10#include "debug.h"
11
12#include <pwd.h>
13#include <string.h>
14
15
16enum perf_target_errno perf_target__validate(struct perf_target *target)
17{
18 enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS;
19
20 if (target->pid)
21 target->tid = target->pid;
22
23 /* CPU and PID are mutually exclusive */
24 if (target->tid && target->cpu_list) {
25 target->cpu_list = NULL;
26 if (ret == PERF_ERRNO_TARGET__SUCCESS)
27 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU;
28 }
29
30 /* UID and PID are mutually exclusive */
31 if (target->tid && target->uid_str) {
32 target->uid_str = NULL;
33 if (ret == PERF_ERRNO_TARGET__SUCCESS)
34 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID;
35 }
36
37 /* UID and CPU are mutually exclusive */
38 if (target->uid_str && target->cpu_list) {
39 target->cpu_list = NULL;
40 if (ret == PERF_ERRNO_TARGET__SUCCESS)
41 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU;
42 }
43
44 /* PID and SYSTEM are mutually exclusive */
45 if (target->tid && target->system_wide) {
46 target->system_wide = false;
47 if (ret == PERF_ERRNO_TARGET__SUCCESS)
48 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM;
49 }
50
51 /* UID and SYSTEM are mutually exclusive */
52 if (target->uid_str && target->system_wide) {
53 target->system_wide = false;
54 if (ret == PERF_ERRNO_TARGET__SUCCESS)
55 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM;
56 }
57
58 return ret;
59}
60
61enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
62{
63 struct passwd pwd, *result;
64 char buf[1024];
65 const char *str = target->uid_str;
66
67 target->uid = UINT_MAX;
68 if (str == NULL)
69 return PERF_ERRNO_TARGET__SUCCESS;
70
71 /* Try user name first */
72 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
73
74 if (result == NULL) {
75 /*
76 * The user name not found. Maybe it's a UID number.
77 */
78 char *endptr;
79 int uid = strtol(str, &endptr, 10);
80
81 if (*endptr != '\0')
82 return PERF_ERRNO_TARGET__INVALID_UID;
83
84 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
85
86 if (result == NULL)
87 return PERF_ERRNO_TARGET__USER_NOT_FOUND;
88 }
89
90 target->uid = result->pw_uid;
91 return PERF_ERRNO_TARGET__SUCCESS;
92}
93
94/*
95 * This must have a same ordering as the enum perf_target_errno.
96 */
97static const char *perf_target__error_str[] = {
98 "PID/TID switch overriding CPU",
99 "PID/TID switch overriding UID",
100 "UID switch overriding CPU",
101 "PID/TID switch overriding SYSTEM",
102 "UID switch overriding SYSTEM",
103 "Invalid User: %s",
104 "Problems obtaining information for user %s",
105};
106
107int perf_target__strerror(struct perf_target *target, int errnum,
108 char *buf, size_t buflen)
109{
110 int idx;
111 const char *msg;
112
113 if (errnum >= 0) {
114 strerror_r(errnum, buf, buflen);
115 return 0;
116 }
117
118 if (errnum < __PERF_ERRNO_TARGET__START ||
119 errnum >= __PERF_ERRNO_TARGET__END)
120 return -1;
121
122 idx = errnum - __PERF_ERRNO_TARGET__START;
123 msg = perf_target__error_str[idx];
124
125 switch (errnum) {
126 case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU
127 ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
128 snprintf(buf, buflen, "%s", msg);
129 break;
130
131 case PERF_ERRNO_TARGET__INVALID_UID:
132 case PERF_ERRNO_TARGET__USER_NOT_FOUND:
133 snprintf(buf, buflen, msg, target->uid_str);
134 break;
135
136 default:
137 /* cannot reach here */
138 break;
139 }
140
141 return 0;
142}
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
new file mode 100644
index 000000000000..a4be8575fda5
--- /dev/null
+++ b/tools/perf/util/target.h
@@ -0,0 +1,65 @@
1#ifndef _PERF_TARGET_H
2#define _PERF_TARGET_H
3
4#include <stdbool.h>
5#include <sys/types.h>
6
7struct perf_target {
8 const char *pid;
9 const char *tid;
10 const char *cpu_list;
11 const char *uid_str;
12 uid_t uid;
13 bool system_wide;
14 bool uses_mmap;
15};
16
17enum perf_target_errno {
18 PERF_ERRNO_TARGET__SUCCESS = 0,
19
20 /*
21 * Choose an arbitrary negative big number not to clash with standard
22 * errno since SUS requires the errno has distinct positive values.
23 * See 'Issue 6' in the link below.
24 *
25 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
26 */
27 __PERF_ERRNO_TARGET__START = -10000,
28
29
30 /* for perf_target__validate() */
31 PERF_ERRNO_TARGET__PID_OVERRIDE_CPU = __PERF_ERRNO_TARGET__START,
32 PERF_ERRNO_TARGET__PID_OVERRIDE_UID,
33 PERF_ERRNO_TARGET__UID_OVERRIDE_CPU,
34 PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM,
35 PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM,
36
37 /* for perf_target__parse_uid() */
38 PERF_ERRNO_TARGET__INVALID_UID,
39 PERF_ERRNO_TARGET__USER_NOT_FOUND,
40
41 __PERF_ERRNO_TARGET__END,
42};
43
44enum perf_target_errno perf_target__validate(struct perf_target *target);
45enum perf_target_errno perf_target__parse_uid(struct perf_target *target);
46
47int perf_target__strerror(struct perf_target *target, int errnum, char *buf,
48 size_t buflen);
49
50static inline bool perf_target__has_task(struct perf_target *target)
51{
52 return target->tid || target->pid || target->uid_str;
53}
54
55static inline bool perf_target__has_cpu(struct perf_target *target)
56{
57 return target->system_wide || target->cpu_list;
58}
59
60static inline bool perf_target__none(struct perf_target *target)
61{
62 return !perf_target__has_task(target) && !perf_target__has_cpu(target);
63}
64
65#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 84d9bd782004..9b5f856cc280 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -188,28 +188,27 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
188 nt = realloc(threads, (sizeof(*threads) + 188 nt = realloc(threads, (sizeof(*threads) +
189 sizeof(pid_t) * total_tasks)); 189 sizeof(pid_t) * total_tasks));
190 if (nt == NULL) 190 if (nt == NULL)
191 goto out_free_threads; 191 goto out_free_namelist;
192 192
193 threads = nt; 193 threads = nt;
194 194
195 if (threads) { 195 for (i = 0; i < items; i++) {
196 for (i = 0; i < items; i++) 196 threads->map[j++] = atoi(namelist[i]->d_name);
197 threads->map[j++] = atoi(namelist[i]->d_name);
198 threads->nr = total_tasks;
199 }
200
201 for (i = 0; i < items; i++)
202 free(namelist[i]); 197 free(namelist[i]);
198 }
199 threads->nr = total_tasks;
203 free(namelist); 200 free(namelist);
204
205 if (!threads)
206 break;
207 } 201 }
208 202
209out: 203out:
210 strlist__delete(slist); 204 strlist__delete(slist);
211 return threads; 205 return threads;
212 206
207out_free_namelist:
208 for (i = 0; i < items; i++)
209 free(namelist[i]);
210 free(namelist);
211
213out_free_threads: 212out_free_threads:
214 free(threads); 213 free(threads);
215 threads = NULL; 214 threads = NULL;
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 7da80f14418b..f718df8a3c59 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -6,7 +6,7 @@
6 6
7struct thread_map { 7struct thread_map {
8 int nr; 8 int nr;
9 int map[]; 9 pid_t map[];
10}; 10};
11 11
12struct thread_map *thread_map__new_by_pid(pid_t pid); 12struct thread_map *thread_map__new_by_pid(pid_t pid);
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 09fe579ccafb..abe0e8e95068 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -69,23 +69,24 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
69 69
70 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
71 71
72 if (top->target_pid) 72 if (top->target.pid)
73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", 73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
74 top->target_pid); 74 top->target.pid);
75 else if (top->target_tid) 75 else if (top->target.tid)
76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", 76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
77 top->target_tid); 77 top->target.tid);
78 else if (top->uid_str != NULL) 78 else if (top->target.uid_str != NULL)
79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", 79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
80 top->uid_str); 80 top->target.uid_str);
81 else 81 else
82 ret += SNPRINTF(bf + ret, size - ret, " (all"); 82 ret += SNPRINTF(bf + ret, size - ret, " (all");
83 83
84 if (top->cpu_list) 84 if (top->target.cpu_list)
85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
86 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); 86 top->evlist->cpus->nr > 1 ? "s" : "",
87 top->target.cpu_list);
87 else { 88 else {
88 if (top->target_tid) 89 if (top->target.tid)
89 ret += SNPRINTF(bf + ret, size - ret, ")"); 90 ret += SNPRINTF(bf + ret, size - ret, ")");
90 else 91 else
91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 92 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index ce61cb2d1acf..33347ca89ee4 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -13,6 +13,7 @@ struct perf_session;
13struct perf_top { 13struct perf_top {
14 struct perf_tool tool; 14 struct perf_tool tool;
15 struct perf_evlist *evlist; 15 struct perf_evlist *evlist;
16 struct perf_target target;
16 /* 17 /*
17 * Symbols will be added here in perf_event__process_sample and will 18 * Symbols will be added here in perf_event__process_sample and will
18 * get out after decayed. 19 * get out after decayed.
@@ -23,10 +24,7 @@ struct perf_top {
23 u64 guest_us_samples, guest_kernel_samples; 24 u64 guest_us_samples, guest_kernel_samples;
24 int print_entries, count_filter, delay_secs; 25 int print_entries, count_filter, delay_secs;
25 int freq; 26 int freq;
26 const char *target_pid, *target_tid;
27 uid_t uid;
28 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
29 bool system_wide;
30 bool use_tui, use_stdio; 28 bool use_tui, use_stdio;
31 bool sort_has_symbols; 29 bool sort_has_symbols;
32 bool dont_use_callchains; 30 bool dont_use_callchains;
@@ -37,7 +35,6 @@ struct perf_top {
37 bool sample_id_all_missing; 35 bool sample_id_all_missing;
38 bool exclude_guest_missing; 36 bool exclude_guest_missing;
39 bool dump_symtab; 37 bool dump_symtab;
40 const char *cpu_list;
41 struct hist_entry *sym_filter_entry; 38 struct hist_entry *sym_filter_entry;
42 struct perf_evsel *sym_evsel; 39 struct perf_evsel *sym_evsel;
43 struct perf_session *session; 40 struct perf_session *session;
@@ -47,7 +44,6 @@ struct perf_top {
47 int realtime_prio; 44 int realtime_prio;
48 int sym_pcnt_filter; 45 int sym_pcnt_filter;
49 const char *sym_filter; 46 const char *sym_filter;
50 const char *uid_str;
51}; 47};
52 48
53size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 49size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index fc22cf5c605f..a8d81c35ef66 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -68,7 +68,7 @@ struct events {
68}; 68};
69 69
70 70
71void *malloc_or_die(unsigned int size) 71static void *malloc_or_die(unsigned int size)
72{ 72{
73 void *data; 73 void *data;
74 74
@@ -448,6 +448,8 @@ static void tracing_data_header(void)
448 else 448 else
449 buf[0] = 0; 449 buf[0] = 0;
450 450
451 read_trace_init(buf[0], buf[0]);
452
451 write_or_die(buf, 1); 453 write_or_die(buf, 1);
452 454
453 /* save size of long */ 455 /* save size of long */
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index dfd1bd8371a4..df2fddbf0cd2 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -17,2169 +17,305 @@
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 *
21 * The parts for function graph printing was taken and modified from the
22 * Linux Kernel that were written by Frederic Weisbecker.
23 */ 20 */
24
25#include <stdio.h> 21#include <stdio.h>
26#include <stdlib.h> 22#include <stdlib.h>
27#include <string.h> 23#include <string.h>
24#include <ctype.h>
28#include <errno.h> 25#include <errno.h>
29 26
30#include "../perf.h" 27#include "../perf.h"
31#include "util.h" 28#include "util.h"
32#include "trace-event.h" 29#include "trace-event.h"
33 30
34int header_page_ts_offset;
35int header_page_ts_size;
36int header_page_size_offset;
37int header_page_size_size; 31int header_page_size_size;
38int header_page_overwrite_offset; 32int header_page_ts_size;
39int header_page_overwrite_size;
40int header_page_data_offset; 33int header_page_data_offset;
41int header_page_data_size;
42
43bool latency_format;
44
45static char *input_buf;
46static unsigned long long input_buf_ptr;
47static unsigned long long input_buf_siz;
48
49static int cpus;
50static int long_size;
51static int is_flag_field;
52static int is_symbolic_field;
53
54static struct format_field *
55find_any_field(struct event *event, const char *name);
56
57static void init_input_buf(char *buf, unsigned long long size)
58{
59 input_buf = buf;
60 input_buf_siz = size;
61 input_buf_ptr = 0;
62}
63
64struct cmdline {
65 char *comm;
66 int pid;
67};
68
69static struct cmdline *cmdlines;
70static int cmdline_count;
71
72static int cmdline_cmp(const void *a, const void *b)
73{
74 const struct cmdline *ca = a;
75 const struct cmdline *cb = b;
76
77 if (ca->pid < cb->pid)
78 return -1;
79 if (ca->pid > cb->pid)
80 return 1;
81
82 return 0;
83}
84 34
85void parse_cmdlines(char *file, int size __unused) 35struct pevent *perf_pevent;
86{ 36static struct pevent *pevent;
87 struct cmdline_list {
88 struct cmdline_list *next;
89 char *comm;
90 int pid;
91 } *list = NULL, *item;
92 char *line;
93 char *next = NULL;
94 int i;
95 37
96 line = strtok_r(file, "\n", &next); 38bool latency_format;
97 while (line) {
98 item = malloc_or_die(sizeof(*item));
99 sscanf(line, "%d %as", &item->pid,
100 (float *)(void *)&item->comm); /* workaround gcc warning */
101 item->next = list;
102 list = item;
103 line = strtok_r(NULL, "\n", &next);
104 cmdline_count++;
105 }
106
107 cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
108
109 i = 0;
110 while (list) {
111 cmdlines[i].pid = list->pid;
112 cmdlines[i].comm = list->comm;
113 i++;
114 item = list;
115 list = list->next;
116 free(item);
117 }
118
119 qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
120}
121
122static struct func_map {
123 unsigned long long addr;
124 char *func;
125 char *mod;
126} *func_list;
127static unsigned int func_count;
128
129static int func_cmp(const void *a, const void *b)
130{
131 const struct func_map *fa = a;
132 const struct func_map *fb = b;
133
134 if (fa->addr < fb->addr)
135 return -1;
136 if (fa->addr > fb->addr)
137 return 1;
138
139 return 0;
140}
141
142void parse_proc_kallsyms(char *file, unsigned int size __unused)
143{
144 struct func_list {
145 struct func_list *next;
146 unsigned long long addr;
147 char *func;
148 char *mod;
149 } *list = NULL, *item;
150 char *line;
151 char *next = NULL;
152 char *addr_str;
153 char ch;
154 int ret __used;
155 int i;
156
157 line = strtok_r(file, "\n", &next);
158 while (line) {
159 item = malloc_or_die(sizeof(*item));
160 item->mod = NULL;
161 ret = sscanf(line, "%as %c %as\t[%as",
162 (float *)(void *)&addr_str, /* workaround gcc warning */
163 &ch,
164 (float *)(void *)&item->func,
165 (float *)(void *)&item->mod);
166 item->addr = strtoull(addr_str, NULL, 16);
167 free(addr_str);
168
169 /* truncate the extra ']' */
170 if (item->mod)
171 item->mod[strlen(item->mod) - 1] = 0;
172
173
174 item->next = list;
175 list = item;
176 line = strtok_r(NULL, "\n", &next);
177 func_count++;
178 }
179
180 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
181
182 i = 0;
183 while (list) {
184 func_list[i].func = list->func;
185 func_list[i].addr = list->addr;
186 func_list[i].mod = list->mod;
187 i++;
188 item = list;
189 list = list->next;
190 free(item);
191 }
192
193 qsort(func_list, func_count, sizeof(*func_list), func_cmp);
194
195 /*
196 * Add a special record at the end.
197 */
198 func_list[func_count].func = NULL;
199 func_list[func_count].addr = 0;
200 func_list[func_count].mod = NULL;
201}
202 39
203/* 40int read_trace_init(int file_bigendian, int host_bigendian)
204 * We are searching for a record in between, not an exact
205 * match.
206 */
207static int func_bcmp(const void *a, const void *b)
208{ 41{
209 const struct func_map *fa = a; 42 if (pevent)
210 const struct func_map *fb = b;
211
212 if ((fa->addr == fb->addr) ||
213
214 (fa->addr > fb->addr &&
215 fa->addr < (fb+1)->addr))
216 return 0; 43 return 0;
217 44
218 if (fa->addr < fb->addr) 45 perf_pevent = pevent_alloc();
219 return -1; 46 pevent = perf_pevent;
220
221 return 1;
222}
223
224static struct func_map *find_func(unsigned long long addr)
225{
226 struct func_map *func;
227 struct func_map key;
228
229 key.addr = addr;
230
231 func = bsearch(&key, func_list, func_count, sizeof(*func_list),
232 func_bcmp);
233
234 return func;
235}
236
237void print_funcs(void)
238{
239 int i;
240
241 for (i = 0; i < (int)func_count; i++) {
242 printf("%016llx %s",
243 func_list[i].addr,
244 func_list[i].func);
245 if (func_list[i].mod)
246 printf(" [%s]\n", func_list[i].mod);
247 else
248 printf("\n");
249 }
250}
251 47
252static struct printk_map { 48 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
253 unsigned long long addr; 49 pevent_set_file_bigendian(pevent, file_bigendian);
254 char *printk; 50 pevent_set_host_bigendian(pevent, host_bigendian);
255} *printk_list;
256static unsigned int printk_count;
257
258static int printk_cmp(const void *a, const void *b)
259{
260 const struct func_map *fa = a;
261 const struct func_map *fb = b;
262
263 if (fa->addr < fb->addr)
264 return -1;
265 if (fa->addr > fb->addr)
266 return 1;
267 51
268 return 0; 52 return 0;
269} 53}
270 54
271static struct printk_map *find_printk(unsigned long long addr) 55static int get_common_field(struct scripting_context *context,
272{ 56 int *offset, int *size, const char *type)
273 struct printk_map *printk;
274 struct printk_map key;
275
276 key.addr = addr;
277
278 printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
279 printk_cmp);
280
281 return printk;
282}
283
284void parse_ftrace_printk(char *file, unsigned int size __unused)
285{
286 struct printk_list {
287 struct printk_list *next;
288 unsigned long long addr;
289 char *printk;
290 } *list = NULL, *item;
291 char *line;
292 char *next = NULL;
293 char *addr_str;
294 int i;
295
296 line = strtok_r(file, "\n", &next);
297 while (line) {
298 addr_str = strsep(&line, ":");
299 if (!line) {
300 warning("error parsing print strings");
301 break;
302 }
303 item = malloc_or_die(sizeof(*item));
304 item->addr = strtoull(addr_str, NULL, 16);
305 /* fmt still has a space, skip it */
306 item->printk = strdup(line+1);
307 item->next = list;
308 list = item;
309 line = strtok_r(NULL, "\n", &next);
310 printk_count++;
311 }
312
313 printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
314
315 i = 0;
316 while (list) {
317 printk_list[i].printk = list->printk;
318 printk_list[i].addr = list->addr;
319 i++;
320 item = list;
321 list = list->next;
322 free(item);
323 }
324
325 qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
326}
327
328void print_printk(void)
329{
330 int i;
331
332 for (i = 0; i < (int)printk_count; i++) {
333 printf("%016llx %s\n",
334 printk_list[i].addr,
335 printk_list[i].printk);
336 }
337}
338
339static struct event *alloc_event(void)
340{
341 struct event *event;
342
343 event = malloc_or_die(sizeof(*event));
344 memset(event, 0, sizeof(*event));
345
346 return event;
347}
348
349enum event_type {
350 EVENT_ERROR,
351 EVENT_NONE,
352 EVENT_SPACE,
353 EVENT_NEWLINE,
354 EVENT_OP,
355 EVENT_DELIM,
356 EVENT_ITEM,
357 EVENT_DQUOTE,
358 EVENT_SQUOTE,
359};
360
361static struct event *event_list;
362
363static void add_event(struct event *event)
364{ 57{
365 event->next = event_list; 58 struct event_format *event;
366 event_list = event; 59 struct format_field *field;
367}
368
369static int event_item_type(enum event_type type)
370{
371 switch (type) {
372 case EVENT_ITEM ... EVENT_SQUOTE:
373 return 1;
374 case EVENT_ERROR ... EVENT_DELIM:
375 default:
376 return 0;
377 }
378}
379
380static void free_arg(struct print_arg *arg)
381{
382 if (!arg)
383 return;
384
385 switch (arg->type) {
386 case PRINT_ATOM:
387 if (arg->atom.atom)
388 free(arg->atom.atom);
389 break;
390 case PRINT_NULL:
391 case PRINT_FIELD ... PRINT_OP:
392 default:
393 /* todo */
394 break;
395 }
396
397 free(arg);
398}
399
400static enum event_type get_type(int ch)
401{
402 if (ch == '\n')
403 return EVENT_NEWLINE;
404 if (isspace(ch))
405 return EVENT_SPACE;
406 if (isalnum(ch) || ch == '_')
407 return EVENT_ITEM;
408 if (ch == '\'')
409 return EVENT_SQUOTE;
410 if (ch == '"')
411 return EVENT_DQUOTE;
412 if (!isprint(ch))
413 return EVENT_NONE;
414 if (ch == '(' || ch == ')' || ch == ',')
415 return EVENT_DELIM;
416
417 return EVENT_OP;
418}
419
420static int __read_char(void)
421{
422 if (input_buf_ptr >= input_buf_siz)
423 return -1;
424
425 return input_buf[input_buf_ptr++];
426}
427
428static int __peek_char(void)
429{
430 if (input_buf_ptr >= input_buf_siz)
431 return -1;
432
433 return input_buf[input_buf_ptr];
434}
435
436static enum event_type __read_token(char **tok)
437{
438 char buf[BUFSIZ];
439 int ch, last_ch, quote_ch, next_ch;
440 int i = 0;
441 int tok_size = 0;
442 enum event_type type;
443
444 *tok = NULL;
445
446
447 ch = __read_char();
448 if (ch < 0)
449 return EVENT_NONE;
450
451 type = get_type(ch);
452 if (type == EVENT_NONE)
453 return type;
454
455 buf[i++] = ch;
456
457 switch (type) {
458 case EVENT_NEWLINE:
459 case EVENT_DELIM:
460 *tok = malloc_or_die(2);
461 (*tok)[0] = ch;
462 (*tok)[1] = 0;
463 return type;
464
465 case EVENT_OP:
466 switch (ch) {
467 case '-':
468 next_ch = __peek_char();
469 if (next_ch == '>') {
470 buf[i++] = __read_char();
471 break;
472 }
473 /* fall through */
474 case '+':
475 case '|':
476 case '&':
477 case '>':
478 case '<':
479 last_ch = ch;
480 ch = __peek_char();
481 if (ch != last_ch)
482 goto test_equal;
483 buf[i++] = __read_char();
484 switch (last_ch) {
485 case '>':
486 case '<':
487 goto test_equal;
488 default:
489 break;
490 }
491 break;
492 case '!':
493 case '=':
494 goto test_equal;
495 default: /* what should we do instead? */
496 break;
497 }
498 buf[i] = 0;
499 *tok = strdup(buf);
500 return type;
501
502 test_equal:
503 ch = __peek_char();
504 if (ch == '=')
505 buf[i++] = __read_char();
506 break;
507
508 case EVENT_DQUOTE:
509 case EVENT_SQUOTE:
510 /* don't keep quotes */
511 i--;
512 quote_ch = ch;
513 last_ch = 0;
514 do {
515 if (i == (BUFSIZ - 1)) {
516 buf[i] = 0;
517 if (*tok) {
518 *tok = realloc(*tok, tok_size + BUFSIZ);
519 if (!*tok)
520 return EVENT_NONE;
521 strcat(*tok, buf);
522 } else
523 *tok = strdup(buf);
524
525 if (!*tok)
526 return EVENT_NONE;
527 tok_size += BUFSIZ;
528 i = 0;
529 }
530 last_ch = ch;
531 ch = __read_char();
532 buf[i++] = ch;
533 /* the '\' '\' will cancel itself */
534 if (ch == '\\' && last_ch == '\\')
535 last_ch = 0;
536 } while (ch != quote_ch || last_ch == '\\');
537 /* remove the last quote */
538 i--;
539 goto out;
540
541 case EVENT_ERROR ... EVENT_SPACE:
542 case EVENT_ITEM:
543 default:
544 break;
545 }
546
547 while (get_type(__peek_char()) == type) {
548 if (i == (BUFSIZ - 1)) {
549 buf[i] = 0;
550 if (*tok) {
551 *tok = realloc(*tok, tok_size + BUFSIZ);
552 if (!*tok)
553 return EVENT_NONE;
554 strcat(*tok, buf);
555 } else
556 *tok = strdup(buf);
557
558 if (!*tok)
559 return EVENT_NONE;
560 tok_size += BUFSIZ;
561 i = 0;
562 }
563 ch = __read_char();
564 buf[i++] = ch;
565 }
566
567 out:
568 buf[i] = 0;
569 if (*tok) {
570 *tok = realloc(*tok, tok_size + i);
571 if (!*tok)
572 return EVENT_NONE;
573 strcat(*tok, buf);
574 } else
575 *tok = strdup(buf);
576 if (!*tok)
577 return EVENT_NONE;
578
579 return type;
580}
581
582static void free_token(char *tok)
583{
584 if (tok)
585 free(tok);
586}
587
588static enum event_type read_token(char **tok)
589{
590 enum event_type type;
591
592 for (;;) {
593 type = __read_token(tok);
594 if (type != EVENT_SPACE)
595 return type;
596
597 free_token(*tok);
598 }
599
600 /* not reached */
601 return EVENT_NONE;
602}
603
604/* no newline */
605static enum event_type read_token_item(char **tok)
606{
607 enum event_type type;
608
609 for (;;) {
610 type = __read_token(tok);
611 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
612 return type;
613
614 free_token(*tok);
615 }
616
617 /* not reached */
618 return EVENT_NONE;
619}
620
621static int test_type(enum event_type type, enum event_type expect)
622{
623 if (type != expect) {
624 warning("Error: expected type %d but read %d",
625 expect, type);
626 return -1;
627 }
628 return 0;
629}
630 60
631static int __test_type_token(enum event_type type, char *token, 61 if (!*size) {
632 enum event_type expect, const char *expect_tok, 62 if (!pevent->events)
633 bool warn) 63 return 0;
634{
635 if (type != expect) {
636 if (warn)
637 warning("Error: expected type %d but read %d",
638 expect, type);
639 return -1;
640 }
641 64
642 if (strcmp(token, expect_tok) != 0) { 65 event = pevent->events[0];
643 if (warn) 66 field = pevent_find_common_field(event, type);
644 warning("Error: expected '%s' but read '%s'", 67 if (!field)
645 expect_tok, token); 68 return 0;
646 return -1; 69 *offset = field->offset;
70 *size = field->size;
647 } 71 }
648 return 0;
649}
650 72
651static int test_type_token(enum event_type type, char *token, 73 return pevent_read_number(pevent, context->event_data + *offset, *size);
652 enum event_type expect, const char *expect_tok)
653{
654 return __test_type_token(type, token, expect, expect_tok, true);
655} 74}
656 75
657static int __read_expect_type(enum event_type expect, char **tok, int newline_ok) 76int common_lock_depth(struct scripting_context *context)
658{
659 enum event_type type;
660
661 if (newline_ok)
662 type = read_token(tok);
663 else
664 type = read_token_item(tok);
665 return test_type(type, expect);
666}
667
668static int read_expect_type(enum event_type expect, char **tok)
669{
670 return __read_expect_type(expect, tok, 1);
671}
672
673static int __read_expected(enum event_type expect, const char *str,
674 int newline_ok, bool warn)
675{ 77{
676 enum event_type type; 78 static int offset;
677 char *token; 79 static int size;
678 int ret; 80 int ret;
679 81
680 if (newline_ok) 82 ret = get_common_field(context, &size, &offset,
681 type = read_token(&token); 83 "common_lock_depth");
682 else 84 if (ret < 0)
683 type = read_token_item(&token); 85 return -1;
684
685 ret = __test_type_token(type, token, expect, str, warn);
686
687 free_token(token);
688 86
689 return ret; 87 return ret;
690} 88}
691 89
692static int read_expected(enum event_type expect, const char *str) 90int common_flags(struct scripting_context *context)
693{
694 return __read_expected(expect, str, 1, true);
695}
696
697static int read_expected_item(enum event_type expect, const char *str)
698{
699 return __read_expected(expect, str, 0, true);
700}
701
702static char *event_read_name(void)
703{
704 char *token;
705
706 if (read_expected(EVENT_ITEM, "name") < 0)
707 return NULL;
708
709 if (read_expected(EVENT_OP, ":") < 0)
710 return NULL;
711
712 if (read_expect_type(EVENT_ITEM, &token) < 0)
713 goto fail;
714
715 return token;
716
717 fail:
718 free_token(token);
719 return NULL;
720}
721
722static int event_read_id(void)
723{ 91{
724 char *token; 92 static int offset;
725 int id = -1; 93 static int size;
726 94 int ret;
727 if (read_expected_item(EVENT_ITEM, "ID") < 0)
728 return -1;
729 95
730 if (read_expected(EVENT_OP, ":") < 0) 96 ret = get_common_field(context, &size, &offset,
97 "common_flags");
98 if (ret < 0)
731 return -1; 99 return -1;
732 100
733 if (read_expect_type(EVENT_ITEM, &token) < 0) 101 return ret;
734 goto free;
735
736 id = strtoul(token, NULL, 0);
737
738 free:
739 free_token(token);
740 return id;
741}
742
743static int field_is_string(struct format_field *field)
744{
745 if ((field->flags & FIELD_IS_ARRAY) &&
746 (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
747 !strstr(field->type, "s8")))
748 return 1;
749
750 return 0;
751}
752
753static int field_is_dynamic(struct format_field *field)
754{
755 if (!strncmp(field->type, "__data_loc", 10))
756 return 1;
757
758 return 0;
759}
760
761static int event_read_fields(struct event *event, struct format_field **fields)
762{
763 struct format_field *field = NULL;
764 enum event_type type;
765 char *token;
766 char *last_token;
767 int count = 0;
768
769 do {
770 type = read_token(&token);
771 if (type == EVENT_NEWLINE) {
772 free_token(token);
773 return count;
774 }
775
776 count++;
777
778 if (test_type_token(type, token, EVENT_ITEM, "field"))
779 goto fail;
780 free_token(token);
781
782 type = read_token(&token);
783 /*
784 * The ftrace fields may still use the "special" name.
785 * Just ignore it.
786 */
787 if (event->flags & EVENT_FL_ISFTRACE &&
788 type == EVENT_ITEM && strcmp(token, "special") == 0) {
789 free_token(token);
790 type = read_token(&token);
791 }
792
793 if (test_type_token(type, token, EVENT_OP, ":") < 0)
794 return -1;
795
796 if (read_expect_type(EVENT_ITEM, &token) < 0)
797 goto fail;
798
799 last_token = token;
800
801 field = malloc_or_die(sizeof(*field));
802 memset(field, 0, sizeof(*field));
803
804 /* read the rest of the type */
805 for (;;) {
806 type = read_token(&token);
807 if (type == EVENT_ITEM ||
808 (type == EVENT_OP && strcmp(token, "*") == 0) ||
809 /*
810 * Some of the ftrace fields are broken and have
811 * an illegal "." in them.
812 */
813 (event->flags & EVENT_FL_ISFTRACE &&
814 type == EVENT_OP && strcmp(token, ".") == 0)) {
815
816 if (strcmp(token, "*") == 0)
817 field->flags |= FIELD_IS_POINTER;
818
819 if (field->type) {
820 field->type = realloc(field->type,
821 strlen(field->type) +
822 strlen(last_token) + 2);
823 strcat(field->type, " ");
824 strcat(field->type, last_token);
825 } else
826 field->type = last_token;
827 last_token = token;
828 continue;
829 }
830
831 break;
832 }
833
834 if (!field->type) {
835 die("no type found");
836 goto fail;
837 }
838 field->name = last_token;
839
840 if (test_type(type, EVENT_OP))
841 goto fail;
842
843 if (strcmp(token, "[") == 0) {
844 enum event_type last_type = type;
845 char *brackets = token;
846 int len;
847
848 field->flags |= FIELD_IS_ARRAY;
849
850 type = read_token(&token);
851 while (strcmp(token, "]") != 0) {
852 if (last_type == EVENT_ITEM &&
853 type == EVENT_ITEM)
854 len = 2;
855 else
856 len = 1;
857 last_type = type;
858
859 brackets = realloc(brackets,
860 strlen(brackets) +
861 strlen(token) + len);
862 if (len == 2)
863 strcat(brackets, " ");
864 strcat(brackets, token);
865 free_token(token);
866 type = read_token(&token);
867 if (type == EVENT_NONE) {
868 die("failed to find token");
869 goto fail;
870 }
871 }
872
873 free_token(token);
874
875 brackets = realloc(brackets, strlen(brackets) + 2);
876 strcat(brackets, "]");
877
878 /* add brackets to type */
879
880 type = read_token(&token);
881 /*
882 * If the next token is not an OP, then it is of
883 * the format: type [] item;
884 */
885 if (type == EVENT_ITEM) {
886 field->type = realloc(field->type,
887 strlen(field->type) +
888 strlen(field->name) +
889 strlen(brackets) + 2);
890 strcat(field->type, " ");
891 strcat(field->type, field->name);
892 free_token(field->name);
893 strcat(field->type, brackets);
894 field->name = token;
895 type = read_token(&token);
896 } else {
897 field->type = realloc(field->type,
898 strlen(field->type) +
899 strlen(brackets) + 1);
900 strcat(field->type, brackets);
901 }
902 free(brackets);
903 }
904
905 if (field_is_string(field)) {
906 field->flags |= FIELD_IS_STRING;
907 if (field_is_dynamic(field))
908 field->flags |= FIELD_IS_DYNAMIC;
909 }
910
911 if (test_type_token(type, token, EVENT_OP, ";"))
912 goto fail;
913 free_token(token);
914
915 if (read_expected(EVENT_ITEM, "offset") < 0)
916 goto fail_expect;
917
918 if (read_expected(EVENT_OP, ":") < 0)
919 goto fail_expect;
920
921 if (read_expect_type(EVENT_ITEM, &token))
922 goto fail;
923 field->offset = strtoul(token, NULL, 0);
924 free_token(token);
925
926 if (read_expected(EVENT_OP, ";") < 0)
927 goto fail_expect;
928
929 if (read_expected(EVENT_ITEM, "size") < 0)
930 goto fail_expect;
931
932 if (read_expected(EVENT_OP, ":") < 0)
933 goto fail_expect;
934
935 if (read_expect_type(EVENT_ITEM, &token))
936 goto fail;
937 field->size = strtoul(token, NULL, 0);
938 free_token(token);
939
940 if (read_expected(EVENT_OP, ";") < 0)
941 goto fail_expect;
942
943 type = read_token(&token);
944 if (type != EVENT_NEWLINE) {
945 /* newer versions of the kernel have a "signed" type */
946 if (test_type_token(type, token, EVENT_ITEM, "signed"))
947 goto fail;
948
949 free_token(token);
950
951 if (read_expected(EVENT_OP, ":") < 0)
952 goto fail_expect;
953
954 if (read_expect_type(EVENT_ITEM, &token))
955 goto fail;
956
957 if (strtoul(token, NULL, 0))
958 field->flags |= FIELD_IS_SIGNED;
959
960 free_token(token);
961 if (read_expected(EVENT_OP, ";") < 0)
962 goto fail_expect;
963
964 if (read_expect_type(EVENT_NEWLINE, &token))
965 goto fail;
966 }
967
968 free_token(token);
969
970 *fields = field;
971 fields = &field->next;
972
973 } while (1);
974
975 return 0;
976
977fail:
978 free_token(token);
979fail_expect:
980 if (field)
981 free(field);
982 return -1;
983} 102}
984 103
985static int event_read_format(struct event *event) 104int common_pc(struct scripting_context *context)
986{ 105{
987 char *token; 106 static int offset;
107 static int size;
988 int ret; 108 int ret;
989 109
990 if (read_expected_item(EVENT_ITEM, "format") < 0) 110 ret = get_common_field(context, &size, &offset,
991 return -1; 111 "common_preempt_count");
992
993 if (read_expected(EVENT_OP, ":") < 0)
994 return -1;
995
996 if (read_expect_type(EVENT_NEWLINE, &token))
997 goto fail;
998 free_token(token);
999
1000 ret = event_read_fields(event, &event->format.common_fields);
1001 if (ret < 0) 112 if (ret < 0)
1002 return ret; 113 return -1;
1003 event->format.nr_common = ret;
1004
1005 ret = event_read_fields(event, &event->format.fields);
1006 if (ret < 0)
1007 return ret;
1008 event->format.nr_fields = ret;
1009
1010 return 0;
1011
1012 fail:
1013 free_token(token);
1014 return -1;
1015}
1016
1017enum event_type
1018process_arg_token(struct event *event, struct print_arg *arg,
1019 char **tok, enum event_type type);
1020
1021static enum event_type
1022process_arg(struct event *event, struct print_arg *arg, char **tok)
1023{
1024 enum event_type type;
1025 char *token;
1026
1027 type = read_token(&token);
1028 *tok = token;
1029 114
1030 return process_arg_token(event, arg, tok, type); 115 return ret;
1031} 116}
1032 117
1033static enum event_type 118unsigned long long
1034process_cond(struct event *event, struct print_arg *top, char **tok) 119raw_field_value(struct event_format *event, const char *name, void *data)
1035{ 120{
1036 struct print_arg *arg, *left, *right; 121 struct format_field *field;
1037 enum event_type type; 122 unsigned long long val;
1038 char *token = NULL;
1039
1040 arg = malloc_or_die(sizeof(*arg));
1041 memset(arg, 0, sizeof(*arg));
1042
1043 left = malloc_or_die(sizeof(*left));
1044
1045 right = malloc_or_die(sizeof(*right));
1046
1047 arg->type = PRINT_OP;
1048 arg->op.left = left;
1049 arg->op.right = right;
1050
1051 *tok = NULL;
1052 type = process_arg(event, left, &token);
1053 if (test_type_token(type, token, EVENT_OP, ":"))
1054 goto out_free;
1055
1056 arg->op.op = token;
1057
1058 type = process_arg(event, right, &token);
1059 123
1060 top->op.right = arg; 124 field = pevent_find_any_field(event, name);
125 if (!field)
126 return 0ULL;
1061 127
1062 *tok = token; 128 pevent_read_number_field(field, data, &val);
1063 return type;
1064 129
1065out_free: 130 return val;
1066 free_token(*tok);
1067 free(right);
1068 free(left);
1069 free_arg(arg);
1070 return EVENT_ERROR;
1071} 131}
1072 132
1073static enum event_type 133void *raw_field_ptr(struct event_format *event, const char *name, void *data)
1074process_array(struct event *event, struct print_arg *top, char **tok)
1075{ 134{
1076 struct print_arg *arg; 135 struct format_field *field;
1077 enum event_type type;
1078 char *token = NULL;
1079
1080 arg = malloc_or_die(sizeof(*arg));
1081 memset(arg, 0, sizeof(*arg));
1082
1083 *tok = NULL;
1084 type = process_arg(event, arg, &token);
1085 if (test_type_token(type, token, EVENT_OP, "]"))
1086 goto out_free;
1087
1088 top->op.right = arg;
1089
1090 free_token(token);
1091 type = read_token_item(&token);
1092 *tok = token;
1093
1094 return type;
1095 136
1096out_free: 137 field = pevent_find_any_field(event, name);
1097 free_token(*tok); 138 if (!field)
1098 free_arg(arg); 139 return NULL;
1099 return EVENT_ERROR;
1100}
1101 140
1102static int get_op_prio(char *op) 141 if (field->flags & FIELD_IS_DYNAMIC) {
1103{ 142 int offset;
1104 if (!op[1]) {
1105 switch (op[0]) {
1106 case '*':
1107 case '/':
1108 case '%':
1109 return 6;
1110 case '+':
1111 case '-':
1112 return 7;
1113 /* '>>' and '<<' are 8 */
1114 case '<':
1115 case '>':
1116 return 9;
1117 /* '==' and '!=' are 10 */
1118 case '&':
1119 return 11;
1120 case '^':
1121 return 12;
1122 case '|':
1123 return 13;
1124 case '?':
1125 return 16;
1126 default:
1127 die("unknown op '%c'", op[0]);
1128 return -1;
1129 }
1130 } else {
1131 if (strcmp(op, "++") == 0 ||
1132 strcmp(op, "--") == 0) {
1133 return 3;
1134 } else if (strcmp(op, ">>") == 0 ||
1135 strcmp(op, "<<") == 0) {
1136 return 8;
1137 } else if (strcmp(op, ">=") == 0 ||
1138 strcmp(op, "<=") == 0) {
1139 return 9;
1140 } else if (strcmp(op, "==") == 0 ||
1141 strcmp(op, "!=") == 0) {
1142 return 10;
1143 } else if (strcmp(op, "&&") == 0) {
1144 return 14;
1145 } else if (strcmp(op, "||") == 0) {
1146 return 15;
1147 } else {
1148 die("unknown op '%s'", op);
1149 return -1;
1150 }
1151 }
1152}
1153 143
1154static void set_op_prio(struct print_arg *arg) 144 offset = *(int *)(data + field->offset);
1155{ 145 offset &= 0xffff;
1156 146
1157 /* single ops are the greatest */ 147 return data + offset;
1158 if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
1159 arg->op.prio = 0;
1160 return;
1161 } 148 }
1162 149
1163 arg->op.prio = get_op_prio(arg->op.op); 150 return data + field->offset;
1164} 151}
1165 152
1166static enum event_type 153int trace_parse_common_type(void *data)
1167process_op(struct event *event, struct print_arg *arg, char **tok)
1168{ 154{
1169 struct print_arg *left, *right = NULL; 155 struct pevent_record record;
1170 enum event_type type;
1171 char *token;
1172
1173 /* the op is passed in via tok */
1174 token = *tok;
1175
1176 if (arg->type == PRINT_OP && !arg->op.left) {
1177 /* handle single op */
1178 if (token[1]) {
1179 die("bad op token %s", token);
1180 return EVENT_ERROR;
1181 }
1182 switch (token[0]) {
1183 case '!':
1184 case '+':
1185 case '-':
1186 break;
1187 default:
1188 die("bad op token %s", token);
1189 return EVENT_ERROR;
1190 }
1191
1192 /* make an empty left */
1193 left = malloc_or_die(sizeof(*left));
1194 left->type = PRINT_NULL;
1195 arg->op.left = left;
1196
1197 right = malloc_or_die(sizeof(*right));
1198 arg->op.right = right;
1199
1200 type = process_arg(event, right, tok);
1201
1202 } else if (strcmp(token, "?") == 0) {
1203
1204 left = malloc_or_die(sizeof(*left));
1205 /* copy the top arg to the left */
1206 *left = *arg;
1207
1208 arg->type = PRINT_OP;
1209 arg->op.op = token;
1210 arg->op.left = left;
1211 arg->op.prio = 0;
1212
1213 type = process_cond(event, arg, tok);
1214
1215 } else if (strcmp(token, ">>") == 0 ||
1216 strcmp(token, "<<") == 0 ||
1217 strcmp(token, "&") == 0 ||
1218 strcmp(token, "|") == 0 ||
1219 strcmp(token, "&&") == 0 ||
1220 strcmp(token, "||") == 0 ||
1221 strcmp(token, "-") == 0 ||
1222 strcmp(token, "+") == 0 ||
1223 strcmp(token, "*") == 0 ||
1224 strcmp(token, "^") == 0 ||
1225 strcmp(token, "/") == 0 ||
1226 strcmp(token, "<") == 0 ||
1227 strcmp(token, ">") == 0 ||
1228 strcmp(token, "==") == 0 ||
1229 strcmp(token, "!=") == 0) {
1230
1231 left = malloc_or_die(sizeof(*left));
1232
1233 /* copy the top arg to the left */
1234 *left = *arg;
1235
1236 arg->type = PRINT_OP;
1237 arg->op.op = token;
1238 arg->op.left = left;
1239
1240 set_op_prio(arg);
1241
1242 right = malloc_or_die(sizeof(*right));
1243
1244 type = read_token_item(&token);
1245 *tok = token;
1246
1247 /* could just be a type pointer */
1248 if ((strcmp(arg->op.op, "*") == 0) &&
1249 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1250 if (left->type != PRINT_ATOM)
1251 die("bad pointer type");
1252 left->atom.atom = realloc(left->atom.atom,
1253 sizeof(left->atom.atom) + 3);
1254 strcat(left->atom.atom, " *");
1255 *arg = *left;
1256 free(arg);
1257
1258 return type;
1259 }
1260
1261 type = process_arg_token(event, right, tok, type);
1262
1263 arg->op.right = right;
1264
1265 } else if (strcmp(token, "[") == 0) {
1266
1267 left = malloc_or_die(sizeof(*left));
1268 *left = *arg;
1269
1270 arg->type = PRINT_OP;
1271 arg->op.op = token;
1272 arg->op.left = left;
1273
1274 arg->op.prio = 0;
1275 type = process_array(event, arg, tok);
1276
1277 } else {
1278 warning("unknown op '%s'", token);
1279 event->flags |= EVENT_FL_FAILED;
1280 /* the arg is now the left side */
1281 return EVENT_NONE;
1282 }
1283
1284 if (type == EVENT_OP) {
1285 int prio;
1286
1287 /* higher prios need to be closer to the root */
1288 prio = get_op_prio(*tok);
1289
1290 if (prio > arg->op.prio)
1291 return process_op(event, arg, tok);
1292 156
1293 return process_op(event, right, tok); 157 record.data = data;
1294 } 158 return pevent_data_type(pevent, &record);
1295
1296 return type;
1297} 159}
1298 160
1299static enum event_type 161int trace_parse_common_pid(void *data)
1300process_entry(struct event *event __unused, struct print_arg *arg,
1301 char **tok)
1302{ 162{
1303 enum event_type type; 163 struct pevent_record record;
1304 char *field;
1305 char *token;
1306
1307 if (read_expected(EVENT_OP, "->") < 0)
1308 return EVENT_ERROR;
1309
1310 if (read_expect_type(EVENT_ITEM, &token) < 0)
1311 goto fail;
1312 field = token;
1313
1314 arg->type = PRINT_FIELD;
1315 arg->field.name = field;
1316
1317 if (is_flag_field) {
1318 arg->field.field = find_any_field(event, arg->field.name);
1319 arg->field.field->flags |= FIELD_IS_FLAG;
1320 is_flag_field = 0;
1321 } else if (is_symbolic_field) {
1322 arg->field.field = find_any_field(event, arg->field.name);
1323 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1324 is_symbolic_field = 0;
1325 }
1326
1327 type = read_token(&token);
1328 *tok = token;
1329 164
1330 return type; 165 record.data = data;
1331 166 return pevent_data_pid(pevent, &record);
1332fail:
1333 free_token(token);
1334 return EVENT_ERROR;
1335} 167}
1336 168
1337static char *arg_eval (struct print_arg *arg); 169unsigned long long read_size(void *ptr, int size)
1338
1339static long long arg_num_eval(struct print_arg *arg)
1340{ 170{
1341 long long left, right; 171 return pevent_read_number(pevent, ptr, size);
1342 long long val = 0;
1343
1344 switch (arg->type) {
1345 case PRINT_ATOM:
1346 val = strtoll(arg->atom.atom, NULL, 0);
1347 break;
1348 case PRINT_TYPE:
1349 val = arg_num_eval(arg->typecast.item);
1350 break;
1351 case PRINT_OP:
1352 switch (arg->op.op[0]) {
1353 case '|':
1354 left = arg_num_eval(arg->op.left);
1355 right = arg_num_eval(arg->op.right);
1356 if (arg->op.op[1])
1357 val = left || right;
1358 else
1359 val = left | right;
1360 break;
1361 case '&':
1362 left = arg_num_eval(arg->op.left);
1363 right = arg_num_eval(arg->op.right);
1364 if (arg->op.op[1])
1365 val = left && right;
1366 else
1367 val = left & right;
1368 break;
1369 case '<':
1370 left = arg_num_eval(arg->op.left);
1371 right = arg_num_eval(arg->op.right);
1372 switch (arg->op.op[1]) {
1373 case 0:
1374 val = left < right;
1375 break;
1376 case '<':
1377 val = left << right;
1378 break;
1379 case '=':
1380 val = left <= right;
1381 break;
1382 default:
1383 die("unknown op '%s'", arg->op.op);
1384 }
1385 break;
1386 case '>':
1387 left = arg_num_eval(arg->op.left);
1388 right = arg_num_eval(arg->op.right);
1389 switch (arg->op.op[1]) {
1390 case 0:
1391 val = left > right;
1392 break;
1393 case '>':
1394 val = left >> right;
1395 break;
1396 case '=':
1397 val = left >= right;
1398 break;
1399 default:
1400 die("unknown op '%s'", arg->op.op);
1401 }
1402 break;
1403 case '=':
1404 left = arg_num_eval(arg->op.left);
1405 right = arg_num_eval(arg->op.right);
1406
1407 if (arg->op.op[1] != '=')
1408 die("unknown op '%s'", arg->op.op);
1409
1410 val = left == right;
1411 break;
1412 case '!':
1413 left = arg_num_eval(arg->op.left);
1414 right = arg_num_eval(arg->op.right);
1415
1416 switch (arg->op.op[1]) {
1417 case '=':
1418 val = left != right;
1419 break;
1420 default:
1421 die("unknown op '%s'", arg->op.op);
1422 }
1423 break;
1424 case '+':
1425 left = arg_num_eval(arg->op.left);
1426 right = arg_num_eval(arg->op.right);
1427 val = left + right;
1428 break;
1429 default:
1430 die("unknown op '%s'", arg->op.op);
1431 }
1432 break;
1433
1434 case PRINT_NULL:
1435 case PRINT_FIELD ... PRINT_SYMBOL:
1436 case PRINT_STRING:
1437 default:
1438 die("invalid eval type %d", arg->type);
1439
1440 }
1441 return val;
1442} 172}
1443 173
1444static char *arg_eval (struct print_arg *arg) 174struct event_format *trace_find_event(int type)
1445{ 175{
1446 long long val; 176 return pevent_find_event(pevent, type);
1447 static char buf[20];
1448
1449 switch (arg->type) {
1450 case PRINT_ATOM:
1451 return arg->atom.atom;
1452 case PRINT_TYPE:
1453 return arg_eval(arg->typecast.item);
1454 case PRINT_OP:
1455 val = arg_num_eval(arg);
1456 sprintf(buf, "%lld", val);
1457 return buf;
1458
1459 case PRINT_NULL:
1460 case PRINT_FIELD ... PRINT_SYMBOL:
1461 case PRINT_STRING:
1462 default:
1463 die("invalid eval type %d", arg->type);
1464 break;
1465 }
1466
1467 return NULL;
1468} 177}
1469 178
1470static enum event_type
1471process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1472{
1473 enum event_type type;
1474 struct print_arg *arg = NULL;
1475 struct print_flag_sym *field;
1476 char *token = NULL;
1477 char *value;
1478
1479 do {
1480 free_token(token);
1481 type = read_token_item(&token);
1482 if (test_type_token(type, token, EVENT_OP, "{"))
1483 break;
1484
1485 arg = malloc_or_die(sizeof(*arg));
1486
1487 free_token(token);
1488 type = process_arg(event, arg, &token);
1489
1490 if (type == EVENT_OP)
1491 type = process_op(event, arg, &token);
1492
1493 if (type == EVENT_ERROR)
1494 goto out_free;
1495
1496 if (test_type_token(type, token, EVENT_DELIM, ","))
1497 goto out_free;
1498
1499 field = malloc_or_die(sizeof(*field));
1500 memset(field, 0, sizeof(*field));
1501
1502 value = arg_eval(arg);
1503 field->value = strdup(value);
1504
1505 free_token(token);
1506 type = process_arg(event, arg, &token);
1507 if (test_type_token(type, token, EVENT_OP, "}"))
1508 goto out_free;
1509
1510 value = arg_eval(arg);
1511 field->str = strdup(value);
1512 free_arg(arg);
1513 arg = NULL;
1514
1515 *list = field;
1516 list = &field->next;
1517 179
1518 free_token(token); 180void print_trace_event(int cpu, void *data, int size)
1519 type = read_token_item(&token);
1520 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
1521
1522 *tok = token;
1523 return type;
1524
1525out_free:
1526 free_arg(arg);
1527 free_token(token);
1528
1529 return EVENT_ERROR;
1530}
1531
1532static enum event_type
1533process_flags(struct event *event, struct print_arg *arg, char **tok)
1534{ 181{
1535 struct print_arg *field; 182 struct event_format *event;
1536 enum event_type type; 183 struct pevent_record record;
1537 char *token; 184 struct trace_seq s;
1538 185 int type;
1539 memset(arg, 0, sizeof(*arg));
1540 arg->type = PRINT_FLAGS;
1541
1542 if (read_expected_item(EVENT_DELIM, "(") < 0)
1543 return EVENT_ERROR;
1544
1545 field = malloc_or_die(sizeof(*field));
1546
1547 type = process_arg(event, field, &token);
1548 while (type == EVENT_OP)
1549 type = process_op(event, field, &token);
1550 if (test_type_token(type, token, EVENT_DELIM, ","))
1551 goto out_free;
1552 186
1553 arg->flags.field = field; 187 type = trace_parse_common_type(data);
1554 188
1555 type = read_token_item(&token); 189 event = trace_find_event(type);
1556 if (event_item_type(type)) { 190 if (!event) {
1557 arg->flags.delim = token; 191 warning("ug! no event found for type %d", type);
1558 type = read_token_item(&token); 192 return;
1559 } 193 }
1560 194
1561 if (test_type_token(type, token, EVENT_DELIM, ",")) 195 memset(&record, 0, sizeof(record));
1562 goto out_free; 196 record.cpu = cpu;
1563 197 record.size = size;
1564 type = process_fields(event, &arg->flags.flags, &token); 198 record.data = data;
1565 if (test_type_token(type, token, EVENT_DELIM, ")"))
1566 goto out_free;
1567 199
1568 free_token(token); 200 trace_seq_init(&s);
1569 type = read_token_item(tok); 201 pevent_print_event(pevent, &s, &record);
1570 return type; 202 trace_seq_do_printf(&s);
1571 203 printf("\n");
1572out_free:
1573 free_token(token);
1574 return EVENT_ERROR;
1575} 204}
1576 205
1577static enum event_type 206void print_event(int cpu, void *data, int size, unsigned long long nsecs,
1578process_symbols(struct event *event, struct print_arg *arg, char **tok) 207 char *comm)
1579{ 208{
1580 struct print_arg *field; 209 struct pevent_record record;
1581 enum event_type type; 210 struct trace_seq s;
1582 char *token; 211 int pid;
1583
1584 memset(arg, 0, sizeof(*arg));
1585 arg->type = PRINT_SYMBOL;
1586
1587 if (read_expected_item(EVENT_DELIM, "(") < 0)
1588 return EVENT_ERROR;
1589
1590 field = malloc_or_die(sizeof(*field));
1591
1592 type = process_arg(event, field, &token);
1593 if (test_type_token(type, token, EVENT_DELIM, ","))
1594 goto out_free;
1595 212
1596 arg->symbol.field = field; 213 pevent->latency_format = latency_format;
1597 214
1598 type = process_fields(event, &arg->symbol.symbols, &token); 215 record.ts = nsecs;
1599 if (test_type_token(type, token, EVENT_DELIM, ")")) 216 record.cpu = cpu;
1600 goto out_free; 217 record.size = size;
218 record.data = data;
219 pid = pevent_data_pid(pevent, &record);
1601 220
1602 free_token(token); 221 if (!pevent_pid_is_registered(pevent, pid))
1603 type = read_token_item(tok); 222 pevent_register_comm(pevent, comm, pid);
1604 return type;
1605 223
1606out_free: 224 trace_seq_init(&s);
1607 free_token(token); 225 pevent_print_event(pevent, &s, &record);
1608 return EVENT_ERROR; 226 trace_seq_do_printf(&s);
227 printf("\n");
1609} 228}
1610 229
1611static enum event_type 230void parse_proc_kallsyms(char *file, unsigned int size __unused)
1612process_paren(struct event *event, struct print_arg *arg, char **tok)
1613{ 231{
1614 struct print_arg *item_arg; 232 unsigned long long addr;
1615 enum event_type type; 233 char *func;
1616 char *token; 234 char *line;
1617 235 char *next = NULL;
1618 type = process_arg(event, arg, &token); 236 char *addr_str;
1619 237 char *mod;
1620 if (type == EVENT_ERROR) 238 char ch;
1621 return EVENT_ERROR;
1622
1623 if (type == EVENT_OP)
1624 type = process_op(event, arg, &token);
1625
1626 if (type == EVENT_ERROR)
1627 return EVENT_ERROR;
1628
1629 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1630 free_token(token);
1631 return EVENT_ERROR;
1632 }
1633
1634 free_token(token);
1635 type = read_token_item(&token);
1636
1637 /*
1638 * If the next token is an item or another open paren, then
1639 * this was a typecast.
1640 */
1641 if (event_item_type(type) ||
1642 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
1643
1644 /* make this a typecast and contine */
1645 239
1646 /* prevous must be an atom */ 240 line = strtok_r(file, "\n", &next);
1647 if (arg->type != PRINT_ATOM) 241 while (line) {
1648 die("previous needed to be PRINT_ATOM"); 242 mod = NULL;
243 sscanf(line, "%as %c %as\t[%as",
244 (float *)(void *)&addr_str, /* workaround gcc warning */
245 &ch, (float *)(void *)&func, (float *)(void *)&mod);
246 addr = strtoull(addr_str, NULL, 16);
247 free(addr_str);
1649 248
1650 item_arg = malloc_or_die(sizeof(*item_arg)); 249 /* truncate the extra ']' */
250 if (mod)
251 mod[strlen(mod) - 1] = 0;
1651 252
1652 arg->type = PRINT_TYPE; 253 pevent_register_function(pevent, func, addr, mod);
1653 arg->typecast.type = arg->atom.atom; 254 free(func);
1654 arg->typecast.item = item_arg; 255 free(mod);
1655 type = process_arg_token(event, item_arg, &token, type);
1656 256
257 line = strtok_r(NULL, "\n", &next);
1657 } 258 }
1658
1659 *tok = token;
1660 return type;
1661} 259}
1662 260
1663 261void parse_ftrace_printk(char *file, unsigned int size __unused)
1664static enum event_type
1665process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1666{ 262{
1667 enum event_type type; 263 unsigned long long addr;
1668 char *token; 264 char *printk;
1669 265 char *line;
1670 if (read_expected(EVENT_DELIM, "(") < 0) 266 char *next = NULL;
1671 return EVENT_ERROR; 267 char *addr_str;
1672 268 char *fmt;
1673 if (read_expect_type(EVENT_ITEM, &token) < 0)
1674 goto fail;
1675
1676 arg->type = PRINT_STRING;
1677 arg->string.string = token;
1678 arg->string.offset = -1;
1679
1680 if (read_expected(EVENT_DELIM, ")") < 0)
1681 return EVENT_ERROR;
1682
1683 type = read_token(&token);
1684 *tok = token;
1685
1686 return type;
1687fail:
1688 free_token(token);
1689 return EVENT_ERROR;
1690}
1691 269
1692enum event_type 270 line = strtok_r(file, "\n", &next);
1693process_arg_token(struct event *event, struct print_arg *arg, 271 while (line) {
1694 char **tok, enum event_type type) 272 addr_str = strtok_r(line, ":", &fmt);
1695{ 273 if (!addr_str) {
1696 char *token; 274 warning("printk format with empty entry");
1697 char *atom;
1698
1699 token = *tok;
1700
1701 switch (type) {
1702 case EVENT_ITEM:
1703 if (strcmp(token, "REC") == 0) {
1704 free_token(token);
1705 type = process_entry(event, arg, &token);
1706 } else if (strcmp(token, "__print_flags") == 0) {
1707 free_token(token);
1708 is_flag_field = 1;
1709 type = process_flags(event, arg, &token);
1710 } else if (strcmp(token, "__print_symbolic") == 0) {
1711 free_token(token);
1712 is_symbolic_field = 1;
1713 type = process_symbols(event, arg, &token);
1714 } else if (strcmp(token, "__get_str") == 0) {
1715 free_token(token);
1716 type = process_str(event, arg, &token);
1717 } else {
1718 atom = token;
1719 /* test the next token */
1720 type = read_token_item(&token);
1721
1722 /* atoms can be more than one token long */
1723 while (type == EVENT_ITEM) {
1724 atom = realloc(atom, strlen(atom) + strlen(token) + 2);
1725 strcat(atom, " ");
1726 strcat(atom, token);
1727 free_token(token);
1728 type = read_token_item(&token);
1729 }
1730
1731 /* todo, test for function */
1732
1733 arg->type = PRINT_ATOM;
1734 arg->atom.atom = atom;
1735 }
1736 break;
1737 case EVENT_DQUOTE:
1738 case EVENT_SQUOTE:
1739 arg->type = PRINT_ATOM;
1740 arg->atom.atom = token;
1741 type = read_token_item(&token);
1742 break;
1743 case EVENT_DELIM:
1744 if (strcmp(token, "(") == 0) {
1745 free_token(token);
1746 type = process_paren(event, arg, &token);
1747 break; 275 break;
1748 } 276 }
1749 case EVENT_OP: 277 addr = strtoull(addr_str, NULL, 16);
1750 /* handle single ops */ 278 /* fmt still has a space, skip it */
1751 arg->type = PRINT_OP; 279 printk = strdup(fmt+1);
1752 arg->op.op = token; 280 line = strtok_r(NULL, "\n", &next);
1753 arg->op.left = NULL; 281 pevent_register_print_string(pevent, printk, addr);
1754 type = process_op(event, arg, &token);
1755
1756 break;
1757
1758 case EVENT_ERROR ... EVENT_NEWLINE:
1759 default:
1760 die("unexpected type %d", type);
1761 }
1762 *tok = token;
1763
1764 return type;
1765}
1766
1767static int event_read_print_args(struct event *event, struct print_arg **list)
1768{
1769 enum event_type type = EVENT_ERROR;
1770 struct print_arg *arg;
1771 char *token;
1772 int args = 0;
1773
1774 do {
1775 if (type == EVENT_NEWLINE) {
1776 free_token(token);
1777 type = read_token_item(&token);
1778 continue;
1779 }
1780
1781 arg = malloc_or_die(sizeof(*arg));
1782 memset(arg, 0, sizeof(*arg));
1783
1784 type = process_arg(event, arg, &token);
1785
1786 if (type == EVENT_ERROR) {
1787 free_arg(arg);
1788 return -1;
1789 }
1790
1791 *list = arg;
1792 args++;
1793
1794 if (type == EVENT_OP) {
1795 type = process_op(event, arg, &token);
1796 list = &arg->next;
1797 continue;
1798 }
1799
1800 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
1801 free_token(token);
1802 *list = arg;
1803 list = &arg->next;
1804 continue;
1805 }
1806 break;
1807 } while (type != EVENT_NONE);
1808
1809 if (type != EVENT_NONE)
1810 free_token(token);
1811
1812 return args;
1813}
1814
1815static int event_read_print(struct event *event)
1816{
1817 enum event_type type;
1818 char *token;
1819 int ret;
1820
1821 if (read_expected_item(EVENT_ITEM, "print") < 0)
1822 return -1;
1823
1824 if (read_expected(EVENT_ITEM, "fmt") < 0)
1825 return -1;
1826
1827 if (read_expected(EVENT_OP, ":") < 0)
1828 return -1;
1829
1830 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1831 goto fail;
1832
1833 concat:
1834 event->print_fmt.format = token;
1835 event->print_fmt.args = NULL;
1836
1837 /* ok to have no arg */
1838 type = read_token_item(&token);
1839
1840 if (type == EVENT_NONE)
1841 return 0;
1842
1843 /* Handle concatination of print lines */
1844 if (type == EVENT_DQUOTE) {
1845 char *cat;
1846
1847 cat = malloc_or_die(strlen(event->print_fmt.format) +
1848 strlen(token) + 1);
1849 strcpy(cat, event->print_fmt.format);
1850 strcat(cat, token);
1851 free_token(token);
1852 free_token(event->print_fmt.format);
1853 event->print_fmt.format = NULL;
1854 token = cat;
1855 goto concat;
1856 }
1857
1858 if (test_type_token(type, token, EVENT_DELIM, ","))
1859 goto fail;
1860
1861 free_token(token);
1862
1863 ret = event_read_print_args(event, &event->print_fmt.args);
1864 if (ret < 0)
1865 return -1;
1866
1867 return ret;
1868
1869 fail:
1870 free_token(token);
1871 return -1;
1872}
1873
1874static struct format_field *
1875find_common_field(struct event *event, const char *name)
1876{
1877 struct format_field *format;
1878
1879 for (format = event->format.common_fields;
1880 format; format = format->next) {
1881 if (strcmp(format->name, name) == 0)
1882 break;
1883 }
1884
1885 return format;
1886}
1887
1888static struct format_field *
1889find_field(struct event *event, const char *name)
1890{
1891 struct format_field *format;
1892
1893 for (format = event->format.fields;
1894 format; format = format->next) {
1895 if (strcmp(format->name, name) == 0)
1896 break;
1897 } 282 }
1898
1899 return format;
1900} 283}
1901 284
1902static struct format_field * 285int parse_ftrace_file(char *buf, unsigned long size)
1903find_any_field(struct event *event, const char *name)
1904{ 286{
1905 struct format_field *format; 287 return pevent_parse_event(pevent, buf, size, "ftrace");
1906
1907 format = find_common_field(event, name);
1908 if (format)
1909 return format;
1910 return find_field(event, name);
1911} 288}
1912 289
1913unsigned long long read_size(void *ptr, int size) 290int parse_event_file(char *buf, unsigned long size, char *sys)
1914{ 291{
1915 switch (size) { 292 return pevent_parse_event(pevent, buf, size, sys);
1916 case 1:
1917 return *(unsigned char *)ptr;
1918 case 2:
1919 return data2host2(ptr);
1920 case 4:
1921 return data2host4(ptr);
1922 case 8:
1923 return data2host8(ptr);
1924 default:
1925 /* BUG! */
1926 return 0;
1927 }
1928} 293}
1929 294
1930unsigned long long 295struct event_format *trace_find_next_event(struct event_format *event)
1931raw_field_value(struct event *event, const char *name, void *data)
1932{ 296{
1933 struct format_field *field; 297 static int idx;
1934
1935 field = find_any_field(event, name);
1936 if (!field)
1937 return 0ULL;
1938 298
1939 return read_size(data + field->offset, field->size); 299 if (!pevent->events)
1940}
1941
1942void *raw_field_ptr(struct event *event, const char *name, void *data)
1943{
1944 struct format_field *field;
1945
1946 field = find_any_field(event, name);
1947 if (!field)
1948 return NULL; 300 return NULL;
1949 301
1950 if (field->flags & FIELD_IS_DYNAMIC) { 302 if (!event) {
1951 int offset; 303 idx = 0;
1952 304 return pevent->events[0];
1953 offset = *(int *)(data + field->offset);
1954 offset &= 0xffff;
1955
1956 return data + offset;
1957 }
1958
1959 return data + field->offset;
1960}
1961
1962static int get_common_info(const char *type, int *offset, int *size)
1963{
1964 struct event *event;
1965 struct format_field *field;
1966
1967 /*
1968 * All events should have the same common elements.
1969 * Pick any event to find where the type is;
1970 */
1971 if (!event_list)
1972 die("no event_list!");
1973
1974 event = event_list;
1975 field = find_common_field(event, type);
1976 if (!field)
1977 die("field '%s' not found", type);
1978
1979 *offset = field->offset;
1980 *size = field->size;
1981
1982 return 0;
1983}
1984
1985static int __parse_common(void *data, int *size, int *offset,
1986 const char *name)
1987{
1988 int ret;
1989
1990 if (!*size) {
1991 ret = get_common_info(name, offset, size);
1992 if (ret < 0)
1993 return ret;
1994 } 305 }
1995 return read_size(data + *offset, *size);
1996}
1997
1998int trace_parse_common_type(void *data)
1999{
2000 static int type_offset;
2001 static int type_size;
2002
2003 return __parse_common(data, &type_size, &type_offset,
2004 "common_type");
2005}
2006
2007int trace_parse_common_pid(void *data)
2008{
2009 static int pid_offset;
2010 static int pid_size;
2011
2012 return __parse_common(data, &pid_size, &pid_offset,
2013 "common_pid");
2014}
2015
2016int parse_common_pc(void *data)
2017{
2018 static int pc_offset;
2019 static int pc_size;
2020
2021 return __parse_common(data, &pc_size, &pc_offset,
2022 "common_preempt_count");
2023}
2024
2025int parse_common_flags(void *data)
2026{
2027 static int flags_offset;
2028 static int flags_size;
2029
2030 return __parse_common(data, &flags_size, &flags_offset,
2031 "common_flags");
2032}
2033
2034int parse_common_lock_depth(void *data)
2035{
2036 static int ld_offset;
2037 static int ld_size;
2038 int ret;
2039 306
2040 ret = __parse_common(data, &ld_size, &ld_offset, 307 if (idx < pevent->nr_events && event == pevent->events[idx]) {
2041 "common_lock_depth"); 308 idx++;
2042 if (ret < 0) 309 if (idx == pevent->nr_events)
2043 return -1; 310 return NULL;
2044 311 return pevent->events[idx];
2045 return ret;
2046}
2047
2048struct event *trace_find_event(int id)
2049{
2050 struct event *event;
2051
2052 for (event = event_list; event; event = event->next) {
2053 if (event->id == id)
2054 break;
2055 } 312 }
2056 return event;
2057}
2058
2059struct event *trace_find_next_event(struct event *event)
2060{
2061 if (!event)
2062 return event_list;
2063
2064 return event->next;
2065}
2066
2067static unsigned long long eval_num_arg(void *data, int size,
2068 struct event *event, struct print_arg *arg)
2069{
2070 unsigned long long val = 0;
2071 unsigned long long left, right;
2072 struct print_arg *larg;
2073 313
2074 switch (arg->type) { 314 for (idx = 1; idx < pevent->nr_events; idx++) {
2075 case PRINT_NULL: 315 if (event == pevent->events[idx - 1])
2076 /* ?? */ 316 return pevent->events[idx];
2077 return 0;
2078 case PRINT_ATOM:
2079 return strtoull(arg->atom.atom, NULL, 0);
2080 case PRINT_FIELD:
2081 if (!arg->field.field) {
2082 arg->field.field = find_any_field(event, arg->field.name);
2083 if (!arg->field.field)
2084 die("field %s not found", arg->field.name);
2085 }
2086 /* must be a number */
2087 val = read_size(data + arg->field.field->offset,
2088 arg->field.field->size);
2089 break;
2090 case PRINT_FLAGS:
2091 case PRINT_SYMBOL:
2092 break;
2093 case PRINT_TYPE:
2094 return eval_num_arg(data, size, event, arg->typecast.item);
2095 case PRINT_STRING:
2096 return 0;
2097 break;
2098 case PRINT_OP:
2099 if (strcmp(arg->op.op, "[") == 0) {
2100 /*
2101 * Arrays are special, since we don't want
2102 * to read the arg as is.
2103 */
2104 if (arg->op.left->type != PRINT_FIELD)
2105 goto default_op; /* oops, all bets off */
2106 larg = arg->op.left;
2107 if (!larg->field.field) {
2108 larg->field.field =
2109 find_any_field(event, larg->field.name);
2110 if (!larg->field.field)
2111 die("field %s not found", larg->field.name);
2112 }
2113 right = eval_num_arg(data, size, event, arg->op.right);
2114 val = read_size(data + larg->field.field->offset +
2115 right * long_size, long_size);
2116 break;
2117 }
2118 default_op:
2119 left = eval_num_arg(data, size, event, arg->op.left);
2120 right = eval_num_arg(data, size, event, arg->op.right);
2121 switch (arg->op.op[0]) {
2122 case '|':
2123 if (arg->op.op[1])
2124 val = left || right;
2125 else
2126 val = left | right;
2127 break;
2128 case '&':
2129 if (arg->op.op[1])
2130 val = left && right;
2131 else
2132 val = left & right;
2133 break;
2134 case '<':
2135 switch (arg->op.op[1]) {
2136 case 0:
2137 val = left < right;
2138 break;
2139 case '<':
2140 val = left << right;
2141 break;
2142 case '=':
2143 val = left <= right;
2144 break;
2145 default:
2146 die("unknown op '%s'", arg->op.op);
2147 }
2148 break;
2149 case '>':
2150 switch (arg->op.op[1]) {
2151 case 0:
2152 val = left > right;
2153 break;
2154 case '>':
2155 val = left >> right;
2156 break;
2157 case '=':
2158 val = left >= right;
2159 break;
2160 default:
2161 die("unknown op '%s'", arg->op.op);
2162 }
2163 break;
2164 case '=':
2165 if (arg->op.op[1] != '=')
2166 die("unknown op '%s'", arg->op.op);
2167 val = left == right;
2168 break;
2169 case '-':
2170 val = left - right;
2171 break;
2172 case '+':
2173 val = left + right;
2174 break;
2175 default:
2176 die("unknown op '%s'", arg->op.op);
2177 }
2178 break;
2179 default: /* not sure what to do there */
2180 return 0;
2181 } 317 }
2182 return val; 318 return NULL;
2183} 319}
2184 320
2185struct flag { 321struct flag {
@@ -2221,933 +357,3 @@ unsigned long long eval_flag(const char *flag)
2221 357
2222 return 0; 358 return 0;
2223} 359}
2224
2225static void print_str_arg(void *data, int size,
2226 struct event *event, struct print_arg *arg)
2227{
2228 struct print_flag_sym *flag;
2229 unsigned long long val, fval;
2230 char *str;
2231 int print;
2232
2233 switch (arg->type) {
2234 case PRINT_NULL:
2235 /* ?? */
2236 return;
2237 case PRINT_ATOM:
2238 printf("%s", arg->atom.atom);
2239 return;
2240 case PRINT_FIELD:
2241 if (!arg->field.field) {
2242 arg->field.field = find_any_field(event, arg->field.name);
2243 if (!arg->field.field)
2244 die("field %s not found", arg->field.name);
2245 }
2246 str = malloc_or_die(arg->field.field->size + 1);
2247 memcpy(str, data + arg->field.field->offset,
2248 arg->field.field->size);
2249 str[arg->field.field->size] = 0;
2250 printf("%s", str);
2251 free(str);
2252 break;
2253 case PRINT_FLAGS:
2254 val = eval_num_arg(data, size, event, arg->flags.field);
2255 print = 0;
2256 for (flag = arg->flags.flags; flag; flag = flag->next) {
2257 fval = eval_flag(flag->value);
2258 if (!val && !fval) {
2259 printf("%s", flag->str);
2260 break;
2261 }
2262 if (fval && (val & fval) == fval) {
2263 if (print && arg->flags.delim)
2264 printf("%s", arg->flags.delim);
2265 printf("%s", flag->str);
2266 print = 1;
2267 val &= ~fval;
2268 }
2269 }
2270 break;
2271 case PRINT_SYMBOL:
2272 val = eval_num_arg(data, size, event, arg->symbol.field);
2273 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
2274 fval = eval_flag(flag->value);
2275 if (val == fval) {
2276 printf("%s", flag->str);
2277 break;
2278 }
2279 }
2280 break;
2281
2282 case PRINT_TYPE:
2283 break;
2284 case PRINT_STRING: {
2285 int str_offset;
2286
2287 if (arg->string.offset == -1) {
2288 struct format_field *f;
2289
2290 f = find_any_field(event, arg->string.string);
2291 arg->string.offset = f->offset;
2292 }
2293 str_offset = *(int *)(data + arg->string.offset);
2294 str_offset &= 0xffff;
2295 printf("%s", ((char *)data) + str_offset);
2296 break;
2297 }
2298 case PRINT_OP:
2299 /*
2300 * The only op for string should be ? :
2301 */
2302 if (arg->op.op[0] != '?')
2303 return;
2304 val = eval_num_arg(data, size, event, arg->op.left);
2305 if (val)
2306 print_str_arg(data, size, event, arg->op.right->op.left);
2307 else
2308 print_str_arg(data, size, event, arg->op.right->op.right);
2309 break;
2310 default:
2311 /* well... */
2312 break;
2313 }
2314}
2315
2316static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
2317{
2318 static struct format_field *field, *ip_field;
2319 struct print_arg *args, *arg, **next;
2320 unsigned long long ip, val;
2321 char *ptr;
2322 void *bptr;
2323
2324 if (!field) {
2325 field = find_field(event, "buf");
2326 if (!field)
2327 die("can't find buffer field for binary printk");
2328 ip_field = find_field(event, "ip");
2329 if (!ip_field)
2330 die("can't find ip field for binary printk");
2331 }
2332
2333 ip = read_size(data + ip_field->offset, ip_field->size);
2334
2335 /*
2336 * The first arg is the IP pointer.
2337 */
2338 args = malloc_or_die(sizeof(*args));
2339 arg = args;
2340 arg->next = NULL;
2341 next = &arg->next;
2342
2343 arg->type = PRINT_ATOM;
2344 arg->atom.atom = malloc_or_die(32);
2345 sprintf(arg->atom.atom, "%lld", ip);
2346
2347 /* skip the first "%pf : " */
2348 for (ptr = fmt + 6, bptr = data + field->offset;
2349 bptr < data + size && *ptr; ptr++) {
2350 int ls = 0;
2351
2352 if (*ptr == '%') {
2353 process_again:
2354 ptr++;
2355 switch (*ptr) {
2356 case '%':
2357 break;
2358 case 'l':
2359 ls++;
2360 goto process_again;
2361 case 'L':
2362 ls = 2;
2363 goto process_again;
2364 case '0' ... '9':
2365 goto process_again;
2366 case 'p':
2367 ls = 1;
2368 /* fall through */
2369 case 'd':
2370 case 'u':
2371 case 'x':
2372 case 'i':
2373 /* the pointers are always 4 bytes aligned */
2374 bptr = (void *)(((unsigned long)bptr + 3) &
2375 ~3);
2376 switch (ls) {
2377 case 0:
2378 case 1:
2379 ls = long_size;
2380 break;
2381 case 2:
2382 ls = 8;
2383 default:
2384 break;
2385 }
2386 val = read_size(bptr, ls);
2387 bptr += ls;
2388 arg = malloc_or_die(sizeof(*arg));
2389 arg->next = NULL;
2390 arg->type = PRINT_ATOM;
2391 arg->atom.atom = malloc_or_die(32);
2392 sprintf(arg->atom.atom, "%lld", val);
2393 *next = arg;
2394 next = &arg->next;
2395 break;
2396 case 's':
2397 arg = malloc_or_die(sizeof(*arg));
2398 arg->next = NULL;
2399 arg->type = PRINT_STRING;
2400 arg->string.string = strdup(bptr);
2401 bptr += strlen(bptr) + 1;
2402 *next = arg;
2403 next = &arg->next;
2404 default:
2405 break;
2406 }
2407 }
2408 }
2409
2410 return args;
2411}
2412
2413static void free_args(struct print_arg *args)
2414{
2415 struct print_arg *next;
2416
2417 while (args) {
2418 next = args->next;
2419
2420 if (args->type == PRINT_ATOM)
2421 free(args->atom.atom);
2422 else
2423 free(args->string.string);
2424 free(args);
2425 args = next;
2426 }
2427}
2428
2429static char *get_bprint_format(void *data, int size __unused, struct event *event)
2430{
2431 unsigned long long addr;
2432 static struct format_field *field;
2433 struct printk_map *printk;
2434 char *format;
2435 char *p;
2436
2437 if (!field) {
2438 field = find_field(event, "fmt");
2439 if (!field)
2440 die("can't find format field for binary printk");
2441 printf("field->offset = %d size=%d\n", field->offset, field->size);
2442 }
2443
2444 addr = read_size(data + field->offset, field->size);
2445
2446 printk = find_printk(addr);
2447 if (!printk) {
2448 format = malloc_or_die(45);
2449 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
2450 addr);
2451 return format;
2452 }
2453
2454 p = printk->printk;
2455 /* Remove any quotes. */
2456 if (*p == '"')
2457 p++;
2458 format = malloc_or_die(strlen(p) + 10);
2459 sprintf(format, "%s : %s", "%pf", p);
2460 /* remove ending quotes and new line since we will add one too */
2461 p = format + strlen(format) - 1;
2462 if (*p == '"')
2463 *p = 0;
2464
2465 p -= 2;
2466 if (strcmp(p, "\\n") == 0)
2467 *p = 0;
2468
2469 return format;
2470}
2471
2472static void pretty_print(void *data, int size, struct event *event)
2473{
2474 struct print_fmt *print_fmt = &event->print_fmt;
2475 struct print_arg *arg = print_fmt->args;
2476 struct print_arg *args = NULL;
2477 const char *ptr = print_fmt->format;
2478 unsigned long long val;
2479 struct func_map *func;
2480 const char *saveptr;
2481 char *bprint_fmt = NULL;
2482 char format[32];
2483 int show_func;
2484 int len;
2485 int ls;
2486
2487 if (event->flags & EVENT_FL_ISFUNC)
2488 ptr = " %pF <-- %pF";
2489
2490 if (event->flags & EVENT_FL_ISBPRINT) {
2491 bprint_fmt = get_bprint_format(data, size, event);
2492 args = make_bprint_args(bprint_fmt, data, size, event);
2493 arg = args;
2494 ptr = bprint_fmt;
2495 }
2496
2497 for (; *ptr; ptr++) {
2498 ls = 0;
2499 if (*ptr == '\\') {
2500 ptr++;
2501 switch (*ptr) {
2502 case 'n':
2503 printf("\n");
2504 break;
2505 case 't':
2506 printf("\t");
2507 break;
2508 case 'r':
2509 printf("\r");
2510 break;
2511 case '\\':
2512 printf("\\");
2513 break;
2514 default:
2515 printf("%c", *ptr);
2516 break;
2517 }
2518
2519 } else if (*ptr == '%') {
2520 saveptr = ptr;
2521 show_func = 0;
2522 cont_process:
2523 ptr++;
2524 switch (*ptr) {
2525 case '%':
2526 printf("%%");
2527 break;
2528 case 'l':
2529 ls++;
2530 goto cont_process;
2531 case 'L':
2532 ls = 2;
2533 goto cont_process;
2534 case 'z':
2535 case 'Z':
2536 case '0' ... '9':
2537 goto cont_process;
2538 case 'p':
2539 if (long_size == 4)
2540 ls = 1;
2541 else
2542 ls = 2;
2543
2544 if (*(ptr+1) == 'F' ||
2545 *(ptr+1) == 'f') {
2546 ptr++;
2547 show_func = *ptr;
2548 }
2549
2550 /* fall through */
2551 case 'd':
2552 case 'i':
2553 case 'x':
2554 case 'X':
2555 case 'u':
2556 if (!arg)
2557 die("no argument match");
2558
2559 len = ((unsigned long)ptr + 1) -
2560 (unsigned long)saveptr;
2561
2562 /* should never happen */
2563 if (len > 32)
2564 die("bad format!");
2565
2566 memcpy(format, saveptr, len);
2567 format[len] = 0;
2568
2569 val = eval_num_arg(data, size, event, arg);
2570 arg = arg->next;
2571
2572 if (show_func) {
2573 func = find_func(val);
2574 if (func) {
2575 printf("%s", func->func);
2576 if (show_func == 'F')
2577 printf("+0x%llx",
2578 val - func->addr);
2579 break;
2580 }
2581 }
2582 switch (ls) {
2583 case 0:
2584 printf(format, (int)val);
2585 break;
2586 case 1:
2587 printf(format, (long)val);
2588 break;
2589 case 2:
2590 printf(format, (long long)val);
2591 break;
2592 default:
2593 die("bad count (%d)", ls);
2594 }
2595 break;
2596 case 's':
2597 if (!arg)
2598 die("no matching argument");
2599
2600 print_str_arg(data, size, event, arg);
2601 arg = arg->next;
2602 break;
2603 default:
2604 printf(">%c<", *ptr);
2605
2606 }
2607 } else
2608 printf("%c", *ptr);
2609 }
2610
2611 if (args) {
2612 free_args(args);
2613 free(bprint_fmt);
2614 }
2615}
2616
2617static inline int log10_cpu(int nb)
2618{
2619 if (nb / 100)
2620 return 3;
2621 if (nb / 10)
2622 return 2;
2623 return 1;
2624}
2625
2626static void print_lat_fmt(void *data, int size __unused)
2627{
2628 unsigned int lat_flags;
2629 unsigned int pc;
2630 int lock_depth;
2631 int hardirq;
2632 int softirq;
2633
2634 lat_flags = parse_common_flags(data);
2635 pc = parse_common_pc(data);
2636 lock_depth = parse_common_lock_depth(data);
2637
2638 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
2639 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
2640
2641 printf("%c%c%c",
2642 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
2643 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
2644 'X' : '.',
2645 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
2646 'N' : '.',
2647 (hardirq && softirq) ? 'H' :
2648 hardirq ? 'h' : softirq ? 's' : '.');
2649
2650 if (pc)
2651 printf("%x", pc);
2652 else
2653 printf(".");
2654
2655 if (lock_depth < 0)
2656 printf(". ");
2657 else
2658 printf("%d ", lock_depth);
2659}
2660
2661#define TRACE_GRAPH_INDENT 2
2662
2663static struct record *
2664get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2665 struct record *next)
2666{
2667 struct format_field *field;
2668 struct event *event;
2669 unsigned long val;
2670 int type;
2671 int pid;
2672
2673 type = trace_parse_common_type(next->data);
2674 event = trace_find_event(type);
2675 if (!event)
2676 return NULL;
2677
2678 if (!(event->flags & EVENT_FL_ISFUNCRET))
2679 return NULL;
2680
2681 pid = trace_parse_common_pid(next->data);
2682 field = find_field(event, "func");
2683 if (!field)
2684 die("function return does not have field func");
2685
2686 val = read_size(next->data + field->offset, field->size);
2687
2688 if (cur_pid != pid || cur_func != val)
2689 return NULL;
2690
2691 /* this is a leaf, now advance the iterator */
2692 return trace_read_data(cpu);
2693}
2694
2695/* Signal a overhead of time execution to the output */
2696static void print_graph_overhead(unsigned long long duration)
2697{
2698 /* Non nested entry or return */
2699 if (duration == ~0ULL)
2700 return (void)printf(" ");
2701
2702 /* Duration exceeded 100 msecs */
2703 if (duration > 100000ULL)
2704 return (void)printf("! ");
2705
2706 /* Duration exceeded 10 msecs */
2707 if (duration > 10000ULL)
2708 return (void)printf("+ ");
2709
2710 printf(" ");
2711}
2712
2713static void print_graph_duration(unsigned long long duration)
2714{
2715 unsigned long usecs = duration / 1000;
2716 unsigned long nsecs_rem = duration % 1000;
2717 /* log10(ULONG_MAX) + '\0' */
2718 char msecs_str[21];
2719 char nsecs_str[5];
2720 int len;
2721 int i;
2722
2723 sprintf(msecs_str, "%lu", usecs);
2724
2725 /* Print msecs */
2726 len = printf("%lu", usecs);
2727
2728 /* Print nsecs (we don't want to exceed 7 numbers) */
2729 if (len < 7) {
2730 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2731 len += printf(".%s", nsecs_str);
2732 }
2733
2734 printf(" us ");
2735
2736 /* Print remaining spaces to fit the row's width */
2737 for (i = len; i < 7; i++)
2738 printf(" ");
2739
2740 printf("| ");
2741}
2742
2743static void
2744print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2745{
2746 unsigned long long rettime, calltime;
2747 unsigned long long duration, depth;
2748 unsigned long long val;
2749 struct format_field *field;
2750 struct func_map *func;
2751 struct event *ret_event;
2752 int type;
2753 int i;
2754
2755 type = trace_parse_common_type(ret_rec->data);
2756 ret_event = trace_find_event(type);
2757
2758 field = find_field(ret_event, "rettime");
2759 if (!field)
2760 die("can't find rettime in return graph");
2761 rettime = read_size(ret_rec->data + field->offset, field->size);
2762
2763 field = find_field(ret_event, "calltime");
2764 if (!field)
2765 die("can't find rettime in return graph");
2766 calltime = read_size(ret_rec->data + field->offset, field->size);
2767
2768 duration = rettime - calltime;
2769
2770 /* Overhead */
2771 print_graph_overhead(duration);
2772
2773 /* Duration */
2774 print_graph_duration(duration);
2775
2776 field = find_field(event, "depth");
2777 if (!field)
2778 die("can't find depth in entry graph");
2779 depth = read_size(data + field->offset, field->size);
2780
2781 /* Function */
2782 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2783 printf(" ");
2784
2785 field = find_field(event, "func");
2786 if (!field)
2787 die("can't find func in entry graph");
2788 val = read_size(data + field->offset, field->size);
2789 func = find_func(val);
2790
2791 if (func)
2792 printf("%s();", func->func);
2793 else
2794 printf("%llx();", val);
2795}
2796
2797static void print_graph_nested(struct event *event, void *data)
2798{
2799 struct format_field *field;
2800 unsigned long long depth;
2801 unsigned long long val;
2802 struct func_map *func;
2803 int i;
2804
2805 /* No overhead */
2806 print_graph_overhead(-1);
2807
2808 /* No time */
2809 printf(" | ");
2810
2811 field = find_field(event, "depth");
2812 if (!field)
2813 die("can't find depth in entry graph");
2814 depth = read_size(data + field->offset, field->size);
2815
2816 /* Function */
2817 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2818 printf(" ");
2819
2820 field = find_field(event, "func");
2821 if (!field)
2822 die("can't find func in entry graph");
2823 val = read_size(data + field->offset, field->size);
2824 func = find_func(val);
2825
2826 if (func)
2827 printf("%s() {", func->func);
2828 else
2829 printf("%llx() {", val);
2830}
2831
2832static void
2833pretty_print_func_ent(void *data, int size, struct event *event,
2834 int cpu, int pid)
2835{
2836 struct format_field *field;
2837 struct record *rec;
2838 void *copy_data;
2839 unsigned long val;
2840
2841 if (latency_format) {
2842 print_lat_fmt(data, size);
2843 printf(" | ");
2844 }
2845
2846 field = find_field(event, "func");
2847 if (!field)
2848 die("function entry does not have func field");
2849
2850 val = read_size(data + field->offset, field->size);
2851
2852 /*
2853 * peek_data may unmap the data pointer. Copy it first.
2854 */
2855 copy_data = malloc_or_die(size);
2856 memcpy(copy_data, data, size);
2857 data = copy_data;
2858
2859 rec = trace_peek_data(cpu);
2860 if (rec) {
2861 rec = get_return_for_leaf(cpu, pid, val, rec);
2862 if (rec) {
2863 print_graph_entry_leaf(event, data, rec);
2864 goto out_free;
2865 }
2866 }
2867 print_graph_nested(event, data);
2868out_free:
2869 free(data);
2870}
2871
2872static void
2873pretty_print_func_ret(void *data, int size __unused, struct event *event)
2874{
2875 unsigned long long rettime, calltime;
2876 unsigned long long duration, depth;
2877 struct format_field *field;
2878 int i;
2879
2880 if (latency_format) {
2881 print_lat_fmt(data, size);
2882 printf(" | ");
2883 }
2884
2885 field = find_field(event, "rettime");
2886 if (!field)
2887 die("can't find rettime in return graph");
2888 rettime = read_size(data + field->offset, field->size);
2889
2890 field = find_field(event, "calltime");
2891 if (!field)
2892 die("can't find calltime in return graph");
2893 calltime = read_size(data + field->offset, field->size);
2894
2895 duration = rettime - calltime;
2896
2897 /* Overhead */
2898 print_graph_overhead(duration);
2899
2900 /* Duration */
2901 print_graph_duration(duration);
2902
2903 field = find_field(event, "depth");
2904 if (!field)
2905 die("can't find depth in entry graph");
2906 depth = read_size(data + field->offset, field->size);
2907
2908 /* Function */
2909 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2910 printf(" ");
2911
2912 printf("}");
2913}
2914
2915static void
2916pretty_print_func_graph(void *data, int size, struct event *event,
2917 int cpu, int pid)
2918{
2919 if (event->flags & EVENT_FL_ISFUNCENT)
2920 pretty_print_func_ent(data, size, event, cpu, pid);
2921 else if (event->flags & EVENT_FL_ISFUNCRET)
2922 pretty_print_func_ret(data, size, event);
2923 printf("\n");
2924}
2925
2926void print_trace_event(int cpu, void *data, int size)
2927{
2928 struct event *event;
2929 int type;
2930 int pid;
2931
2932 type = trace_parse_common_type(data);
2933
2934 event = trace_find_event(type);
2935 if (!event) {
2936 warning("ug! no event found for type %d", type);
2937 return;
2938 }
2939
2940 pid = trace_parse_common_pid(data);
2941
2942 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2943 return pretty_print_func_graph(data, size, event, cpu, pid);
2944
2945 if (latency_format)
2946 print_lat_fmt(data, size);
2947
2948 if (event->flags & EVENT_FL_FAILED) {
2949 printf("EVENT '%s' FAILED TO PARSE\n",
2950 event->name);
2951 return;
2952 }
2953
2954 pretty_print(data, size, event);
2955}
2956
2957static void print_fields(struct print_flag_sym *field)
2958{
2959 printf("{ %s, %s }", field->value, field->str);
2960 if (field->next) {
2961 printf(", ");
2962 print_fields(field->next);
2963 }
2964}
2965
2966static void print_args(struct print_arg *args)
2967{
2968 int print_paren = 1;
2969
2970 switch (args->type) {
2971 case PRINT_NULL:
2972 printf("null");
2973 break;
2974 case PRINT_ATOM:
2975 printf("%s", args->atom.atom);
2976 break;
2977 case PRINT_FIELD:
2978 printf("REC->%s", args->field.name);
2979 break;
2980 case PRINT_FLAGS:
2981 printf("__print_flags(");
2982 print_args(args->flags.field);
2983 printf(", %s, ", args->flags.delim);
2984 print_fields(args->flags.flags);
2985 printf(")");
2986 break;
2987 case PRINT_SYMBOL:
2988 printf("__print_symbolic(");
2989 print_args(args->symbol.field);
2990 printf(", ");
2991 print_fields(args->symbol.symbols);
2992 printf(")");
2993 break;
2994 case PRINT_STRING:
2995 printf("__get_str(%s)", args->string.string);
2996 break;
2997 case PRINT_TYPE:
2998 printf("(%s)", args->typecast.type);
2999 print_args(args->typecast.item);
3000 break;
3001 case PRINT_OP:
3002 if (strcmp(args->op.op, ":") == 0)
3003 print_paren = 0;
3004 if (print_paren)
3005 printf("(");
3006 print_args(args->op.left);
3007 printf(" %s ", args->op.op);
3008 print_args(args->op.right);
3009 if (print_paren)
3010 printf(")");
3011 break;
3012 default:
3013 /* we should warn... */
3014 return;
3015 }
3016 if (args->next) {
3017 printf("\n");
3018 print_args(args->next);
3019 }
3020}
3021
3022int parse_ftrace_file(char *buf, unsigned long size)
3023{
3024 struct format_field *field;
3025 struct print_arg *arg, **list;
3026 struct event *event;
3027 int ret;
3028
3029 init_input_buf(buf, size);
3030
3031 event = alloc_event();
3032 if (!event)
3033 return -ENOMEM;
3034
3035 event->flags |= EVENT_FL_ISFTRACE;
3036
3037 event->name = event_read_name();
3038 if (!event->name)
3039 die("failed to read ftrace event name");
3040
3041 if (strcmp(event->name, "function") == 0)
3042 event->flags |= EVENT_FL_ISFUNC;
3043
3044 else if (strcmp(event->name, "funcgraph_entry") == 0)
3045 event->flags |= EVENT_FL_ISFUNCENT;
3046
3047 else if (strcmp(event->name, "funcgraph_exit") == 0)
3048 event->flags |= EVENT_FL_ISFUNCRET;
3049
3050 else if (strcmp(event->name, "bprint") == 0)
3051 event->flags |= EVENT_FL_ISBPRINT;
3052
3053 event->id = event_read_id();
3054 if (event->id < 0)
3055 die("failed to read ftrace event id");
3056
3057 add_event(event);
3058
3059 ret = event_read_format(event);
3060 if (ret < 0)
3061 die("failed to read ftrace event format");
3062
3063 ret = event_read_print(event);
3064 if (ret < 0)
3065 die("failed to read ftrace event print fmt");
3066
3067 /* New ftrace handles args */
3068 if (ret > 0)
3069 return 0;
3070 /*
3071 * The arguments for ftrace files are parsed by the fields.
3072 * Set up the fields as their arguments.
3073 */
3074 list = &event->print_fmt.args;
3075 for (field = event->format.fields; field; field = field->next) {
3076 arg = malloc_or_die(sizeof(*arg));
3077 memset(arg, 0, sizeof(*arg));
3078 *list = arg;
3079 list = &arg->next;
3080 arg->type = PRINT_FIELD;
3081 arg->field.name = field->name;
3082 arg->field.field = field;
3083 }
3084 return 0;
3085}
3086
3087int parse_event_file(char *buf, unsigned long size, char *sys)
3088{
3089 struct event *event;
3090 int ret;
3091
3092 init_input_buf(buf, size);
3093
3094 event = alloc_event();
3095 if (!event)
3096 return -ENOMEM;
3097
3098 event->name = event_read_name();
3099 if (!event->name)
3100 die("failed to read event name");
3101
3102 event->id = event_read_id();
3103 if (event->id < 0)
3104 die("failed to read event id");
3105
3106 ret = event_read_format(event);
3107 if (ret < 0) {
3108 warning("failed to read event format for %s", event->name);
3109 goto event_failed;
3110 }
3111
3112 ret = event_read_print(event);
3113 if (ret < 0) {
3114 warning("failed to read event print fmt for %s", event->name);
3115 goto event_failed;
3116 }
3117
3118 event->system = strdup(sys);
3119
3120#define PRINT_ARGS 0
3121 if (PRINT_ARGS && event->print_fmt.args)
3122 print_args(event->print_fmt.args);
3123
3124 add_event(event);
3125 return 0;
3126
3127 event_failed:
3128 event->flags |= EVENT_FL_FAILED;
3129 /* still add it even if it failed */
3130 add_event(event);
3131 return -1;
3132}
3133
3134void parse_set_info(int nr_cpus, int long_sz)
3135{
3136 cpus = nr_cpus;
3137 long_size = long_sz;
3138}
3139
3140int common_pc(struct scripting_context *context)
3141{
3142 return parse_common_pc(context->event_data);
3143}
3144
3145int common_flags(struct scripting_context *context)
3146{
3147 return parse_common_flags(context->event_data);
3148}
3149
3150int common_lock_depth(struct scripting_context *context)
3151{
3152 return parse_common_lock_depth(context->event_data);
3153}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index b9592e0de8d7..f097e0dd6c5c 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -52,6 +52,16 @@ static unsigned long page_size;
52static ssize_t calc_data_size; 52static ssize_t calc_data_size;
53static bool repipe; 53static bool repipe;
54 54
55static void *malloc_or_die(int size)
56{
57 void *ret;
58
59 ret = malloc(size);
60 if (!ret)
61 die("malloc");
62 return ret;
63}
64
55static int do_read(int fd, void *buf, int size) 65static int do_read(int fd, void *buf, int size)
56{ 66{
57 int rsize = size; 67 int rsize = size;
@@ -109,7 +119,7 @@ static unsigned int read4(void)
109 unsigned int data; 119 unsigned int data;
110 120
111 read_or_die(&data, 4); 121 read_or_die(&data, 4);
112 return __data2host4(data); 122 return __data2host4(perf_pevent, data);
113} 123}
114 124
115static unsigned long long read8(void) 125static unsigned long long read8(void)
@@ -117,7 +127,7 @@ static unsigned long long read8(void)
117 unsigned long long data; 127 unsigned long long data;
118 128
119 read_or_die(&data, 8); 129 read_or_die(&data, 8);
120 return __data2host8(data); 130 return __data2host8(perf_pevent, data);
121} 131}
122 132
123static char *read_string(void) 133static char *read_string(void)
@@ -282,7 +292,7 @@ struct cpu_data {
282 unsigned long long offset; 292 unsigned long long offset;
283 unsigned long long size; 293 unsigned long long size;
284 unsigned long long timestamp; 294 unsigned long long timestamp;
285 struct record *next; 295 struct pevent_record *next;
286 char *page; 296 char *page;
287 int cpu; 297 int cpu;
288 int index; 298 int index;
@@ -367,9 +377,9 @@ static int calc_index(void *ptr, int cpu)
367 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; 377 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
368} 378}
369 379
370struct record *trace_peek_data(int cpu) 380struct pevent_record *trace_peek_data(int cpu)
371{ 381{
372 struct record *data; 382 struct pevent_record *data;
373 void *page = cpu_data[cpu].page; 383 void *page = cpu_data[cpu].page;
374 int idx = cpu_data[cpu].index; 384 int idx = cpu_data[cpu].index;
375 void *ptr = page + idx; 385 void *ptr = page + idx;
@@ -389,15 +399,15 @@ struct record *trace_peek_data(int cpu)
389 /* FIXME: handle header page */ 399 /* FIXME: handle header page */
390 if (header_page_ts_size != 8) 400 if (header_page_ts_size != 8)
391 die("expected a long long type for timestamp"); 401 die("expected a long long type for timestamp");
392 cpu_data[cpu].timestamp = data2host8(ptr); 402 cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr);
393 ptr += 8; 403 ptr += 8;
394 switch (header_page_size_size) { 404 switch (header_page_size_size) {
395 case 4: 405 case 4:
396 cpu_data[cpu].page_size = data2host4(ptr); 406 cpu_data[cpu].page_size = data2host4(perf_pevent, ptr);
397 ptr += 4; 407 ptr += 4;
398 break; 408 break;
399 case 8: 409 case 8:
400 cpu_data[cpu].page_size = data2host8(ptr); 410 cpu_data[cpu].page_size = data2host8(perf_pevent, ptr);
401 ptr += 8; 411 ptr += 8;
402 break; 412 break;
403 default: 413 default:
@@ -414,7 +424,7 @@ read_again:
414 return trace_peek_data(cpu); 424 return trace_peek_data(cpu);
415 } 425 }
416 426
417 type_len_ts = data2host4(ptr); 427 type_len_ts = data2host4(perf_pevent, ptr);
418 ptr += 4; 428 ptr += 4;
419 429
420 type_len = type_len4host(type_len_ts); 430 type_len = type_len4host(type_len_ts);
@@ -424,14 +434,14 @@ read_again:
424 case RINGBUF_TYPE_PADDING: 434 case RINGBUF_TYPE_PADDING:
425 if (!delta) 435 if (!delta)
426 die("error, hit unexpected end of page"); 436 die("error, hit unexpected end of page");
427 length = data2host4(ptr); 437 length = data2host4(perf_pevent, ptr);
428 ptr += 4; 438 ptr += 4;
429 length *= 4; 439 length *= 4;
430 ptr += length; 440 ptr += length;
431 goto read_again; 441 goto read_again;
432 442
433 case RINGBUF_TYPE_TIME_EXTEND: 443 case RINGBUF_TYPE_TIME_EXTEND:
434 extend = data2host4(ptr); 444 extend = data2host4(perf_pevent, ptr);
435 ptr += 4; 445 ptr += 4;
436 extend <<= TS_SHIFT; 446 extend <<= TS_SHIFT;
437 extend += delta; 447 extend += delta;
@@ -442,7 +452,7 @@ read_again:
442 ptr += 12; 452 ptr += 12;
443 break; 453 break;
444 case 0: 454 case 0:
445 length = data2host4(ptr); 455 length = data2host4(perf_pevent, ptr);
446 ptr += 4; 456 ptr += 4;
447 die("here! length=%d", length); 457 die("here! length=%d", length);
448 break; 458 break;
@@ -467,9 +477,9 @@ read_again:
467 return data; 477 return data;
468} 478}
469 479
470struct record *trace_read_data(int cpu) 480struct pevent_record *trace_read_data(int cpu)
471{ 481{
472 struct record *data; 482 struct pevent_record *data;
473 483
474 data = trace_peek_data(cpu); 484 data = trace_peek_data(cpu);
475 cpu_data[cpu].next = NULL; 485 cpu_data[cpu].next = NULL;
@@ -509,6 +519,8 @@ ssize_t trace_report(int fd, bool __repipe)
509 file_bigendian = buf[0]; 519 file_bigendian = buf[0];
510 host_bigendian = bigendian(); 520 host_bigendian = bigendian();
511 521
522 read_trace_init(file_bigendian, host_bigendian);
523
512 read_or_die(buf, 1); 524 read_or_die(buf, 1);
513 long_size = buf[0]; 525 long_size = buf[0];
514 526
@@ -526,11 +538,11 @@ ssize_t trace_report(int fd, bool __repipe)
526 repipe = false; 538 repipe = false;
527 539
528 if (show_funcs) { 540 if (show_funcs) {
529 print_funcs(); 541 pevent_print_funcs(perf_pevent);
530 return size; 542 return size;
531 } 543 }
532 if (show_printk) { 544 if (show_printk) {
533 print_printk(); 545 pevent_print_printk(perf_pevent);
534 return size; 546 return size;
535 } 547 }
536 548
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 58ae14c5baac..639852ac1117 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,20 +1,21 @@
1#ifndef __PERF_TRACE_EVENTS_H 1#ifndef _PERF_UTIL_TRACE_EVENT_H
2#define __PERF_TRACE_EVENTS_H 2#define _PERF_UTIL_TRACE_EVENT_H
3 3
4#include <stdbool.h>
5#include "parse-events.h" 4#include "parse-events.h"
5#include "event-parse.h"
6#include "session.h"
6 7
7struct machine; 8struct machine;
8struct perf_sample; 9struct perf_sample;
9union perf_event; 10union perf_event;
10struct thread; 11struct thread;
11 12
12#define __unused __attribute__((unused)) 13extern int header_page_size_size;
13 14extern int header_page_ts_size;
15extern int header_page_data_offset;
14 16
15#ifndef PAGE_MASK 17extern bool latency_format;
16#define PAGE_MASK (page_size - 1) 18extern struct pevent *perf_pevent;
17#endif
18 19
19enum { 20enum {
20 RINGBUF_TYPE_PADDING = 29, 21 RINGBUF_TYPE_PADDING = 29,
@@ -26,246 +27,37 @@ enum {
26#define TS_SHIFT 27 27#define TS_SHIFT 27
27#endif 28#endif
28 29
29#define NSECS_PER_SEC 1000000000ULL 30int bigendian(void);
30#define NSECS_PER_USEC 1000ULL
31
32enum format_flags {
33 FIELD_IS_ARRAY = 1,
34 FIELD_IS_POINTER = 2,
35 FIELD_IS_SIGNED = 4,
36 FIELD_IS_STRING = 8,
37 FIELD_IS_DYNAMIC = 16,
38 FIELD_IS_FLAG = 32,
39 FIELD_IS_SYMBOLIC = 64,
40};
41
42struct format_field {
43 struct format_field *next;
44 char *type;
45 char *name;
46 int offset;
47 int size;
48 unsigned long flags;
49};
50
51struct format {
52 int nr_common;
53 int nr_fields;
54 struct format_field *common_fields;
55 struct format_field *fields;
56};
57
58struct print_arg_atom {
59 char *atom;
60};
61
62struct print_arg_string {
63 char *string;
64 int offset;
65};
66
67struct print_arg_field {
68 char *name;
69 struct format_field *field;
70};
71
72struct print_flag_sym {
73 struct print_flag_sym *next;
74 char *value;
75 char *str;
76};
77
78struct print_arg_typecast {
79 char *type;
80 struct print_arg *item;
81};
82
83struct print_arg_flags {
84 struct print_arg *field;
85 char *delim;
86 struct print_flag_sym *flags;
87};
88
89struct print_arg_symbol {
90 struct print_arg *field;
91 struct print_flag_sym *symbols;
92};
93
94struct print_arg;
95
96struct print_arg_op {
97 char *op;
98 int prio;
99 struct print_arg *left;
100 struct print_arg *right;
101};
102
103struct print_arg_func {
104 char *name;
105 struct print_arg *args;
106};
107
108enum print_arg_type {
109 PRINT_NULL,
110 PRINT_ATOM,
111 PRINT_FIELD,
112 PRINT_FLAGS,
113 PRINT_SYMBOL,
114 PRINT_TYPE,
115 PRINT_STRING,
116 PRINT_OP,
117};
118
119struct print_arg {
120 struct print_arg *next;
121 enum print_arg_type type;
122 union {
123 struct print_arg_atom atom;
124 struct print_arg_field field;
125 struct print_arg_typecast typecast;
126 struct print_arg_flags flags;
127 struct print_arg_symbol symbol;
128 struct print_arg_func func;
129 struct print_arg_string string;
130 struct print_arg_op op;
131 };
132};
133
134struct print_fmt {
135 char *format;
136 struct print_arg *args;
137};
138
139struct event {
140 struct event *next;
141 char *name;
142 int id;
143 int flags;
144 struct format format;
145 struct print_fmt print_fmt;
146 char *system;
147};
148
149enum {
150 EVENT_FL_ISFTRACE = 0x01,
151 EVENT_FL_ISPRINT = 0x02,
152 EVENT_FL_ISBPRINT = 0x04,
153 EVENT_FL_ISFUNC = 0x08,
154 EVENT_FL_ISFUNCENT = 0x10,
155 EVENT_FL_ISFUNCRET = 0x20,
156
157 EVENT_FL_FAILED = 0x80000000
158};
159
160struct record {
161 unsigned long long ts;
162 int size;
163 void *data;
164};
165
166struct record *trace_peek_data(int cpu);
167struct record *trace_read_data(int cpu);
168
169void parse_set_info(int nr_cpus, int long_sz);
170
171ssize_t trace_report(int fd, bool repipe);
172
173void *malloc_or_die(unsigned int size);
174 31
175void parse_cmdlines(char *file, int size); 32int read_trace_init(int file_bigendian, int host_bigendian);
176void parse_proc_kallsyms(char *file, unsigned int size); 33void print_trace_event(int cpu, void *data, int size);
177void parse_ftrace_printk(char *file, unsigned int size);
178 34
179void print_funcs(void); 35void print_event(int cpu, void *data, int size, unsigned long long nsecs,
180void print_printk(void); 36 char *comm);
181 37
182int parse_ftrace_file(char *buf, unsigned long size); 38int parse_ftrace_file(char *buf, unsigned long size);
183int parse_event_file(char *buf, unsigned long size, char *sys); 39int parse_event_file(char *buf, unsigned long size, char *sys);
184void print_trace_event(int cpu, void *data, int size);
185
186extern int file_bigendian;
187extern int host_bigendian;
188
189int bigendian(void);
190
191static inline unsigned short __data2host2(unsigned short data)
192{
193 unsigned short swap;
194
195 if (host_bigendian == file_bigendian)
196 return data;
197 40
198 swap = ((data & 0xffULL) << 8) | 41struct pevent_record *trace_peek_data(int cpu);
199 ((data & (0xffULL << 8)) >> 8); 42struct event_format *trace_find_event(int type);
200 43
201 return swap; 44unsigned long long
202} 45raw_field_value(struct event_format *event, const char *name, void *data);
203 46void *raw_field_ptr(struct event_format *event, const char *name, void *data);
204static inline unsigned int __data2host4(unsigned int data)
205{
206 unsigned int swap;
207
208 if (host_bigendian == file_bigendian)
209 return data;
210
211 swap = ((data & 0xffULL) << 24) |
212 ((data & (0xffULL << 8)) << 8) |
213 ((data & (0xffULL << 16)) >> 8) |
214 ((data & (0xffULL << 24)) >> 24);
215
216 return swap;
217}
218
219static inline unsigned long long __data2host8(unsigned long long data)
220{
221 unsigned long long swap;
222
223 if (host_bigendian == file_bigendian)
224 return data;
225
226 swap = ((data & 0xffULL) << 56) |
227 ((data & (0xffULL << 8)) << 40) |
228 ((data & (0xffULL << 16)) << 24) |
229 ((data & (0xffULL << 24)) << 8) |
230 ((data & (0xffULL << 32)) >> 8) |
231 ((data & (0xffULL << 40)) >> 24) |
232 ((data & (0xffULL << 48)) >> 40) |
233 ((data & (0xffULL << 56)) >> 56);
234
235 return swap;
236}
237 47
238#define data2host2(ptr) __data2host2(*(unsigned short *)ptr) 48void parse_proc_kallsyms(char *file, unsigned int size __unused);
239#define data2host4(ptr) __data2host4(*(unsigned int *)ptr) 49void parse_ftrace_printk(char *file, unsigned int size __unused);
240#define data2host8(ptr) ({ \
241 unsigned long long __val; \
242 \
243 memcpy(&__val, (ptr), sizeof(unsigned long long)); \
244 __data2host8(__val); \
245})
246 50
247extern int header_page_ts_offset; 51ssize_t trace_report(int fd, bool repipe);
248extern int header_page_ts_size;
249extern int header_page_size_offset;
250extern int header_page_size_size;
251extern int header_page_data_offset;
252extern int header_page_data_size;
253
254extern bool latency_format;
255 52
256int trace_parse_common_type(void *data); 53int trace_parse_common_type(void *data);
257int trace_parse_common_pid(void *data); 54int trace_parse_common_pid(void *data);
258int parse_common_pc(void *data); 55
259int parse_common_flags(void *data); 56struct event_format *trace_find_next_event(struct event_format *event);
260int parse_common_lock_depth(void *data);
261struct event *trace_find_event(int id);
262struct event *trace_find_next_event(struct event *event);
263unsigned long long read_size(void *ptr, int size); 57unsigned long long read_size(void *ptr, int size);
264unsigned long long
265raw_field_value(struct event *event, const char *name, void *data);
266void *raw_field_ptr(struct event *event, const char *name, void *data);
267unsigned long long eval_flag(const char *flag); 58unsigned long long eval_flag(const char *flag);
268 59
60struct pevent_record *trace_read_data(int cpu);
269int read_tracing_data(int fd, struct list_head *pattrs); 61int read_tracing_data(int fd, struct list_head *pattrs);
270 62
271struct tracing_data { 63struct tracing_data {
@@ -280,15 +72,6 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
280void tracing_data_put(struct tracing_data *tdata); 72void tracing_data_put(struct tracing_data *tdata);
281 73
282 74
283/* taken from kernel/trace/trace.h */
284enum trace_flag_type {
285 TRACE_FLAG_IRQS_OFF = 0x01,
286 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
287 TRACE_FLAG_NEED_RESCHED = 0x04,
288 TRACE_FLAG_HARDIRQ = 0x08,
289 TRACE_FLAG_SOFTIRQ = 0x10,
290};
291
292struct scripting_ops { 75struct scripting_ops {
293 const char *name; 76 const char *name;
294 int (*start_script) (const char *script, int argc, const char **argv); 77 int (*start_script) (const char *script, int argc, const char **argv);
@@ -314,4 +97,4 @@ int common_pc(struct scripting_context *context);
314int common_flags(struct scripting_context *context); 97int common_flags(struct scripting_context *context);
315int common_lock_depth(struct scripting_context *context); 98int common_lock_depth(struct scripting_context *context);
316 99
317#endif /* __PERF_TRACE_EVENTS_H */ 100#endif /* _PERF_UTIL_TRACE_EVENT_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5f3689a3d085..c51fa6b70a28 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -16,4 +16,9 @@ typedef signed short s16;
16typedef unsigned char u8; 16typedef unsigned char u8;
17typedef signed char s8; 17typedef signed char s8;
18 18
19union u64_swap {
20 u64 val64;
21 u32 val32[2];
22};
23
19#endif /* __PERF_TYPES_H */ 24#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
deleted file mode 100644
index 57a4c6ef3fd2..000000000000
--- a/tools/perf/util/ui/browsers/annotate.c
+++ /dev/null
@@ -1,433 +0,0 @@
1#include "../../util.h"
2#include "../browser.h"
3#include "../helpline.h"
4#include "../libslang.h"
5#include "../ui.h"
6#include "../util.h"
7#include "../../annotate.h"
8#include "../../hist.h"
9#include "../../sort.h"
10#include "../../symbol.h"
11#include <pthread.h>
12#include <newt.h>
13
14struct annotate_browser {
15 struct ui_browser b;
16 struct rb_root entries;
17 struct rb_node *curr_hot;
18 struct objdump_line *selection;
19 int nr_asm_entries;
20 int nr_entries;
21 bool hide_src_code;
22};
23
24struct objdump_line_rb_node {
25 struct rb_node rb_node;
26 double percent;
27 u32 idx;
28 int idx_asm;
29};
30
31static inline
32struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
33{
34 return (struct objdump_line_rb_node *)(self + 1);
35}
36
37static bool objdump_line__filter(struct ui_browser *browser, void *entry)
38{
39 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
40
41 if (ab->hide_src_code) {
42 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
43 return ol->offset == -1;
44 }
45
46 return false;
47}
48
49static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
50{
51 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
52 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
53 bool current_entry = ui_browser__is_current_entry(self, row);
54 int width = self->width;
55
56 if (ol->offset != -1) {
57 struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
58 ui_browser__set_percent_color(self, olrb->percent, current_entry);
59 slsmg_printf(" %7.2f ", olrb->percent);
60 } else {
61 ui_browser__set_percent_color(self, 0, current_entry);
62 slsmg_write_nstring(" ", 9);
63 }
64
65 SLsmg_write_char(':');
66 slsmg_write_nstring(" ", 8);
67
68 /* The scroll bar isn't being used */
69 if (!self->navkeypressed)
70 width += 1;
71
72 if (!ab->hide_src_code && ol->offset != -1)
73 if (!current_entry || (self->use_navkeypressed &&
74 !self->navkeypressed))
75 ui_browser__set_color(self, HE_COLORSET_CODE);
76
77 if (!*ol->line)
78 slsmg_write_nstring(" ", width - 18);
79 else
80 slsmg_write_nstring(ol->line, width - 18);
81
82 if (current_entry)
83 ab->selection = ol;
84}
85
86static double objdump_line__calc_percent(struct objdump_line *self,
87 struct symbol *sym, int evidx)
88{
89 double percent = 0.0;
90
91 if (self->offset != -1) {
92 int len = sym->end - sym->start;
93 unsigned int hits = 0;
94 struct annotation *notes = symbol__annotation(sym);
95 struct source_line *src_line = notes->src->lines;
96 struct sym_hist *h = annotation__histogram(notes, evidx);
97 s64 offset = self->offset;
98 struct objdump_line *next;
99
100 next = objdump__get_next_ip_line(&notes->src->source, self);
101 while (offset < (s64)len &&
102 (next == NULL || offset < next->offset)) {
103 if (src_line) {
104 percent += src_line[offset].percent;
105 } else
106 hits += h->addr[offset];
107
108 ++offset;
109 }
110 /*
111 * If the percentage wasn't already calculated in
112 * symbol__get_source_line, do it now:
113 */
114 if (src_line == NULL && h->sum)
115 percent = 100.0 * hits / h->sum;
116 }
117
118 return percent;
119}
120
121static void objdump__insert_line(struct rb_root *self,
122 struct objdump_line_rb_node *line)
123{
124 struct rb_node **p = &self->rb_node;
125 struct rb_node *parent = NULL;
126 struct objdump_line_rb_node *l;
127
128 while (*p != NULL) {
129 parent = *p;
130 l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
131 if (line->percent < l->percent)
132 p = &(*p)->rb_left;
133 else
134 p = &(*p)->rb_right;
135 }
136 rb_link_node(&line->rb_node, parent, p);
137 rb_insert_color(&line->rb_node, self);
138}
139
140static void annotate_browser__set_top(struct annotate_browser *self,
141 struct rb_node *nd)
142{
143 struct objdump_line_rb_node *rbpos;
144 struct objdump_line *pos;
145 unsigned back;
146
147 ui_browser__refresh_dimensions(&self->b);
148 back = self->b.height / 2;
149 rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
150 pos = ((struct objdump_line *)rbpos) - 1;
151 self->b.top_idx = self->b.index = rbpos->idx;
152
153 while (self->b.top_idx != 0 && back != 0) {
154 pos = list_entry(pos->node.prev, struct objdump_line, node);
155
156 --self->b.top_idx;
157 --back;
158 }
159
160 self->b.top = pos;
161 self->curr_hot = nd;
162}
163
164static void annotate_browser__calc_percent(struct annotate_browser *browser,
165 int evidx)
166{
167 struct map_symbol *ms = browser->b.priv;
168 struct symbol *sym = ms->sym;
169 struct annotation *notes = symbol__annotation(sym);
170 struct objdump_line *pos;
171
172 browser->entries = RB_ROOT;
173
174 pthread_mutex_lock(&notes->lock);
175
176 list_for_each_entry(pos, &notes->src->source, node) {
177 struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
178 rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
179 if (rbpos->percent < 0.01) {
180 RB_CLEAR_NODE(&rbpos->rb_node);
181 continue;
182 }
183 objdump__insert_line(&browser->entries, rbpos);
184 }
185 pthread_mutex_unlock(&notes->lock);
186
187 browser->curr_hot = rb_last(&browser->entries);
188}
189
190static bool annotate_browser__toggle_source(struct annotate_browser *browser)
191{
192 struct objdump_line *ol;
193 struct objdump_line_rb_node *olrb;
194 off_t offset = browser->b.index - browser->b.top_idx;
195
196 browser->b.seek(&browser->b, offset, SEEK_CUR);
197 ol = list_entry(browser->b.top, struct objdump_line, node);
198 olrb = objdump_line__rb(ol);
199
200 if (browser->hide_src_code) {
201 if (olrb->idx_asm < offset)
202 offset = olrb->idx;
203
204 browser->b.nr_entries = browser->nr_entries;
205 browser->hide_src_code = false;
206 browser->b.seek(&browser->b, -offset, SEEK_CUR);
207 browser->b.top_idx = olrb->idx - offset;
208 browser->b.index = olrb->idx;
209 } else {
210 if (olrb->idx_asm < 0) {
211 ui_helpline__puts("Only available for assembly lines.");
212 browser->b.seek(&browser->b, -offset, SEEK_CUR);
213 return false;
214 }
215
216 if (olrb->idx_asm < offset)
217 offset = olrb->idx_asm;
218
219 browser->b.nr_entries = browser->nr_asm_entries;
220 browser->hide_src_code = true;
221 browser->b.seek(&browser->b, -offset, SEEK_CUR);
222 browser->b.top_idx = olrb->idx_asm - offset;
223 browser->b.index = olrb->idx_asm;
224 }
225
226 return true;
227}
228
229static int annotate_browser__run(struct annotate_browser *self, int evidx,
230 void(*timer)(void *arg),
231 void *arg, int delay_secs)
232{
233 struct rb_node *nd = NULL;
234 struct map_symbol *ms = self->b.priv;
235 struct symbol *sym = ms->sym;
236 const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
237 "H: Go to hottest line, ->/ENTER: Line action, "
238 "S: Toggle source code view";
239 int key;
240
241 if (ui_browser__show(&self->b, sym->name, help) < 0)
242 return -1;
243
244 annotate_browser__calc_percent(self, evidx);
245
246 if (self->curr_hot)
247 annotate_browser__set_top(self, self->curr_hot);
248
249 nd = self->curr_hot;
250
251 while (1) {
252 key = ui_browser__run(&self->b, delay_secs);
253
254 if (delay_secs != 0) {
255 annotate_browser__calc_percent(self, evidx);
256 /*
257 * Current line focus got out of the list of most active
258 * lines, NULL it so that if TAB|UNTAB is pressed, we
259 * move to curr_hot (current hottest line).
260 */
261 if (nd != NULL && RB_EMPTY_NODE(nd))
262 nd = NULL;
263 }
264
265 switch (key) {
266 case K_TIMER:
267 if (timer != NULL)
268 timer(arg);
269
270 if (delay_secs != 0)
271 symbol__annotate_decay_histogram(sym, evidx);
272 continue;
273 case K_TAB:
274 if (nd != NULL) {
275 nd = rb_prev(nd);
276 if (nd == NULL)
277 nd = rb_last(&self->entries);
278 } else
279 nd = self->curr_hot;
280 break;
281 case K_UNTAB:
282 if (nd != NULL)
283 nd = rb_next(nd);
284 if (nd == NULL)
285 nd = rb_first(&self->entries);
286 else
287 nd = self->curr_hot;
288 break;
289 case 'H':
290 case 'h':
291 nd = self->curr_hot;
292 break;
293 case 'S':
294 case 's':
295 if (annotate_browser__toggle_source(self))
296 ui_helpline__puts(help);
297 continue;
298 case K_ENTER:
299 case K_RIGHT:
300 if (self->selection == NULL) {
301 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
302 continue;
303 }
304
305 if (self->selection->offset == -1) {
306 ui_helpline__puts("Actions are only available for assembly lines.");
307 continue;
308 } else {
309 char *s = strstr(self->selection->line, "callq ");
310 struct annotation *notes;
311 struct symbol *target;
312 u64 ip;
313
314 if (s == NULL) {
315 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
316 continue;
317 }
318
319 s = strchr(s, ' ');
320 if (s++ == NULL) {
321 ui_helpline__puts("Invallid callq instruction.");
322 continue;
323 }
324
325 ip = strtoull(s, NULL, 16);
326 ip = ms->map->map_ip(ms->map, ip);
327 target = map__find_symbol(ms->map, ip, NULL);
328 if (target == NULL) {
329 ui_helpline__puts("The called function was not found.");
330 continue;
331 }
332
333 notes = symbol__annotation(target);
334 pthread_mutex_lock(&notes->lock);
335
336 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
337 pthread_mutex_unlock(&notes->lock);
338 ui__warning("Not enough memory for annotating '%s' symbol!\n",
339 target->name);
340 continue;
341 }
342
343 pthread_mutex_unlock(&notes->lock);
344 symbol__tui_annotate(target, ms->map, evidx,
345 timer, arg, delay_secs);
346 ui_browser__show_title(&self->b, sym->name);
347 }
348 continue;
349 case K_LEFT:
350 case K_ESC:
351 case 'q':
352 case CTRL('c'):
353 goto out;
354 default:
355 continue;
356 }
357
358 if (nd != NULL)
359 annotate_browser__set_top(self, nd);
360 }
361out:
362 ui_browser__hide(&self->b);
363 return key;
364}
365
366int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
367 void(*timer)(void *arg), void *arg, int delay_secs)
368{
369 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
370 timer, arg, delay_secs);
371}
372
373int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
374 void(*timer)(void *arg), void *arg,
375 int delay_secs)
376{
377 struct objdump_line *pos, *n;
378 struct annotation *notes;
379 struct map_symbol ms = {
380 .map = map,
381 .sym = sym,
382 };
383 struct annotate_browser browser = {
384 .b = {
385 .refresh = ui_browser__list_head_refresh,
386 .seek = ui_browser__list_head_seek,
387 .write = annotate_browser__write,
388 .filter = objdump_line__filter,
389 .priv = &ms,
390 .use_navkeypressed = true,
391 },
392 };
393 int ret;
394
395 if (sym == NULL)
396 return -1;
397
398 if (map->dso->annotate_warned)
399 return -1;
400
401 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
402 ui__error("%s", ui_helpline__last_msg);
403 return -1;
404 }
405
406 ui_helpline__push("Press <- or ESC to exit");
407
408 notes = symbol__annotation(sym);
409
410 list_for_each_entry(pos, &notes->src->source, node) {
411 struct objdump_line_rb_node *rbpos;
412 size_t line_len = strlen(pos->line);
413
414 if (browser.b.width < line_len)
415 browser.b.width = line_len;
416 rbpos = objdump_line__rb(pos);
417 rbpos->idx = browser.nr_entries++;
418 if (pos->offset != -1)
419 rbpos->idx_asm = browser.nr_asm_entries++;
420 else
421 rbpos->idx_asm = -1;
422 }
423
424 browser.b.nr_entries = browser.nr_entries;
425 browser.b.entries = &notes->src->source,
426 browser.b.width += 18; /* Percentage */
427 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
428 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
429 list_del(&pos->node);
430 objdump_line__free(pos);
431 }
432 return ret;
433}
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index 52bb07c6442a..4007aca8e0ca 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -82,41 +82,3 @@ void warning(const char *warn, ...)
82 warn_routine(warn, params); 82 warn_routine(warn, params);
83 va_end(params); 83 va_end(params);
84} 84}
85
86uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
87{
88 struct passwd pwd, *result;
89 char buf[1024];
90
91 if (str == NULL)
92 return UINT_MAX;
93
94 /* UID and PID are mutually exclusive */
95 if (tid || pid) {
96 ui__warning("PID/TID switch overriding UID\n");
97 sleep(1);
98 return UINT_MAX;
99 }
100
101 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
102
103 if (result == NULL) {
104 char *endptr;
105 int uid = strtol(str, &endptr, 10);
106
107 if (*endptr != '\0') {
108 ui__error("Invalid user %s\n", str);
109 return UINT_MAX - 1;
110 }
111
112 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
113
114 if (result == NULL) {
115 ui__error("Problems obtaining information for user %s\n",
116 str);
117 return UINT_MAX - 1;
118 }
119 }
120
121 return result->pw_uid;
122}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 8109a907841e..d03599fbe78b 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -148,3 +148,13 @@ int readn(int fd, void *buf, size_t n)
148 148
149 return buf - buf_start; 149 return buf - buf_start;
150} 150}
151
152size_t hex_width(u64 v)
153{
154 size_t n = 1;
155
156 while ((v >>= 4))
157 ++n;
158
159 return n;
160}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0f99f394d8e0..2daaedb83d84 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -74,7 +74,6 @@
74#include <netinet/tcp.h> 74#include <netinet/tcp.h>
75#include <arpa/inet.h> 75#include <arpa/inet.h>
76#include <netdb.h> 76#include <netdb.h>
77#include <pwd.h>
78#include <inttypes.h> 77#include <inttypes.h>
79#include "../../../include/linux/magic.h" 78#include "../../../include/linux/magic.h"
80#include "types.h" 79#include "types.h"
@@ -249,8 +248,6 @@ struct perf_event_attr;
249 248
250void event_attr_init(struct perf_event_attr *attr); 249void event_attr_init(struct perf_event_attr *attr);
251 250
252uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
253
254#define _STR(x) #x 251#define _STR(x) #x
255#define STR(x) _STR(x) 252#define STR(x) _STR(x)
256 253
@@ -265,4 +262,6 @@ bool is_power_of_2(unsigned long n)
265 return (n != 0 && ((n & (n - 1)) == 0)); 262 return (n != 0 && ((n & (n - 1)) == 0));
266} 263}
267 264
265size_t hex_width(u64 v);
266
268#endif 267#endif