aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-05-05 22:42:12 -0400
committerIngo Molnar <mingo@kernel.org>2015-05-05 22:42:12 -0400
commit1836ac856e4fb446e48afa4f8cae897d4856b06c (patch)
tree1b5da329b15a09e13189801c82266fb6805a90af
parent5ebe6afaf0057ac3eaeb98defd5456894b446d22 (diff)
parent3698dab1c849c7e1cd440df4fca24baa1973d53b (diff)
Merge tag 'perf-core-for-mingo-3' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Improve --filter support for 'perf probe', allowing using its arguments on other commands, as --add, --del, etc (Masami Hiramatsu) - Show warning when running 'perf kmem stat' on a unsuitable perf.data file, i.e. one with events that are not the ones required for the stat variant used (Namhyung Kim). Infrastructure changes: - Auxtrace support patches, paving the way to support Intel PT and BTS (Adrian Hunter) - hists browser (top, report) refactorings (Namhyung Kim) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--Makefile5
-rw-r--r--tools/Makefile20
-rw-r--r--tools/lib/traceevent/event-parse.c6
-rw-r--r--tools/lib/traceevent/event-parse.h1
-rw-r--r--tools/perf/Documentation/callchain-overhead-calculation.txt108
-rw-r--r--tools/perf/Documentation/perf-inject.txt27
-rw-r--r--tools/perf/Documentation/perf-kmem.txt11
-rw-r--r--tools/perf/Documentation/perf-probe.txt11
-rw-r--r--tools/perf/Documentation/perf-record.txt9
-rw-r--r--tools/perf/Documentation/perf-report.txt32
-rw-r--r--tools/perf/Documentation/perf-script.txt37
-rw-r--r--tools/perf/Documentation/perf-top.txt3
-rw-r--r--tools/perf/Documentation/perf-trace.txt2
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/Makefile.perf2
-rw-r--r--tools/perf/arch/powerpc/util/Build1
-rw-r--r--tools/perf/arch/powerpc/util/sym-handling.c82
-rw-r--r--tools/perf/bench/numa.c32
-rw-r--r--tools/perf/builtin-buildid-list.c9
-rw-r--r--tools/perf/builtin-inject.c174
-rw-r--r--tools/perf/builtin-kmem.c1015
-rw-r--r--tools/perf/builtin-probe.c167
-rw-r--r--tools/perf/builtin-record.c274
-rw-r--r--tools/perf/builtin-report.c11
-rw-r--r--tools/perf/builtin-script.c74
-rw-r--r--tools/perf/builtin-stat.c146
-rw-r--r--tools/perf/builtin-trace.c7
-rw-r--r--tools/perf/config/Makefile5
-rw-r--r--tools/perf/perf.h5
-rw-r--r--tools/perf/tests/code-reading.c2
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c4
-rw-r--r--tools/perf/tests/hists_cumulate.c2
-rw-r--r--tools/perf/tests/hists_filter.c4
-rw-r--r--tools/perf/tests/hists_link.c4
-rw-r--r--tools/perf/tests/hists_output.c2
-rw-r--r--tools/perf/tests/keep-tracking.c4
-rw-r--r--tools/perf/tests/make18
-rw-r--r--tools/perf/tests/parse-events.c2
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c2
-rw-r--r--tools/perf/tests/pmu.c3
-rw-r--r--tools/perf/tests/switch-tracking.c8
-rw-r--r--tools/perf/ui/browsers/hists.c633
-rw-r--r--tools/perf/util/Build3
-rw-r--r--tools/perf/util/auxtrace.c1352
-rw-r--r--tools/perf/util/auxtrace.h643
-rw-r--r--tools/perf/util/callchain.h4
-rw-r--r--tools/perf/util/data-convert-bt.c410
-rw-r--r--tools/perf/util/dso.c2
-rw-r--r--tools/perf/util/dso.h3
-rw-r--r--tools/perf/util/event.c42
-rw-r--r--tools/perf/util/event.h70
-rw-r--r--tools/perf/util/evlist.c73
-rw-r--r--tools/perf/util/evlist.h6
-rw-r--r--tools/perf/util/evsel.c1
-rw-r--r--tools/perf/util/header.c37
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/hist.c2
-rw-r--r--tools/perf/util/machine.c21
-rw-r--r--tools/perf/util/machine.h4
-rw-r--r--tools/perf/util/map.c5
-rw-r--r--tools/perf/util/map.h3
-rw-r--r--tools/perf/util/parse-events.c194
-rw-r--r--tools/perf/util/parse-events.h36
-rw-r--r--tools/perf/util/parse-events.l41
-rw-r--r--tools/perf/util/parse-events.y48
-rw-r--r--tools/perf/util/parse-options.h4
-rw-r--r--tools/perf/util/pmu.c57
-rw-r--r--tools/perf/util/pmu.h6
-rw-r--r--tools/perf/util/probe-event.c159
-rw-r--r--tools/perf/util/probe-event.h7
-rw-r--r--tools/perf/util/pstack.c7
-rw-r--r--tools/perf/util/pstack.h1
-rw-r--r--tools/perf/util/record.c15
-rw-r--r--tools/perf/util/session.c184
-rw-r--r--tools/perf/util/session.h6
-rw-r--r--tools/perf/util/sort.h38
-rw-r--r--tools/perf/util/strfilter.c107
-rw-r--r--tools/perf/util/strfilter.h35
-rw-r--r--tools/perf/util/symbol-elf.c13
-rw-r--r--tools/perf/util/symbol.c25
-rw-r--r--tools/perf/util/symbol.h12
-rw-r--r--tools/perf/util/tool.h12
82 files changed, 5843 insertions, 812 deletions
diff --git a/Makefile b/Makefile
index 2da553fd7fc3..66a094216cad 100644
--- a/Makefile
+++ b/Makefile
@@ -215,7 +215,6 @@ VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
215 215
216export srctree objtree VPATH 216export srctree objtree VPATH
217 217
218
219# SUBARCH tells the usermode build what the underlying arch is. That is set 218# SUBARCH tells the usermode build what the underlying arch is. That is set
220# first, and if a usermode build is happening, the "ARCH=um" on the command 219# first, and if a usermode build is happening, the "ARCH=um" on the command
221# line overrides the setting of ARCH below. If a native build is happening, 220# line overrides the setting of ARCH below. If a native build is happening,
@@ -1497,11 +1496,11 @@ image_name:
1497# Clear a bunch of variables before executing the submake 1496# Clear a bunch of variables before executing the submake
1498tools/: FORCE 1497tools/: FORCE
1499 $(Q)mkdir -p $(objtree)/tools 1498 $(Q)mkdir -p $(objtree)/tools
1500 $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ 1499 $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/
1501 1500
1502tools/%: FORCE 1501tools/%: FORCE
1503 $(Q)mkdir -p $(objtree)/tools 1502 $(Q)mkdir -p $(objtree)/tools
1504 $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ $* 1503 $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/ $*
1505 1504
1506# Single targets 1505# Single targets
1507# --------------------------------------------------------------------------- 1506# ---------------------------------------------------------------------------
diff --git a/tools/Makefile b/tools/Makefile
index 9a617adc6675..b35102721cbb 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -1,3 +1,8 @@
1# Some of the tools (perf) use same make variables
2# as in kernel build.
3export srctree=
4export objtree=
5
1include scripts/Makefile.include 6include scripts/Makefile.include
2 7
3help: 8help:
@@ -47,11 +52,16 @@ cgroup firewire hv guest usb virtio vm net: FORCE
47liblockdep: FORCE 52liblockdep: FORCE
48 $(call descend,lib/lockdep) 53 $(call descend,lib/lockdep)
49 54
50libapikfs: FORCE 55libapi: FORCE
51 $(call descend,lib/api) 56 $(call descend,lib/api)
52 57
53perf: libapikfs FORCE 58# The perf build does not follow the descend function setup,
54 $(call descend,$@) 59# invoking it via it's own make rule.
60PERF_O = $(if $(O),$(O)/tools/perf,)
61
62perf: FORCE
63 $(Q)mkdir -p $(PERF_O) .
64 $(Q)$(MAKE) --no-print-directory -C perf O=$(PERF_O) subdir=
55 65
56selftests: FORCE 66selftests: FORCE
57 $(call descend,testing/$@) 67 $(call descend,testing/$@)
@@ -97,10 +107,10 @@ cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clea
97liblockdep_clean: 107liblockdep_clean:
98 $(call descend,lib/lockdep,clean) 108 $(call descend,lib/lockdep,clean)
99 109
100libapikfs_clean: 110libapi_clean:
101 $(call descend,lib/api,clean) 111 $(call descend,lib/api,clean)
102 112
103perf_clean: libapikfs_clean 113perf_clean:
104 $(call descend,$(@:_clean=),clean) 114 $(call descend,$(@:_clean=),clean)
105 115
106selftests_clean: 116selftests_clean:
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index e0917c0f5d9f..e29e4f81a40d 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -1387,7 +1387,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1387 do_warning_event(event, "%s: no type found", __func__); 1387 do_warning_event(event, "%s: no type found", __func__);
1388 goto fail; 1388 goto fail;
1389 } 1389 }
1390 field->name = last_token; 1390 field->name = field->alias = last_token;
1391 1391
1392 if (test_type(type, EVENT_OP)) 1392 if (test_type(type, EVENT_OP))
1393 goto fail; 1393 goto fail;
@@ -1469,7 +1469,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1469 size_dynamic = type_size(field->name); 1469 size_dynamic = type_size(field->name);
1470 free_token(field->name); 1470 free_token(field->name);
1471 strcat(field->type, brackets); 1471 strcat(field->type, brackets);
1472 field->name = token; 1472 field->name = field->alias = token;
1473 type = read_token(&token); 1473 type = read_token(&token);
1474 } else { 1474 } else {
1475 char *new_type; 1475 char *new_type;
@@ -6444,6 +6444,8 @@ void pevent_ref(struct pevent *pevent)
6444void pevent_free_format_field(struct format_field *field) 6444void pevent_free_format_field(struct format_field *field)
6445{ 6445{
6446 free(field->type); 6446 free(field->type);
6447 if (field->alias != field->name)
6448 free(field->alias);
6447 free(field->name); 6449 free(field->name);
6448 free(field); 6450 free(field);
6449} 6451}
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 86a5839fb048..063b1971eb35 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -191,6 +191,7 @@ struct format_field {
191 struct event_format *event; 191 struct event_format *event;
192 char *type; 192 char *type;
193 char *name; 193 char *name;
194 char *alias;
194 int offset; 195 int offset;
195 int size; 196 int size;
196 unsigned int arraylen; 197 unsigned int arraylen;
diff --git a/tools/perf/Documentation/callchain-overhead-calculation.txt b/tools/perf/Documentation/callchain-overhead-calculation.txt
new file mode 100644
index 000000000000..1a757927195e
--- /dev/null
+++ b/tools/perf/Documentation/callchain-overhead-calculation.txt
@@ -0,0 +1,108 @@
1Overhead calculation
2--------------------
3The overhead can be shown in two columns as 'Children' and 'Self' when
4perf collects callchains. The 'self' overhead is simply calculated by
5adding all period values of the entry - usually a function (symbol).
6This is the value that perf shows traditionally and sum of all the
7'self' overhead values should be 100%.
8
9The 'children' overhead is calculated by adding all period values of
10the child functions so that it can show the total overhead of the
11higher level functions even if they don't directly execute much.
12'Children' here means functions that are called from another (parent)
13function.
14
15It might be confusing that the sum of all the 'children' overhead
16values exceeds 100% since each of them is already an accumulation of
17'self' overhead of its child functions. But with this enabled, users
18can find which function has the most overhead even if samples are
19spread over the children.
20
21Consider the following example; there are three functions like below.
22
23-----------------------
24void foo(void) {
25 /* do something */
26}
27
28void bar(void) {
29 /* do something */
30 foo();
31}
32
33int main(void) {
34 bar()
35 return 0;
36}
37-----------------------
38
39In this case 'foo' is a child of 'bar', and 'bar' is an immediate
40child of 'main' so 'foo' also is a child of 'main'. In other words,
41'main' is a parent of 'foo' and 'bar', and 'bar' is a parent of 'foo'.
42
43Suppose all samples are recorded in 'foo' and 'bar' only. When it's
44recorded with callchains the output will show something like below
45in the usual (self-overhead-only) output of perf report:
46
47----------------------------------
48Overhead Symbol
49........ .....................
50 60.00% foo
51 |
52 --- foo
53 bar
54 main
55 __libc_start_main
56
57 40.00% bar
58 |
59 --- bar
60 main
61 __libc_start_main
62----------------------------------
63
64When the --children option is enabled, the 'self' overhead values of
65child functions (i.e. 'foo' and 'bar') are added to the parents to
66calculate the 'children' overhead. In this case the report could be
67displayed as:
68
69-------------------------------------------
70Children Self Symbol
71........ ........ ....................
72 100.00% 0.00% __libc_start_main
73 |
74 --- __libc_start_main
75
76 100.00% 0.00% main
77 |
78 --- main
79 __libc_start_main
80
81 100.00% 40.00% bar
82 |
83 --- bar
84 main
85 __libc_start_main
86
87 60.00% 60.00% foo
88 |
89 --- foo
90 bar
91 main
92 __libc_start_main
93-------------------------------------------
94
95In the above output, the 'self' overhead of 'foo' (60%) was add to the
96'children' overhead of 'bar', 'main' and '\_\_libc_start_main'.
97Likewise, the 'self' overhead of 'bar' (40%) was added to the
98'children' overhead of 'main' and '\_\_libc_start_main'.
99
100So '\_\_libc_start_main' and 'main' are shown first since they have
101same (100%) 'children' overhead (even though they have zero 'self'
102overhead) and they are the parents of 'foo' and 'bar'.
103
104Since v3.16 the 'children' overhead is shown by default and the output
105is sorted by its values. The 'children' overhead is disabled by
106specifying --no-children option on the command line or by adding
107'report.children = false' or 'top.children = false' in the perf config
108file.
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index dc7442cf3d7f..b876ae312699 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -44,6 +44,33 @@ OPTIONS
44--kallsyms=<file>:: 44--kallsyms=<file>::
45 kallsyms pathname 45 kallsyms pathname
46 46
47--itrace::
48 Decode Instruction Tracing data, replacing it with synthesized events.
49 Options are:
50
51 i synthesize instructions events
52 b synthesize branches events
53 c synthesize branches events (calls only)
54 r synthesize branches events (returns only)
55 x synthesize transactions events
56 e synthesize error events
57 d create a debug log
58 g synthesize a call chain (use with i or x)
59
60 The default is all events i.e. the same as --itrace=ibxe
61
62 In addition, the period (default 100000) for instructions events
63 can be specified in units of:
64
65 i instructions
66 t ticks
67 ms milliseconds
68 us microseconds
69 ns nanoseconds (default)
70
71 Also the call chain size (default 16, max. 1024) for instructions or
72 transactions events can be specified.
73
47SEE ALSO 74SEE ALSO
48-------- 75--------
49linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] 76linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
index 23219c65c16f..ff0f433b3fce 100644
--- a/tools/perf/Documentation/perf-kmem.txt
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -37,7 +37,11 @@ OPTIONS
37 37
38-s <key[,key2...]>:: 38-s <key[,key2...]>::
39--sort=<key[,key2...]>:: 39--sort=<key[,key2...]>::
40 Sort the output (default: frag,hit,bytes) 40 Sort the output (default: 'frag,hit,bytes' for slab and 'bytes,hit'
41 for page). Available sort keys are 'ptr, callsite, bytes, hit,
42 pingpong, frag' for slab and 'page, callsite, bytes, hit, order,
43 migtype, gfp' for page. This option should be preceded by one of the
44 mode selection options - i.e. --slab, --page, --alloc and/or --caller.
41 45
42-l <num>:: 46-l <num>::
43--line=<num>:: 47--line=<num>::
@@ -52,6 +56,11 @@ OPTIONS
52--page:: 56--page::
53 Analyze page allocator events 57 Analyze page allocator events
54 58
59--live::
60 Show live page stat. The perf kmem shows total allocation stat by
61 default, but this option shows live (currently allocated) pages
62 instead. (This option works with --page option only)
63
55SEE ALSO 64SEE ALSO
56-------- 65--------
57linkperf:perf-record[1] 66linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 239609c09f83..a272f2e9a1cf 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -14,11 +14,13 @@ or
14or 14or
15'perf probe' [options] --del='[GROUP:]EVENT' [...] 15'perf probe' [options] --del='[GROUP:]EVENT' [...]
16or 16or
17'perf probe' --list 17'perf probe' --list[=[GROUP:]EVENT]
18or 18or
19'perf probe' [options] --line='LINE' 19'perf probe' [options] --line='LINE'
20or 20or
21'perf probe' [options] --vars='PROBEPOINT' 21'perf probe' [options] --vars='PROBEPOINT'
22or
23'perf probe' [options] --funcs
22 24
23DESCRIPTION 25DESCRIPTION
24----------- 26-----------
@@ -64,8 +66,8 @@ OPTIONS
64 classes(e.g. [a-z], [!A-Z]). 66 classes(e.g. [a-z], [!A-Z]).
65 67
66-l:: 68-l::
67--list:: 69--list[=[GROUP:]EVENT]::
68 List up current probe events. 70 List up current probe events. This can also accept filtering patterns of event names.
69 71
70-L:: 72-L::
71--line=:: 73--line=::
@@ -82,9 +84,10 @@ OPTIONS
82 variables. 84 variables.
83 85
84-F:: 86-F::
85--funcs:: 87--funcs[=FILTER]::
86 Show available functions in given module or kernel. With -x/--exec, 88 Show available functions in given module or kernel. With -x/--exec,
87 can also list functions in a user space executable / shared library. 89 can also list functions in a user space executable / shared library.
90 This also can accept a FILTER rule argument.
88 91
89--filter=FILTER:: 92--filter=FILTER::
90 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob 93 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 4847a793de65..57dd57bcef95 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -108,6 +108,8 @@ OPTIONS
108 Number of mmap data pages (must be a power of two) or size 108 Number of mmap data pages (must be a power of two) or size
109 specification with appended unit character - B/K/M/G. The 109 specification with appended unit character - B/K/M/G. The
110 size is rounded up to have nearest pages power of two value. 110 size is rounded up to have nearest pages power of two value.
111 Also, by adding a comma, the number of mmap pages for AUX
112 area tracing can be specified.
111 113
112--group:: 114--group::
113 Put all events in a single event group. This precedes the --event 115 Put all events in a single event group. This precedes the --event
@@ -257,6 +259,13 @@ records. See clock_gettime(). In particular CLOCK_MONOTONIC and
257CLOCK_MONOTONIC_RAW are supported, some events might also allow 259CLOCK_MONOTONIC_RAW are supported, some events might also allow
258CLOCK_BOOTTIME, CLOCK_REALTIME and CLOCK_TAI. 260CLOCK_BOOTTIME, CLOCK_REALTIME and CLOCK_TAI.
259 261
262-S::
263--snapshot::
264Select AUX area tracing Snapshot Mode. This option is valid only with an
265AUX area tracing event. Optionally the number of bytes to capture per
266snapshot can be specified. In Snapshot Mode, trace data is captured only when
267signal SIGUSR2 is received.
268
260SEE ALSO 269SEE ALSO
261-------- 270--------
262linkperf:perf-stat[1], linkperf:perf-list[1] 271linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 4879cf638824..27190ed06f9c 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -193,6 +193,7 @@ OPTIONS
193 Accumulate callchain of children to parent entry so that then can 193 Accumulate callchain of children to parent entry so that then can
194 show up in the output. The output will have a new "Children" column 194 show up in the output. The output will have a new "Children" column
195 and will be sorted on the data. It requires callchains are recorded. 195 and will be sorted on the data. It requires callchains are recorded.
196 See the `overhead calculation' section for more details.
196 197
197--max-stack:: 198--max-stack::
198 Set the stack depth limit when parsing the callchain, anything 199 Set the stack depth limit when parsing the callchain, anything
@@ -323,6 +324,37 @@ OPTIONS
323--header-only:: 324--header-only::
324 Show only perf.data header (forces --stdio). 325 Show only perf.data header (forces --stdio).
325 326
327--itrace::
328 Options for decoding instruction tracing data. The options are:
329
330 i synthesize instructions events
331 b synthesize branches events
332 c synthesize branches events (calls only)
333 r synthesize branches events (returns only)
334 x synthesize transactions events
335 e synthesize error events
336 d create a debug log
337 g synthesize a call chain (use with i or x)
338
339 The default is all events i.e. the same as --itrace=ibxe
340
341 In addition, the period (default 100000) for instructions events
342 can be specified in units of:
343
344 i instructions
345 t ticks
346 ms milliseconds
347 us microseconds
348 ns nanoseconds (default)
349
350 Also the call chain size (default 16, max. 1024) for instructions or
351 transactions events can be specified.
352
353 To disable decoding entirely, use --no-itrace.
354
355
356include::callchain-overhead-calculation.txt[]
357
326SEE ALSO 358SEE ALSO
327-------- 359--------
328linkperf:perf-stat[1], linkperf:perf-annotate[1] 360linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 79445750fcb3..c82df572fac2 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -115,7 +115,8 @@ OPTIONS
115-f:: 115-f::
116--fields:: 116--fields::
117 Comma separated list of fields to print. Options are: 117 Comma separated list of fields to print. Options are:
118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, srcline, period. 118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
119 srcline, period, flags.
119 Field list can be prepended with the type, trace, sw or hw, 120 Field list can be prepended with the type, trace, sw or hw,
120 to indicate to which event type the field list applies. 121 to indicate to which event type the field list applies.
121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace 122 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
@@ -165,6 +166,12 @@ OPTIONS
165 166
166 At this point usage is displayed, and perf-script exits. 167 At this point usage is displayed, and perf-script exits.
167 168
169 The flags field is synthesized and may have a value when Instruction
170 Trace decoding. The flags are "bcrosyiABEx" which stand for branch,
171 call, return, conditional, system, asynchronous, interrupt,
172 transaction abort, trace begin, trace end, and in transaction,
173 respectively.
174
168 Finally, a user may not set fields to none for all event types. 175 Finally, a user may not set fields to none for all event types.
169 i.e., -f "" is not allowed. 176 i.e., -f "" is not allowed.
170 177
@@ -221,6 +228,34 @@ OPTIONS
221--header-only 228--header-only
222 Show only perf.data header. 229 Show only perf.data header.
223 230
231--itrace::
232 Options for decoding instruction tracing data. The options are:
233
234 i synthesize instructions events
235 b synthesize branches events
236 c synthesize branches events (calls only)
237 r synthesize branches events (returns only)
238 x synthesize transactions events
239 e synthesize error events
240 d create a debug log
241 g synthesize a call chain (use with i or x)
242
243 The default is all events i.e. the same as --itrace=ibxe
244
245 In addition, the period (default 100000) for instructions events
246 can be specified in units of:
247
248 i instructions
249 t ticks
250 ms milliseconds
251 us microseconds
252 ns nanoseconds (default)
253
254 Also the call chain size (default 16, max. 1024) for instructions or
255 transactions events can be specified.
256
257 To disable decoding entirely, use --no-itrace.
258
224SEE ALSO 259SEE ALSO
225-------- 260--------
226linkperf:perf-record[1], linkperf:perf-script-perl[1], 261linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 3265b1070518..9e5b07eb7d35 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -168,7 +168,7 @@ Default is to monitor all CPUS.
168 Accumulate callchain of children to parent entry so that then can 168 Accumulate callchain of children to parent entry so that then can
169 show up in the output. The output will have a new "Children" column 169 show up in the output. The output will have a new "Children" column
170 and will be sorted on the data. It requires -g/--call-graph option 170 and will be sorted on the data. It requires -g/--call-graph option
171 enabled. 171 enabled. See the `overhead calculation' section for more details.
172 172
173--max-stack:: 173--max-stack::
174 Set the stack depth limit when parsing the callchain, anything 174 Set the stack depth limit when parsing the callchain, anything
@@ -234,6 +234,7 @@ INTERACTIVE PROMPTING KEYS
234 234
235Pressing any unmapped key displays a menu, and prompts for input. 235Pressing any unmapped key displays a menu, and prompts for input.
236 236
237include::callchain-overhead-calculation.txt[]
237 238
238SEE ALSO 239SEE ALSO
239-------- 240--------
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index ba03fd5d1a54..1db9c8b79880 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -35,7 +35,7 @@ OPTIONS
35 35
36-e:: 36-e::
37--expr:: 37--expr::
38 List of events to show, currently only syscall names. 38 List of syscalls to show, currently only syscall names.
39 Prefixing with ! shows all syscalls but the ones specified. You may 39 Prefixing with ! shows all syscalls but the ones specified. You may
40 need to escape it. 40 need to escape it.
41 41
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index c699dc35eef9..d31a7bbd7cee 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -24,7 +24,7 @@ unexport MAKEFLAGS
24# (To override it, run 'make JOBS=1' and similar.) 24# (To override it, run 'make JOBS=1' and similar.)
25# 25#
26ifeq ($(JOBS),) 26ifeq ($(JOBS),)
27 JOBS := $(shell egrep -c '^processor|^CPU' /proc/cpuinfo 2>/dev/null) 27 JOBS := $(shell (getconf _NPROCESSORS_ONLN || egrep -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
28 ifeq ($(JOBS),0) 28 ifeq ($(JOBS),0)
29 JOBS := 1 29 JOBS := 1
30 endif 30 endif
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index c43a20517591..03409cc02117 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -73,6 +73,8 @@ include config/utilities.mak
73# for CTF data format. 73# for CTF data format.
74# 74#
75# Define NO_LZMA if you do not want to support compressed (xz) kernel modules 75# Define NO_LZMA if you do not want to support compressed (xz) kernel modules
76#
77# Define NO_AUXTRACE if you do not want AUX area tracing support
76 78
77ifeq ($(srctree),) 79ifeq ($(srctree),)
78srctree := $(patsubst %/,%,$(dir $(shell pwd))) 80srctree := $(patsubst %/,%,$(dir $(shell pwd)))
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 0af6e9b3f728..7b8b0d1a1b62 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -1,4 +1,5 @@
1libperf-y += header.o 1libperf-y += header.o
2libperf-y += sym-handling.o
2 3
3libperf-$(CONFIG_DWARF) += dwarf-regs.o 4libperf-$(CONFIG_DWARF) += dwarf-regs.o
4libperf-$(CONFIG_DWARF) += skip-callchain-idx.o 5libperf-$(CONFIG_DWARF) += skip-callchain-idx.o
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
new file mode 100644
index 000000000000..bbc1a50768dd
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -0,0 +1,82 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
5 *
6 * Copyright (C) 2015 Naveen N. Rao, IBM Corporation
7 */
8
9#include "debug.h"
10#include "symbol.h"
11#include "map.h"
12#include "probe-event.h"
13
14#ifdef HAVE_LIBELF_SUPPORT
15bool elf__needs_adjust_symbols(GElf_Ehdr ehdr)
16{
17 return ehdr.e_type == ET_EXEC ||
18 ehdr.e_type == ET_REL ||
19 ehdr.e_type == ET_DYN;
20}
21
22#if defined(_CALL_ELF) && _CALL_ELF == 2
23void arch__elf_sym_adjust(GElf_Sym *sym)
24{
25 sym->st_value += PPC64_LOCAL_ENTRY_OFFSET(sym->st_other);
26}
27#endif
28#endif
29
30#if !defined(_CALL_ELF) || _CALL_ELF != 2
31int arch__choose_best_symbol(struct symbol *syma,
32 struct symbol *symb __maybe_unused)
33{
34 char *sym = syma->name;
35
36 /* Skip over any initial dot */
37 if (*sym == '.')
38 sym++;
39
40 /* Avoid "SyS" kernel syscall aliases */
41 if (strlen(sym) >= 3 && !strncmp(sym, "SyS", 3))
42 return SYMBOL_B;
43 if (strlen(sym) >= 10 && !strncmp(sym, "compat_SyS", 10))
44 return SYMBOL_B;
45
46 return SYMBOL_A;
47}
48
49/* Allow matching against dot variants */
50int arch__compare_symbol_names(const char *namea, const char *nameb)
51{
52 /* Skip over initial dot */
53 if (*namea == '.')
54 namea++;
55 if (*nameb == '.')
56 nameb++;
57
58 return strcmp(namea, nameb);
59}
60#endif
61
62#if defined(_CALL_ELF) && _CALL_ELF == 2
63bool arch__prefers_symtab(void)
64{
65 return true;
66}
67
68#define PPC64LE_LEP_OFFSET 8
69
70void arch__fix_tev_from_maps(struct perf_probe_event *pev,
71 struct probe_trace_event *tev, struct map *map)
72{
73 /*
74 * ppc64 ABIv2 local entry point is currently always 2 instructions
75 * (8 bytes) after the global entry point.
76 */
77 if (!pev->uprobes && map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
78 tev->point.address += PPC64LE_LEP_OFFSET;
79 tev->point.offset += PPC64LE_LEP_OFFSET;
80 }
81}
82#endif
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index ebfa163b80b5..0b704c5f6d90 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -23,6 +23,7 @@
23#include <pthread.h> 23#include <pthread.h>
24#include <sys/mman.h> 24#include <sys/mman.h>
25#include <sys/time.h> 25#include <sys/time.h>
26#include <sys/resource.h>
26#include <sys/wait.h> 27#include <sys/wait.h>
27#include <sys/prctl.h> 28#include <sys/prctl.h>
28#include <sys/types.h> 29#include <sys/types.h>
@@ -51,6 +52,9 @@ struct thread_data {
51 unsigned int loops_done; 52 unsigned int loops_done;
52 u64 val; 53 u64 val;
53 u64 runtime_ns; 54 u64 runtime_ns;
55 u64 system_time_ns;
56 u64 user_time_ns;
57 double speed_gbs;
54 pthread_mutex_t *process_lock; 58 pthread_mutex_t *process_lock;
55}; 59};
56 60
@@ -1034,6 +1038,7 @@ static void *worker_thread(void *__tdata)
1034 u64 bytes_done; 1038 u64 bytes_done;
1035 long work_done; 1039 long work_done;
1036 u32 l; 1040 u32 l;
1041 struct rusage rusage;
1037 1042
1038 bind_to_cpumask(td->bind_cpumask); 1043 bind_to_cpumask(td->bind_cpumask);
1039 bind_to_memnode(td->bind_node); 1044 bind_to_memnode(td->bind_node);
@@ -1186,6 +1191,13 @@ static void *worker_thread(void *__tdata)
1186 timersub(&stop, &start0, &diff); 1191 timersub(&stop, &start0, &diff);
1187 td->runtime_ns = diff.tv_sec * 1000000000ULL; 1192 td->runtime_ns = diff.tv_sec * 1000000000ULL;
1188 td->runtime_ns += diff.tv_usec * 1000ULL; 1193 td->runtime_ns += diff.tv_usec * 1000ULL;
1194 td->speed_gbs = bytes_done / (td->runtime_ns / 1e9) / 1e9;
1195
1196 getrusage(RUSAGE_THREAD, &rusage);
1197 td->system_time_ns = rusage.ru_stime.tv_sec * 1000000000ULL;
1198 td->system_time_ns += rusage.ru_stime.tv_usec * 1000ULL;
1199 td->user_time_ns = rusage.ru_utime.tv_sec * 1000000000ULL;
1200 td->user_time_ns += rusage.ru_utime.tv_usec * 1000ULL;
1189 1201
1190 free_data(thread_data, g->p.bytes_thread); 1202 free_data(thread_data, g->p.bytes_thread);
1191 1203
@@ -1412,7 +1424,7 @@ static int __bench_numa(const char *name)
1412 double runtime_sec_min; 1424 double runtime_sec_min;
1413 int wait_stat; 1425 int wait_stat;
1414 double bytes; 1426 double bytes;
1415 int i, t; 1427 int i, t, p;
1416 1428
1417 if (init()) 1429 if (init())
1418 return -1; 1430 return -1;
@@ -1548,6 +1560,24 @@ static int __bench_numa(const char *name)
1548 print_res(name, bytes / runtime_sec_max / 1e9, 1560 print_res(name, bytes / runtime_sec_max / 1e9,
1549 "GB/sec,", "total-speed", "GB/sec total speed"); 1561 "GB/sec,", "total-speed", "GB/sec total speed");
1550 1562
1563 if (g->p.show_details >= 2) {
1564 char tname[32];
1565 struct thread_data *td;
1566 for (p = 0; p < g->p.nr_proc; p++) {
1567 for (t = 0; t < g->p.nr_threads; t++) {
1568 memset(tname, 0, 32);
1569 td = g->threads + p*g->p.nr_threads + t;
1570 snprintf(tname, 32, "process%d:thread%d", p, t);
1571 print_res(tname, td->speed_gbs,
1572 "GB/sec", "thread-speed", "GB/sec/thread speed");
1573 print_res(tname, td->system_time_ns / 1e9,
1574 "secs", "thread-system-time", "system CPU time/thread");
1575 print_res(tname, td->user_time_ns / 1e9,
1576 "secs", "thread-user-time", "user CPU time/thread");
1577 }
1578 }
1579 }
1580
1551 free(pids); 1581 free(pids);
1552 1582
1553 deinit(); 1583 deinit();
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index feb420f74c2d..9fe93c8d4fcf 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -69,6 +69,15 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
69 session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops); 69 session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
70 if (session == NULL) 70 if (session == NULL)
71 return -1; 71 return -1;
72
73 /*
74 * We take all buildids when the file contains AUX area tracing data
75 * because we do not decode the trace because it would take too long.
76 */
77 if (!perf_data_file__is_pipe(&file) &&
78 perf_header__has_feat(&session->header, HEADER_AUXTRACE))
79 with_hits = false;
80
72 /* 81 /*
73 * in pipe-mode, the only way to get the buildids is to parse 82 * in pipe-mode, the only way to get the buildids is to parse
74 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID 83 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 40a33d7334cc..d6a47e854b2b 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -16,6 +16,7 @@
16#include "util/debug.h" 16#include "util/debug.h"
17#include "util/build-id.h" 17#include "util/build-id.h"
18#include "util/data.h" 18#include "util/data.h"
19#include "util/auxtrace.h"
19 20
20#include "util/parse-options.h" 21#include "util/parse-options.h"
21 22
@@ -26,10 +27,12 @@ struct perf_inject {
26 struct perf_session *session; 27 struct perf_session *session;
27 bool build_ids; 28 bool build_ids;
28 bool sched_stat; 29 bool sched_stat;
30 bool have_auxtrace;
29 const char *input_name; 31 const char *input_name;
30 struct perf_data_file output; 32 struct perf_data_file output;
31 u64 bytes_written; 33 u64 bytes_written;
32 struct list_head samples; 34 struct list_head samples;
35 struct itrace_synth_opts itrace_synth_opts;
33}; 36};
34 37
35struct event_entry { 38struct event_entry {
@@ -38,14 +41,11 @@ struct event_entry {
38 union perf_event event[0]; 41 union perf_event event[0];
39}; 42};
40 43
41static int perf_event__repipe_synth(struct perf_tool *tool, 44static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
42 union perf_event *event)
43{ 45{
44 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
45 ssize_t size; 46 ssize_t size;
46 47
47 size = perf_data_file__write(&inject->output, event, 48 size = perf_data_file__write(&inject->output, buf, sz);
48 event->header.size);
49 if (size < 0) 49 if (size < 0)
50 return -errno; 50 return -errno;
51 51
@@ -53,6 +53,15 @@ static int perf_event__repipe_synth(struct perf_tool *tool,
53 return 0; 53 return 0;
54} 54}
55 55
56static int perf_event__repipe_synth(struct perf_tool *tool,
57 union perf_event *event)
58{
59 struct perf_inject *inject = container_of(tool, struct perf_inject,
60 tool);
61
62 return output_bytes(inject, event, event->header.size);
63}
64
56static int perf_event__repipe_oe_synth(struct perf_tool *tool, 65static int perf_event__repipe_oe_synth(struct perf_tool *tool,
57 union perf_event *event, 66 union perf_event *event,
58 struct ordered_events *oe __maybe_unused) 67 struct ordered_events *oe __maybe_unused)
@@ -86,6 +95,79 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
86 return perf_event__repipe_synth(tool, event); 95 return perf_event__repipe_synth(tool, event);
87} 96}
88 97
98#ifdef HAVE_AUXTRACE_SUPPORT
99
100static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
101{
102 char buf[4096];
103 ssize_t ssz;
104 int ret;
105
106 while (size > 0) {
107 ssz = read(fd, buf, min(size, (off_t)sizeof(buf)));
108 if (ssz < 0)
109 return -errno;
110 ret = output_bytes(inject, buf, ssz);
111 if (ret)
112 return ret;
113 size -= ssz;
114 }
115
116 return 0;
117}
118
119static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
120 union perf_event *event,
121 struct perf_session *session
122 __maybe_unused)
123{
124 struct perf_inject *inject = container_of(tool, struct perf_inject,
125 tool);
126 int ret;
127
128 inject->have_auxtrace = true;
129
130 if (!inject->output.is_pipe) {
131 off_t offset;
132
133 offset = lseek(inject->output.fd, 0, SEEK_CUR);
134 if (offset == -1)
135 return -errno;
136 ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
137 event, offset);
138 if (ret < 0)
139 return ret;
140 }
141
142 if (perf_data_file__is_pipe(session->file) || !session->one_mmap) {
143 ret = output_bytes(inject, event, event->header.size);
144 if (ret < 0)
145 return ret;
146 ret = copy_bytes(inject, perf_data_file__fd(session->file),
147 event->auxtrace.size);
148 } else {
149 ret = output_bytes(inject, event,
150 event->header.size + event->auxtrace.size);
151 }
152 if (ret < 0)
153 return ret;
154
155 return event->auxtrace.size;
156}
157
158#else
159
160static s64
161perf_event__repipe_auxtrace(struct perf_tool *tool __maybe_unused,
162 union perf_event *event __maybe_unused,
163 struct perf_session *session __maybe_unused)
164{
165 pr_err("AUX area tracing not supported\n");
166 return -EINVAL;
167}
168
169#endif
170
89static int perf_event__repipe(struct perf_tool *tool, 171static int perf_event__repipe(struct perf_tool *tool,
90 union perf_event *event, 172 union perf_event *event,
91 struct perf_sample *sample __maybe_unused, 173 struct perf_sample *sample __maybe_unused,
@@ -155,6 +237,32 @@ static int perf_event__repipe_fork(struct perf_tool *tool,
155 return err; 237 return err;
156} 238}
157 239
240static int perf_event__repipe_comm(struct perf_tool *tool,
241 union perf_event *event,
242 struct perf_sample *sample,
243 struct machine *machine)
244{
245 int err;
246
247 err = perf_event__process_comm(tool, event, sample, machine);
248 perf_event__repipe(tool, event, sample, machine);
249
250 return err;
251}
252
253static int perf_event__repipe_exit(struct perf_tool *tool,
254 union perf_event *event,
255 struct perf_sample *sample,
256 struct machine *machine)
257{
258 int err;
259
260 err = perf_event__process_exit(tool, event, sample, machine);
261 perf_event__repipe(tool, event, sample, machine);
262
263 return err;
264}
265
158static int perf_event__repipe_tracing_data(struct perf_tool *tool, 266static int perf_event__repipe_tracing_data(struct perf_tool *tool,
159 union perf_event *event, 267 union perf_event *event,
160 struct perf_session *session) 268 struct perf_session *session)
@@ -167,6 +275,18 @@ static int perf_event__repipe_tracing_data(struct perf_tool *tool,
167 return err; 275 return err;
168} 276}
169 277
278static int perf_event__repipe_id_index(struct perf_tool *tool,
279 union perf_event *event,
280 struct perf_session *session)
281{
282 int err;
283
284 perf_event__repipe_synth(tool, event);
285 err = perf_event__process_id_index(tool, event, session);
286
287 return err;
288}
289
170static int dso__read_build_id(struct dso *dso) 290static int dso__read_build_id(struct dso *dso)
171{ 291{
172 if (dso->has_build_id) 292 if (dso->has_build_id)
@@ -351,16 +471,20 @@ static int __cmd_inject(struct perf_inject *inject)
351 struct perf_session *session = inject->session; 471 struct perf_session *session = inject->session;
352 struct perf_data_file *file_out = &inject->output; 472 struct perf_data_file *file_out = &inject->output;
353 int fd = perf_data_file__fd(file_out); 473 int fd = perf_data_file__fd(file_out);
474 u64 output_data_offset;
354 475
355 signal(SIGINT, sig_handler); 476 signal(SIGINT, sig_handler);
356 477
357 if (inject->build_ids || inject->sched_stat) { 478 if (inject->build_ids || inject->sched_stat ||
479 inject->itrace_synth_opts.set) {
358 inject->tool.mmap = perf_event__repipe_mmap; 480 inject->tool.mmap = perf_event__repipe_mmap;
359 inject->tool.mmap2 = perf_event__repipe_mmap2; 481 inject->tool.mmap2 = perf_event__repipe_mmap2;
360 inject->tool.fork = perf_event__repipe_fork; 482 inject->tool.fork = perf_event__repipe_fork;
361 inject->tool.tracing_data = perf_event__repipe_tracing_data; 483 inject->tool.tracing_data = perf_event__repipe_tracing_data;
362 } 484 }
363 485
486 output_data_offset = session->header.data_offset;
487
364 if (inject->build_ids) { 488 if (inject->build_ids) {
365 inject->tool.sample = perf_event__inject_buildid; 489 inject->tool.sample = perf_event__inject_buildid;
366 } else if (inject->sched_stat) { 490 } else if (inject->sched_stat) {
@@ -379,17 +503,43 @@ static int __cmd_inject(struct perf_inject *inject)
379 else if (!strncmp(name, "sched:sched_stat_", 17)) 503 else if (!strncmp(name, "sched:sched_stat_", 17))
380 evsel->handler = perf_inject__sched_stat; 504 evsel->handler = perf_inject__sched_stat;
381 } 505 }
506 } else if (inject->itrace_synth_opts.set) {
507 session->itrace_synth_opts = &inject->itrace_synth_opts;
508 inject->itrace_synth_opts.inject = true;
509 inject->tool.comm = perf_event__repipe_comm;
510 inject->tool.exit = perf_event__repipe_exit;
511 inject->tool.id_index = perf_event__repipe_id_index;
512 inject->tool.auxtrace_info = perf_event__process_auxtrace_info;
513 inject->tool.auxtrace = perf_event__process_auxtrace;
514 inject->tool.ordered_events = true;
515 inject->tool.ordering_requires_timestamps = true;
516 /* Allow space in the header for new attributes */
517 output_data_offset = 4096;
382 } 518 }
383 519
520 if (!inject->itrace_synth_opts.set)
521 auxtrace_index__free(&session->auxtrace_index);
522
384 if (!file_out->is_pipe) 523 if (!file_out->is_pipe)
385 lseek(fd, session->header.data_offset, SEEK_SET); 524 lseek(fd, output_data_offset, SEEK_SET);
386 525
387 ret = perf_session__process_events(session); 526 ret = perf_session__process_events(session);
388 527
389 if (!file_out->is_pipe) { 528 if (!file_out->is_pipe) {
390 if (inject->build_ids) 529 if (inject->build_ids) {
391 perf_header__set_feat(&session->header, 530 perf_header__set_feat(&session->header,
392 HEADER_BUILD_ID); 531 HEADER_BUILD_ID);
532 if (inject->have_auxtrace)
533 dsos__hit_all(session);
534 }
535 /*
536 * The AUX areas have been removed and replaced with
537 * synthesized hardware events, so clear the feature flag.
538 */
539 if (inject->itrace_synth_opts.set)
540 perf_header__clear_feat(&session->header,
541 HEADER_AUXTRACE);
542 session->header.data_offset = output_data_offset;
393 session->header.data_size = inject->bytes_written; 543 session->header.data_size = inject->bytes_written;
394 perf_session__write_header(session, session->evlist, fd, true); 544 perf_session__write_header(session, session->evlist, fd, true);
395 } 545 }
@@ -408,11 +558,16 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
408 .fork = perf_event__repipe, 558 .fork = perf_event__repipe,
409 .exit = perf_event__repipe, 559 .exit = perf_event__repipe,
410 .lost = perf_event__repipe, 560 .lost = perf_event__repipe,
561 .aux = perf_event__repipe,
562 .itrace_start = perf_event__repipe,
411 .read = perf_event__repipe_sample, 563 .read = perf_event__repipe_sample,
412 .throttle = perf_event__repipe, 564 .throttle = perf_event__repipe,
413 .unthrottle = perf_event__repipe, 565 .unthrottle = perf_event__repipe,
414 .attr = perf_event__repipe_attr, 566 .attr = perf_event__repipe_attr,
415 .tracing_data = perf_event__repipe_op2_synth, 567 .tracing_data = perf_event__repipe_op2_synth,
568 .auxtrace_info = perf_event__repipe_op2_synth,
569 .auxtrace = perf_event__repipe_auxtrace,
570 .auxtrace_error = perf_event__repipe_op2_synth,
416 .finished_round = perf_event__repipe_oe_synth, 571 .finished_round = perf_event__repipe_oe_synth,
417 .build_id = perf_event__repipe_op2_synth, 572 .build_id = perf_event__repipe_op2_synth,
418 .id_index = perf_event__repipe_op2_synth, 573 .id_index = perf_event__repipe_op2_synth,
@@ -444,6 +599,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
444 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 599 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
445 "kallsyms pathname"), 600 "kallsyms pathname"),
446 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"), 601 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
602 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
603 NULL, "opts", "Instruction Tracing options",
604 itrace_parse_synth_opts),
447 OPT_END() 605 OPT_END()
448 }; 606 };
449 const char * const inject_usage[] = { 607 const char * const inject_usage[] = {
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 63ea01349b6e..e628bf1a0c24 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -10,6 +10,7 @@
10#include "util/header.h" 10#include "util/header.h"
11#include "util/session.h" 11#include "util/session.h"
12#include "util/tool.h" 12#include "util/tool.h"
13#include "util/callchain.h"
13 14
14#include "util/parse-options.h" 15#include "util/parse-options.h"
15#include "util/trace-event.h" 16#include "util/trace-event.h"
@@ -21,14 +22,19 @@
21#include <linux/rbtree.h> 22#include <linux/rbtree.h>
22#include <linux/string.h> 23#include <linux/string.h>
23#include <locale.h> 24#include <locale.h>
25#include <regex.h>
24 26
25static int kmem_slab; 27static int kmem_slab;
26static int kmem_page; 28static int kmem_page;
27 29
28static long kmem_page_size; 30static long kmem_page_size;
31static enum {
32 KMEM_SLAB,
33 KMEM_PAGE,
34} kmem_default = KMEM_SLAB; /* for backward compatibility */
29 35
30struct alloc_stat; 36struct alloc_stat;
31typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); 37typedef int (*sort_fn_t)(void *, void *);
32 38
33static int alloc_flag; 39static int alloc_flag;
34static int caller_flag; 40static int caller_flag;
@@ -179,8 +185,8 @@ static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
179 return ret; 185 return ret;
180} 186}
181 187
182static int ptr_cmp(struct alloc_stat *, struct alloc_stat *); 188static int ptr_cmp(void *, void *);
183static int callsite_cmp(struct alloc_stat *, struct alloc_stat *); 189static int slab_callsite_cmp(void *, void *);
184 190
185static struct alloc_stat *search_alloc_stat(unsigned long ptr, 191static struct alloc_stat *search_alloc_stat(unsigned long ptr,
186 unsigned long call_site, 192 unsigned long call_site,
@@ -221,7 +227,8 @@ static int perf_evsel__process_free_event(struct perf_evsel *evsel,
221 s_alloc->pingpong++; 227 s_alloc->pingpong++;
222 228
223 s_caller = search_alloc_stat(0, s_alloc->call_site, 229 s_caller = search_alloc_stat(0, s_alloc->call_site,
224 &root_caller_stat, callsite_cmp); 230 &root_caller_stat,
231 slab_callsite_cmp);
225 if (!s_caller) 232 if (!s_caller)
226 return -1; 233 return -1;
227 s_caller->pingpong++; 234 s_caller->pingpong++;
@@ -241,6 +248,8 @@ static unsigned long nr_page_fails;
241static unsigned long nr_page_nomatch; 248static unsigned long nr_page_nomatch;
242 249
243static bool use_pfn; 250static bool use_pfn;
251static bool live_page;
252static struct perf_session *kmem_session;
244 253
245#define MAX_MIGRATE_TYPES 6 254#define MAX_MIGRATE_TYPES 6
246#define MAX_PAGE_ORDER 11 255#define MAX_PAGE_ORDER 11
@@ -250,6 +259,7 @@ static int order_stats[MAX_PAGE_ORDER][MAX_MIGRATE_TYPES];
250struct page_stat { 259struct page_stat {
251 struct rb_node node; 260 struct rb_node node;
252 u64 page; 261 u64 page;
262 u64 callsite;
253 int order; 263 int order;
254 unsigned gfp_flags; 264 unsigned gfp_flags;
255 unsigned migrate_type; 265 unsigned migrate_type;
@@ -259,13 +269,158 @@ struct page_stat {
259 int nr_free; 269 int nr_free;
260}; 270};
261 271
262static struct rb_root page_tree; 272static struct rb_root page_live_tree;
263static struct rb_root page_alloc_tree; 273static struct rb_root page_alloc_tree;
264static struct rb_root page_alloc_sorted; 274static struct rb_root page_alloc_sorted;
275static struct rb_root page_caller_tree;
276static struct rb_root page_caller_sorted;
265 277
266static struct page_stat *search_page(unsigned long page, bool create) 278struct alloc_func {
279 u64 start;
280 u64 end;
281 char *name;
282};
283
284static int nr_alloc_funcs;
285static struct alloc_func *alloc_func_list;
286
287static int funcmp(const void *a, const void *b)
288{
289 const struct alloc_func *fa = a;
290 const struct alloc_func *fb = b;
291
292 if (fa->start > fb->start)
293 return 1;
294 else
295 return -1;
296}
297
298static int callcmp(const void *a, const void *b)
299{
300 const struct alloc_func *fa = a;
301 const struct alloc_func *fb = b;
302
303 if (fb->start <= fa->start && fa->end < fb->end)
304 return 0;
305
306 if (fa->start > fb->start)
307 return 1;
308 else
309 return -1;
310}
311
312static int build_alloc_func_list(void)
313{
314 int ret;
315 struct map *kernel_map;
316 struct symbol *sym;
317 struct rb_node *node;
318 struct alloc_func *func;
319 struct machine *machine = &kmem_session->machines.host;
320 regex_t alloc_func_regex;
321 const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?";
322
323 ret = regcomp(&alloc_func_regex, pattern, REG_EXTENDED);
324 if (ret) {
325 char err[BUFSIZ];
326
327 regerror(ret, &alloc_func_regex, err, sizeof(err));
328 pr_err("Invalid regex: %s\n%s", pattern, err);
329 return -EINVAL;
330 }
331
332 kernel_map = machine->vmlinux_maps[MAP__FUNCTION];
333 if (map__load(kernel_map, NULL) < 0) {
334 pr_err("cannot load kernel map\n");
335 return -ENOENT;
336 }
337
338 map__for_each_symbol(kernel_map, sym, node) {
339 if (regexec(&alloc_func_regex, sym->name, 0, NULL, 0))
340 continue;
341
342 func = realloc(alloc_func_list,
343 (nr_alloc_funcs + 1) * sizeof(*func));
344 if (func == NULL)
345 return -ENOMEM;
346
347 pr_debug("alloc func: %s\n", sym->name);
348 func[nr_alloc_funcs].start = sym->start;
349 func[nr_alloc_funcs].end = sym->end;
350 func[nr_alloc_funcs].name = sym->name;
351
352 alloc_func_list = func;
353 nr_alloc_funcs++;
354 }
355
356 qsort(alloc_func_list, nr_alloc_funcs, sizeof(*func), funcmp);
357
358 regfree(&alloc_func_regex);
359 return 0;
360}
361
362/*
363 * Find first non-memory allocation function from callchain.
364 * The allocation functions are in the 'alloc_func_list'.
365 */
366static u64 find_callsite(struct perf_evsel *evsel, struct perf_sample *sample)
367{
368 struct addr_location al;
369 struct machine *machine = &kmem_session->machines.host;
370 struct callchain_cursor_node *node;
371
372 if (alloc_func_list == NULL) {
373 if (build_alloc_func_list() < 0)
374 goto out;
375 }
376
377 al.thread = machine__findnew_thread(machine, sample->pid, sample->tid);
378 sample__resolve_callchain(sample, NULL, evsel, &al, 16);
379
380 callchain_cursor_commit(&callchain_cursor);
381 while (true) {
382 struct alloc_func key, *caller;
383 u64 addr;
384
385 node = callchain_cursor_current(&callchain_cursor);
386 if (node == NULL)
387 break;
388
389 key.start = key.end = node->ip;
390 caller = bsearch(&key, alloc_func_list, nr_alloc_funcs,
391 sizeof(key), callcmp);
392 if (!caller) {
393 /* found */
394 if (node->map)
395 addr = map__unmap_ip(node->map, node->ip);
396 else
397 addr = node->ip;
398
399 return addr;
400 } else
401 pr_debug3("skipping alloc function: %s\n", caller->name);
402
403 callchain_cursor_advance(&callchain_cursor);
404 }
405
406out:
407 pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip);
408 return sample->ip;
409}
410
411struct sort_dimension {
412 const char name[20];
413 sort_fn_t cmp;
414 struct list_head list;
415};
416
417static LIST_HEAD(page_alloc_sort_input);
418static LIST_HEAD(page_caller_sort_input);
419
420static struct page_stat *
421__page_stat__findnew_page(struct page_stat *pstat, bool create)
267{ 422{
268 struct rb_node **node = &page_tree.rb_node; 423 struct rb_node **node = &page_live_tree.rb_node;
269 struct rb_node *parent = NULL; 424 struct rb_node *parent = NULL;
270 struct page_stat *data; 425 struct page_stat *data;
271 426
@@ -275,7 +430,7 @@ static struct page_stat *search_page(unsigned long page, bool create)
275 parent = *node; 430 parent = *node;
276 data = rb_entry(*node, struct page_stat, node); 431 data = rb_entry(*node, struct page_stat, node);
277 432
278 cmp = data->page - page; 433 cmp = data->page - pstat->page;
279 if (cmp < 0) 434 if (cmp < 0)
280 node = &parent->rb_left; 435 node = &parent->rb_left;
281 else if (cmp > 0) 436 else if (cmp > 0)
@@ -289,49 +444,48 @@ static struct page_stat *search_page(unsigned long page, bool create)
289 444
290 data = zalloc(sizeof(*data)); 445 data = zalloc(sizeof(*data));
291 if (data != NULL) { 446 if (data != NULL) {
292 data->page = page; 447 data->page = pstat->page;
448 data->order = pstat->order;
449 data->gfp_flags = pstat->gfp_flags;
450 data->migrate_type = pstat->migrate_type;
293 451
294 rb_link_node(&data->node, parent, node); 452 rb_link_node(&data->node, parent, node);
295 rb_insert_color(&data->node, &page_tree); 453 rb_insert_color(&data->node, &page_live_tree);
296 } 454 }
297 455
298 return data; 456 return data;
299} 457}
300 458
301static int page_stat_cmp(struct page_stat *a, struct page_stat *b) 459static struct page_stat *page_stat__find_page(struct page_stat *pstat)
302{ 460{
303 if (a->page > b->page) 461 return __page_stat__findnew_page(pstat, false);
304 return -1; 462}
305 if (a->page < b->page) 463
306 return 1; 464static struct page_stat *page_stat__findnew_page(struct page_stat *pstat)
307 if (a->order > b->order) 465{
308 return -1; 466 return __page_stat__findnew_page(pstat, true);
309 if (a->order < b->order)
310 return 1;
311 if (a->migrate_type > b->migrate_type)
312 return -1;
313 if (a->migrate_type < b->migrate_type)
314 return 1;
315 if (a->gfp_flags > b->gfp_flags)
316 return -1;
317 if (a->gfp_flags < b->gfp_flags)
318 return 1;
319 return 0;
320} 467}
321 468
322static struct page_stat *search_page_alloc_stat(struct page_stat *stat, bool create) 469static struct page_stat *
470__page_stat__findnew_alloc(struct page_stat *pstat, bool create)
323{ 471{
324 struct rb_node **node = &page_alloc_tree.rb_node; 472 struct rb_node **node = &page_alloc_tree.rb_node;
325 struct rb_node *parent = NULL; 473 struct rb_node *parent = NULL;
326 struct page_stat *data; 474 struct page_stat *data;
475 struct sort_dimension *sort;
327 476
328 while (*node) { 477 while (*node) {
329 s64 cmp; 478 int cmp = 0;
330 479
331 parent = *node; 480 parent = *node;
332 data = rb_entry(*node, struct page_stat, node); 481 data = rb_entry(*node, struct page_stat, node);
333 482
334 cmp = page_stat_cmp(data, stat); 483 list_for_each_entry(sort, &page_alloc_sort_input, list) {
484 cmp = sort->cmp(pstat, data);
485 if (cmp)
486 break;
487 }
488
335 if (cmp < 0) 489 if (cmp < 0)
336 node = &parent->rb_left; 490 node = &parent->rb_left;
337 else if (cmp > 0) 491 else if (cmp > 0)
@@ -345,10 +499,10 @@ static struct page_stat *search_page_alloc_stat(struct page_stat *stat, bool cre
345 499
346 data = zalloc(sizeof(*data)); 500 data = zalloc(sizeof(*data));
347 if (data != NULL) { 501 if (data != NULL) {
348 data->page = stat->page; 502 data->page = pstat->page;
349 data->order = stat->order; 503 data->order = pstat->order;
350 data->gfp_flags = stat->gfp_flags; 504 data->gfp_flags = pstat->gfp_flags;
351 data->migrate_type = stat->migrate_type; 505 data->migrate_type = pstat->migrate_type;
352 506
353 rb_link_node(&data->node, parent, node); 507 rb_link_node(&data->node, parent, node);
354 rb_insert_color(&data->node, &page_alloc_tree); 508 rb_insert_color(&data->node, &page_alloc_tree);
@@ -357,6 +511,71 @@ static struct page_stat *search_page_alloc_stat(struct page_stat *stat, bool cre
357 return data; 511 return data;
358} 512}
359 513
514static struct page_stat *page_stat__find_alloc(struct page_stat *pstat)
515{
516 return __page_stat__findnew_alloc(pstat, false);
517}
518
519static struct page_stat *page_stat__findnew_alloc(struct page_stat *pstat)
520{
521 return __page_stat__findnew_alloc(pstat, true);
522}
523
524static struct page_stat *
525__page_stat__findnew_caller(struct page_stat *pstat, bool create)
526{
527 struct rb_node **node = &page_caller_tree.rb_node;
528 struct rb_node *parent = NULL;
529 struct page_stat *data;
530 struct sort_dimension *sort;
531
532 while (*node) {
533 int cmp = 0;
534
535 parent = *node;
536 data = rb_entry(*node, struct page_stat, node);
537
538 list_for_each_entry(sort, &page_caller_sort_input, list) {
539 cmp = sort->cmp(pstat, data);
540 if (cmp)
541 break;
542 }
543
544 if (cmp < 0)
545 node = &parent->rb_left;
546 else if (cmp > 0)
547 node = &parent->rb_right;
548 else
549 return data;
550 }
551
552 if (!create)
553 return NULL;
554
555 data = zalloc(sizeof(*data));
556 if (data != NULL) {
557 data->callsite = pstat->callsite;
558 data->order = pstat->order;
559 data->gfp_flags = pstat->gfp_flags;
560 data->migrate_type = pstat->migrate_type;
561
562 rb_link_node(&data->node, parent, node);
563 rb_insert_color(&data->node, &page_caller_tree);
564 }
565
566 return data;
567}
568
569static struct page_stat *page_stat__find_caller(struct page_stat *pstat)
570{
571 return __page_stat__findnew_caller(pstat, false);
572}
573
574static struct page_stat *page_stat__findnew_caller(struct page_stat *pstat)
575{
576 return __page_stat__findnew_caller(pstat, true);
577}
578
360static bool valid_page(u64 pfn_or_page) 579static bool valid_page(u64 pfn_or_page)
361{ 580{
362 if (use_pfn && pfn_or_page == -1UL) 581 if (use_pfn && pfn_or_page == -1UL)
@@ -366,6 +585,176 @@ static bool valid_page(u64 pfn_or_page)
366 return true; 585 return true;
367} 586}
368 587
588struct gfp_flag {
589 unsigned int flags;
590 char *compact_str;
591 char *human_readable;
592};
593
594static struct gfp_flag *gfps;
595static int nr_gfps;
596
597static int gfpcmp(const void *a, const void *b)
598{
599 const struct gfp_flag *fa = a;
600 const struct gfp_flag *fb = b;
601
602 return fa->flags - fb->flags;
603}
604
605/* see include/trace/events/gfpflags.h */
606static const struct {
607 const char *original;
608 const char *compact;
609} gfp_compact_table[] = {
610 { "GFP_TRANSHUGE", "THP" },
611 { "GFP_HIGHUSER_MOVABLE", "HUM" },
612 { "GFP_HIGHUSER", "HU" },
613 { "GFP_USER", "U" },
614 { "GFP_TEMPORARY", "TMP" },
615 { "GFP_KERNEL", "K" },
616 { "GFP_NOFS", "NF" },
617 { "GFP_ATOMIC", "A" },
618 { "GFP_NOIO", "NI" },
619 { "GFP_HIGH", "H" },
620 { "GFP_WAIT", "W" },
621 { "GFP_IO", "I" },
622 { "GFP_COLD", "CO" },
623 { "GFP_NOWARN", "NWR" },
624 { "GFP_REPEAT", "R" },
625 { "GFP_NOFAIL", "NF" },
626 { "GFP_NORETRY", "NR" },
627 { "GFP_COMP", "C" },
628 { "GFP_ZERO", "Z" },
629 { "GFP_NOMEMALLOC", "NMA" },
630 { "GFP_MEMALLOC", "MA" },
631 { "GFP_HARDWALL", "HW" },
632 { "GFP_THISNODE", "TN" },
633 { "GFP_RECLAIMABLE", "RC" },
634 { "GFP_MOVABLE", "M" },
635 { "GFP_NOTRACK", "NT" },
636 { "GFP_NO_KSWAPD", "NK" },
637 { "GFP_OTHER_NODE", "ON" },
638 { "GFP_NOWAIT", "NW" },
639};
640
641static size_t max_gfp_len;
642
643static char *compact_gfp_flags(char *gfp_flags)
644{
645 char *orig_flags = strdup(gfp_flags);
646 char *new_flags = NULL;
647 char *str, *pos;
648 size_t len = 0;
649
650 if (orig_flags == NULL)
651 return NULL;
652
653 str = strtok_r(orig_flags, "|", &pos);
654 while (str) {
655 size_t i;
656 char *new;
657 const char *cpt;
658
659 for (i = 0; i < ARRAY_SIZE(gfp_compact_table); i++) {
660 if (strcmp(gfp_compact_table[i].original, str))
661 continue;
662
663 cpt = gfp_compact_table[i].compact;
664 new = realloc(new_flags, len + strlen(cpt) + 2);
665 if (new == NULL) {
666 free(new_flags);
667 return NULL;
668 }
669
670 new_flags = new;
671
672 if (!len) {
673 strcpy(new_flags, cpt);
674 } else {
675 strcat(new_flags, "|");
676 strcat(new_flags, cpt);
677 len++;
678 }
679
680 len += strlen(cpt);
681 }
682
683 str = strtok_r(NULL, "|", &pos);
684 }
685
686 if (max_gfp_len < len)
687 max_gfp_len = len;
688
689 free(orig_flags);
690 return new_flags;
691}
692
693static char *compact_gfp_string(unsigned long gfp_flags)
694{
695 struct gfp_flag key = {
696 .flags = gfp_flags,
697 };
698 struct gfp_flag *gfp;
699
700 gfp = bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp);
701 if (gfp)
702 return gfp->compact_str;
703
704 return NULL;
705}
706
707static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample,
708 unsigned int gfp_flags)
709{
710 struct pevent_record record = {
711 .cpu = sample->cpu,
712 .data = sample->raw_data,
713 .size = sample->raw_size,
714 };
715 struct trace_seq seq;
716 char *str, *pos;
717
718 if (nr_gfps) {
719 struct gfp_flag key = {
720 .flags = gfp_flags,
721 };
722
723 if (bsearch(&key, gfps, nr_gfps, sizeof(*gfps), gfpcmp))
724 return 0;
725 }
726
727 trace_seq_init(&seq);
728 pevent_event_info(&seq, evsel->tp_format, &record);
729
730 str = strtok_r(seq.buffer, " ", &pos);
731 while (str) {
732 if (!strncmp(str, "gfp_flags=", 10)) {
733 struct gfp_flag *new;
734
735 new = realloc(gfps, (nr_gfps + 1) * sizeof(*gfps));
736 if (new == NULL)
737 return -ENOMEM;
738
739 gfps = new;
740 new += nr_gfps++;
741
742 new->flags = gfp_flags;
743 new->human_readable = strdup(str + 10);
744 new->compact_str = compact_gfp_flags(str + 10);
745 if (!new->human_readable || !new->compact_str)
746 return -ENOMEM;
747
748 qsort(gfps, nr_gfps, sizeof(*gfps), gfpcmp);
749 }
750
751 str = strtok_r(NULL, " ", &pos);
752 }
753
754 trace_seq_destroy(&seq);
755 return 0;
756}
757
369static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel, 758static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
370 struct perf_sample *sample) 759 struct perf_sample *sample)
371{ 760{
@@ -375,7 +764,8 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
375 unsigned int migrate_type = perf_evsel__intval(evsel, sample, 764 unsigned int migrate_type = perf_evsel__intval(evsel, sample,
376 "migratetype"); 765 "migratetype");
377 u64 bytes = kmem_page_size << order; 766 u64 bytes = kmem_page_size << order;
378 struct page_stat *stat; 767 u64 callsite;
768 struct page_stat *pstat;
379 struct page_stat this = { 769 struct page_stat this = {
380 .order = order, 770 .order = order,
381 .gfp_flags = gfp_flags, 771 .gfp_flags = gfp_flags,
@@ -397,25 +787,41 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
397 return 0; 787 return 0;
398 } 788 }
399 789
790 if (parse_gfp_flags(evsel, sample, gfp_flags) < 0)
791 return -1;
792
793 callsite = find_callsite(evsel, sample);
794
400 /* 795 /*
401 * This is to find the current page (with correct gfp flags and 796 * This is to find the current page (with correct gfp flags and
402 * migrate type) at free event. 797 * migrate type) at free event.
403 */ 798 */
404 stat = search_page(page, true); 799 this.page = page;
405 if (stat == NULL) 800 pstat = page_stat__findnew_page(&this);
801 if (pstat == NULL)
406 return -ENOMEM; 802 return -ENOMEM;
407 803
408 stat->order = order; 804 pstat->nr_alloc++;
409 stat->gfp_flags = gfp_flags; 805 pstat->alloc_bytes += bytes;
410 stat->migrate_type = migrate_type; 806 pstat->callsite = callsite;
411 807
412 this.page = page; 808 if (!live_page) {
413 stat = search_page_alloc_stat(&this, true); 809 pstat = page_stat__findnew_alloc(&this);
414 if (stat == NULL) 810 if (pstat == NULL)
811 return -ENOMEM;
812
813 pstat->nr_alloc++;
814 pstat->alloc_bytes += bytes;
815 pstat->callsite = callsite;
816 }
817
818 this.callsite = callsite;
819 pstat = page_stat__findnew_caller(&this);
820 if (pstat == NULL)
415 return -ENOMEM; 821 return -ENOMEM;
416 822
417 stat->nr_alloc++; 823 pstat->nr_alloc++;
418 stat->alloc_bytes += bytes; 824 pstat->alloc_bytes += bytes;
419 825
420 order_stats[order][migrate_type]++; 826 order_stats[order][migrate_type]++;
421 827
@@ -428,7 +834,7 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
428 u64 page; 834 u64 page;
429 unsigned int order = perf_evsel__intval(evsel, sample, "order"); 835 unsigned int order = perf_evsel__intval(evsel, sample, "order");
430 u64 bytes = kmem_page_size << order; 836 u64 bytes = kmem_page_size << order;
431 struct page_stat *stat; 837 struct page_stat *pstat;
432 struct page_stat this = { 838 struct page_stat this = {
433 .order = order, 839 .order = order,
434 }; 840 };
@@ -441,8 +847,9 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
441 nr_page_frees++; 847 nr_page_frees++;
442 total_page_free_bytes += bytes; 848 total_page_free_bytes += bytes;
443 849
444 stat = search_page(page, false); 850 this.page = page;
445 if (stat == NULL) { 851 pstat = page_stat__find_page(&this);
852 if (pstat == NULL) {
446 pr_debug2("missing free at page %"PRIx64" (order: %d)\n", 853 pr_debug2("missing free at page %"PRIx64" (order: %d)\n",
447 page, order); 854 page, order);
448 855
@@ -452,19 +859,40 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
452 return 0; 859 return 0;
453 } 860 }
454 861
455 this.page = page; 862 this.gfp_flags = pstat->gfp_flags;
456 this.gfp_flags = stat->gfp_flags; 863 this.migrate_type = pstat->migrate_type;
457 this.migrate_type = stat->migrate_type; 864 this.callsite = pstat->callsite;
458 865
459 rb_erase(&stat->node, &page_tree); 866 rb_erase(&pstat->node, &page_live_tree);
460 free(stat); 867 free(pstat);
461 868
462 stat = search_page_alloc_stat(&this, false); 869 if (live_page) {
463 if (stat == NULL) 870 order_stats[this.order][this.migrate_type]--;
871 } else {
872 pstat = page_stat__find_alloc(&this);
873 if (pstat == NULL)
874 return -ENOMEM;
875
876 pstat->nr_free++;
877 pstat->free_bytes += bytes;
878 }
879
880 pstat = page_stat__find_caller(&this);
881 if (pstat == NULL)
464 return -ENOENT; 882 return -ENOENT;
465 883
466 stat->nr_free++; 884 pstat->nr_free++;
467 stat->free_bytes += bytes; 885 pstat->free_bytes += bytes;
886
887 if (live_page) {
888 pstat->nr_alloc--;
889 pstat->alloc_bytes -= bytes;
890
891 if (pstat->nr_alloc == 0) {
892 rb_erase(&pstat->node, &page_caller_tree);
893 free(pstat);
894 }
895 }
468 896
469 return 0; 897 return 0;
470} 898}
@@ -576,41 +1004,111 @@ static const char * const migrate_type_str[] = {
576 "UNKNOWN", 1004 "UNKNOWN",
577}; 1005};
578 1006
579static void __print_page_result(struct rb_root *root, 1007static void __print_page_alloc_result(struct perf_session *session, int n_lines)
580 struct perf_session *session __maybe_unused,
581 int n_lines)
582{ 1008{
583 struct rb_node *next = rb_first(root); 1009 struct rb_node *next = rb_first(&page_alloc_sorted);
1010 struct machine *machine = &session->machines.host;
584 const char *format; 1011 const char *format;
1012 int gfp_len = max(strlen("GFP flags"), max_gfp_len);
585 1013
586 printf("\n%.80s\n", graph_dotted_line); 1014 printf("\n%.105s\n", graph_dotted_line);
587 printf(" %-16s | Total alloc (KB) | Hits | Order | Mig.type | GFP flags\n", 1015 printf(" %-16s | %5s alloc (KB) | Hits | Order | Mig.type | %-*s | Callsite\n",
588 use_pfn ? "PFN" : "Page"); 1016 use_pfn ? "PFN" : "Page", live_page ? "Live" : "Total",
589 printf("%.80s\n", graph_dotted_line); 1017 gfp_len, "GFP flags");
1018 printf("%.105s\n", graph_dotted_line);
590 1019
591 if (use_pfn) 1020 if (use_pfn)
592 format = " %16llu | %'16llu | %'9d | %5d | %8s | %08lx\n"; 1021 format = " %16llu | %'16llu | %'9d | %5d | %8s | %-*s | %s\n";
593 else 1022 else
594 format = " %016llx | %'16llu | %'9d | %5d | %8s | %08lx\n"; 1023 format = " %016llx | %'16llu | %'9d | %5d | %8s | %-*s | %s\n";
595 1024
596 while (next && n_lines--) { 1025 while (next && n_lines--) {
597 struct page_stat *data; 1026 struct page_stat *data;
1027 struct symbol *sym;
1028 struct map *map;
1029 char buf[32];
1030 char *caller = buf;
598 1031
599 data = rb_entry(next, struct page_stat, node); 1032 data = rb_entry(next, struct page_stat, node);
1033 sym = machine__find_kernel_function(machine, data->callsite,
1034 &map, NULL);
1035 if (sym && sym->name)
1036 caller = sym->name;
1037 else
1038 scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite);
600 1039
601 printf(format, (unsigned long long)data->page, 1040 printf(format, (unsigned long long)data->page,
602 (unsigned long long)data->alloc_bytes / 1024, 1041 (unsigned long long)data->alloc_bytes / 1024,
603 data->nr_alloc, data->order, 1042 data->nr_alloc, data->order,
604 migrate_type_str[data->migrate_type], 1043 migrate_type_str[data->migrate_type],
605 (unsigned long)data->gfp_flags); 1044 gfp_len, compact_gfp_string(data->gfp_flags), caller);
606 1045
607 next = rb_next(next); 1046 next = rb_next(next);
608 } 1047 }
609 1048
610 if (n_lines == -1) 1049 if (n_lines == -1) {
611 printf(" ... | ... | ... | ... | ... | ... \n"); 1050 printf(" ... | ... | ... | ... | ... | %-*s | ...\n",
1051 gfp_len, "...");
1052 }
612 1053
613 printf("%.80s\n", graph_dotted_line); 1054 printf("%.105s\n", graph_dotted_line);
1055}
1056
1057static void __print_page_caller_result(struct perf_session *session, int n_lines)
1058{
1059 struct rb_node *next = rb_first(&page_caller_sorted);
1060 struct machine *machine = &session->machines.host;
1061 int gfp_len = max(strlen("GFP flags"), max_gfp_len);
1062
1063 printf("\n%.105s\n", graph_dotted_line);
1064 printf(" %5s alloc (KB) | Hits | Order | Mig.type | %-*s | Callsite\n",
1065 live_page ? "Live" : "Total", gfp_len, "GFP flags");
1066 printf("%.105s\n", graph_dotted_line);
1067
1068 while (next && n_lines--) {
1069 struct page_stat *data;
1070 struct symbol *sym;
1071 struct map *map;
1072 char buf[32];
1073 char *caller = buf;
1074
1075 data = rb_entry(next, struct page_stat, node);
1076 sym = machine__find_kernel_function(machine, data->callsite,
1077 &map, NULL);
1078 if (sym && sym->name)
1079 caller = sym->name;
1080 else
1081 scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite);
1082
1083 printf(" %'16llu | %'9d | %5d | %8s | %-*s | %s\n",
1084 (unsigned long long)data->alloc_bytes / 1024,
1085 data->nr_alloc, data->order,
1086 migrate_type_str[data->migrate_type],
1087 gfp_len, compact_gfp_string(data->gfp_flags), caller);
1088
1089 next = rb_next(next);
1090 }
1091
1092 if (n_lines == -1) {
1093 printf(" ... | ... | ... | ... | %-*s | ...\n",
1094 gfp_len, "...");
1095 }
1096
1097 printf("%.105s\n", graph_dotted_line);
1098}
1099
1100static void print_gfp_flags(void)
1101{
1102 int i;
1103
1104 printf("#\n");
1105 printf("# GFP flags\n");
1106 printf("# ---------\n");
1107 for (i = 0; i < nr_gfps; i++) {
1108 printf("# %08x: %*s: %s\n", gfps[i].flags,
1109 (int) max_gfp_len, gfps[i].compact_str,
1110 gfps[i].human_readable);
1111 }
614} 1112}
615 1113
616static void print_slab_summary(void) 1114static void print_slab_summary(void)
@@ -682,8 +1180,12 @@ static void print_slab_result(struct perf_session *session)
682 1180
683static void print_page_result(struct perf_session *session) 1181static void print_page_result(struct perf_session *session)
684{ 1182{
1183 if (caller_flag || alloc_flag)
1184 print_gfp_flags();
1185 if (caller_flag)
1186 __print_page_caller_result(session, caller_lines);
685 if (alloc_flag) 1187 if (alloc_flag)
686 __print_page_result(&page_alloc_sorted, session, alloc_lines); 1188 __print_page_alloc_result(session, alloc_lines);
687 print_page_summary(); 1189 print_page_summary();
688} 1190}
689 1191
@@ -695,14 +1197,10 @@ static void print_result(struct perf_session *session)
695 print_page_result(session); 1197 print_page_result(session);
696} 1198}
697 1199
698struct sort_dimension { 1200static LIST_HEAD(slab_caller_sort);
699 const char name[20]; 1201static LIST_HEAD(slab_alloc_sort);
700 sort_fn_t cmp; 1202static LIST_HEAD(page_caller_sort);
701 struct list_head list; 1203static LIST_HEAD(page_alloc_sort);
702};
703
704static LIST_HEAD(caller_sort);
705static LIST_HEAD(alloc_sort);
706 1204
707static void sort_slab_insert(struct rb_root *root, struct alloc_stat *data, 1205static void sort_slab_insert(struct rb_root *root, struct alloc_stat *data,
708 struct list_head *sort_list) 1206 struct list_head *sort_list)
@@ -751,10 +1249,12 @@ static void __sort_slab_result(struct rb_root *root, struct rb_root *root_sorted
751 } 1249 }
752} 1250}
753 1251
754static void sort_page_insert(struct rb_root *root, struct page_stat *data) 1252static void sort_page_insert(struct rb_root *root, struct page_stat *data,
1253 struct list_head *sort_list)
755{ 1254{
756 struct rb_node **new = &root->rb_node; 1255 struct rb_node **new = &root->rb_node;
757 struct rb_node *parent = NULL; 1256 struct rb_node *parent = NULL;
1257 struct sort_dimension *sort;
758 1258
759 while (*new) { 1259 while (*new) {
760 struct page_stat *this; 1260 struct page_stat *this;
@@ -763,8 +1263,11 @@ static void sort_page_insert(struct rb_root *root, struct page_stat *data)
763 this = rb_entry(*new, struct page_stat, node); 1263 this = rb_entry(*new, struct page_stat, node);
764 parent = *new; 1264 parent = *new;
765 1265
766 /* TODO: support more sort key */ 1266 list_for_each_entry(sort, sort_list, list) {
767 cmp = data->alloc_bytes - this->alloc_bytes; 1267 cmp = sort->cmp(data, this);
1268 if (cmp)
1269 break;
1270 }
768 1271
769 if (cmp > 0) 1272 if (cmp > 0)
770 new = &parent->rb_left; 1273 new = &parent->rb_left;
@@ -776,7 +1279,8 @@ static void sort_page_insert(struct rb_root *root, struct page_stat *data)
776 rb_insert_color(&data->node, root); 1279 rb_insert_color(&data->node, root);
777} 1280}
778 1281
779static void __sort_page_result(struct rb_root *root, struct rb_root *root_sorted) 1282static void __sort_page_result(struct rb_root *root, struct rb_root *root_sorted,
1283 struct list_head *sort_list)
780{ 1284{
781 struct rb_node *node; 1285 struct rb_node *node;
782 struct page_stat *data; 1286 struct page_stat *data;
@@ -788,7 +1292,7 @@ static void __sort_page_result(struct rb_root *root, struct rb_root *root_sorted
788 1292
789 rb_erase(node, root); 1293 rb_erase(node, root);
790 data = rb_entry(node, struct page_stat, node); 1294 data = rb_entry(node, struct page_stat, node);
791 sort_page_insert(root_sorted, data); 1295 sort_page_insert(root_sorted, data, sort_list);
792 } 1296 }
793} 1297}
794 1298
@@ -796,12 +1300,20 @@ static void sort_result(void)
796{ 1300{
797 if (kmem_slab) { 1301 if (kmem_slab) {
798 __sort_slab_result(&root_alloc_stat, &root_alloc_sorted, 1302 __sort_slab_result(&root_alloc_stat, &root_alloc_sorted,
799 &alloc_sort); 1303 &slab_alloc_sort);
800 __sort_slab_result(&root_caller_stat, &root_caller_sorted, 1304 __sort_slab_result(&root_caller_stat, &root_caller_sorted,
801 &caller_sort); 1305 &slab_caller_sort);
802 } 1306 }
803 if (kmem_page) { 1307 if (kmem_page) {
804 __sort_page_result(&page_alloc_tree, &page_alloc_sorted); 1308 if (live_page)
1309 __sort_page_result(&page_live_tree, &page_alloc_sorted,
1310 &page_alloc_sort);
1311 else
1312 __sort_page_result(&page_alloc_tree, &page_alloc_sorted,
1313 &page_alloc_sort);
1314
1315 __sort_page_result(&page_caller_tree, &page_caller_sorted,
1316 &page_caller_sort);
805 } 1317 }
806} 1318}
807 1319
@@ -850,8 +1362,12 @@ out:
850 return err; 1362 return err;
851} 1363}
852 1364
853static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) 1365/* slab sort keys */
1366static int ptr_cmp(void *a, void *b)
854{ 1367{
1368 struct alloc_stat *l = a;
1369 struct alloc_stat *r = b;
1370
855 if (l->ptr < r->ptr) 1371 if (l->ptr < r->ptr)
856 return -1; 1372 return -1;
857 else if (l->ptr > r->ptr) 1373 else if (l->ptr > r->ptr)
@@ -864,8 +1380,11 @@ static struct sort_dimension ptr_sort_dimension = {
864 .cmp = ptr_cmp, 1380 .cmp = ptr_cmp,
865}; 1381};
866 1382
867static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r) 1383static int slab_callsite_cmp(void *a, void *b)
868{ 1384{
1385 struct alloc_stat *l = a;
1386 struct alloc_stat *r = b;
1387
869 if (l->call_site < r->call_site) 1388 if (l->call_site < r->call_site)
870 return -1; 1389 return -1;
871 else if (l->call_site > r->call_site) 1390 else if (l->call_site > r->call_site)
@@ -875,11 +1394,14 @@ static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
875 1394
876static struct sort_dimension callsite_sort_dimension = { 1395static struct sort_dimension callsite_sort_dimension = {
877 .name = "callsite", 1396 .name = "callsite",
878 .cmp = callsite_cmp, 1397 .cmp = slab_callsite_cmp,
879}; 1398};
880 1399
881static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r) 1400static int hit_cmp(void *a, void *b)
882{ 1401{
1402 struct alloc_stat *l = a;
1403 struct alloc_stat *r = b;
1404
883 if (l->hit < r->hit) 1405 if (l->hit < r->hit)
884 return -1; 1406 return -1;
885 else if (l->hit > r->hit) 1407 else if (l->hit > r->hit)
@@ -892,8 +1414,11 @@ static struct sort_dimension hit_sort_dimension = {
892 .cmp = hit_cmp, 1414 .cmp = hit_cmp,
893}; 1415};
894 1416
895static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r) 1417static int bytes_cmp(void *a, void *b)
896{ 1418{
1419 struct alloc_stat *l = a;
1420 struct alloc_stat *r = b;
1421
897 if (l->bytes_alloc < r->bytes_alloc) 1422 if (l->bytes_alloc < r->bytes_alloc)
898 return -1; 1423 return -1;
899 else if (l->bytes_alloc > r->bytes_alloc) 1424 else if (l->bytes_alloc > r->bytes_alloc)
@@ -906,9 +1431,11 @@ static struct sort_dimension bytes_sort_dimension = {
906 .cmp = bytes_cmp, 1431 .cmp = bytes_cmp,
907}; 1432};
908 1433
909static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r) 1434static int frag_cmp(void *a, void *b)
910{ 1435{
911 double x, y; 1436 double x, y;
1437 struct alloc_stat *l = a;
1438 struct alloc_stat *r = b;
912 1439
913 x = fragmentation(l->bytes_req, l->bytes_alloc); 1440 x = fragmentation(l->bytes_req, l->bytes_alloc);
914 y = fragmentation(r->bytes_req, r->bytes_alloc); 1441 y = fragmentation(r->bytes_req, r->bytes_alloc);
@@ -925,8 +1452,11 @@ static struct sort_dimension frag_sort_dimension = {
925 .cmp = frag_cmp, 1452 .cmp = frag_cmp,
926}; 1453};
927 1454
928static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r) 1455static int pingpong_cmp(void *a, void *b)
929{ 1456{
1457 struct alloc_stat *l = a;
1458 struct alloc_stat *r = b;
1459
930 if (l->pingpong < r->pingpong) 1460 if (l->pingpong < r->pingpong)
931 return -1; 1461 return -1;
932 else if (l->pingpong > r->pingpong) 1462 else if (l->pingpong > r->pingpong)
@@ -939,7 +1469,135 @@ static struct sort_dimension pingpong_sort_dimension = {
939 .cmp = pingpong_cmp, 1469 .cmp = pingpong_cmp,
940}; 1470};
941 1471
942static struct sort_dimension *avail_sorts[] = { 1472/* page sort keys */
1473static int page_cmp(void *a, void *b)
1474{
1475 struct page_stat *l = a;
1476 struct page_stat *r = b;
1477
1478 if (l->page < r->page)
1479 return -1;
1480 else if (l->page > r->page)
1481 return 1;
1482 return 0;
1483}
1484
1485static struct sort_dimension page_sort_dimension = {
1486 .name = "page",
1487 .cmp = page_cmp,
1488};
1489
1490static int page_callsite_cmp(void *a, void *b)
1491{
1492 struct page_stat *l = a;
1493 struct page_stat *r = b;
1494
1495 if (l->callsite < r->callsite)
1496 return -1;
1497 else if (l->callsite > r->callsite)
1498 return 1;
1499 return 0;
1500}
1501
1502static struct sort_dimension page_callsite_sort_dimension = {
1503 .name = "callsite",
1504 .cmp = page_callsite_cmp,
1505};
1506
1507static int page_hit_cmp(void *a, void *b)
1508{
1509 struct page_stat *l = a;
1510 struct page_stat *r = b;
1511
1512 if (l->nr_alloc < r->nr_alloc)
1513 return -1;
1514 else if (l->nr_alloc > r->nr_alloc)
1515 return 1;
1516 return 0;
1517}
1518
1519static struct sort_dimension page_hit_sort_dimension = {
1520 .name = "hit",
1521 .cmp = page_hit_cmp,
1522};
1523
1524static int page_bytes_cmp(void *a, void *b)
1525{
1526 struct page_stat *l = a;
1527 struct page_stat *r = b;
1528
1529 if (l->alloc_bytes < r->alloc_bytes)
1530 return -1;
1531 else if (l->alloc_bytes > r->alloc_bytes)
1532 return 1;
1533 return 0;
1534}
1535
1536static struct sort_dimension page_bytes_sort_dimension = {
1537 .name = "bytes",
1538 .cmp = page_bytes_cmp,
1539};
1540
1541static int page_order_cmp(void *a, void *b)
1542{
1543 struct page_stat *l = a;
1544 struct page_stat *r = b;
1545
1546 if (l->order < r->order)
1547 return -1;
1548 else if (l->order > r->order)
1549 return 1;
1550 return 0;
1551}
1552
1553static struct sort_dimension page_order_sort_dimension = {
1554 .name = "order",
1555 .cmp = page_order_cmp,
1556};
1557
1558static int migrate_type_cmp(void *a, void *b)
1559{
1560 struct page_stat *l = a;
1561 struct page_stat *r = b;
1562
1563 /* for internal use to find free'd page */
1564 if (l->migrate_type == -1U)
1565 return 0;
1566
1567 if (l->migrate_type < r->migrate_type)
1568 return -1;
1569 else if (l->migrate_type > r->migrate_type)
1570 return 1;
1571 return 0;
1572}
1573
1574static struct sort_dimension migrate_type_sort_dimension = {
1575 .name = "migtype",
1576 .cmp = migrate_type_cmp,
1577};
1578
1579static int gfp_flags_cmp(void *a, void *b)
1580{
1581 struct page_stat *l = a;
1582 struct page_stat *r = b;
1583
1584 /* for internal use to find free'd page */
1585 if (l->gfp_flags == -1U)
1586 return 0;
1587
1588 if (l->gfp_flags < r->gfp_flags)
1589 return -1;
1590 else if (l->gfp_flags > r->gfp_flags)
1591 return 1;
1592 return 0;
1593}
1594
1595static struct sort_dimension gfp_flags_sort_dimension = {
1596 .name = "gfp",
1597 .cmp = gfp_flags_cmp,
1598};
1599
1600static struct sort_dimension *slab_sorts[] = {
943 &ptr_sort_dimension, 1601 &ptr_sort_dimension,
944 &callsite_sort_dimension, 1602 &callsite_sort_dimension,
945 &hit_sort_dimension, 1603 &hit_sort_dimension,
@@ -948,16 +1606,24 @@ static struct sort_dimension *avail_sorts[] = {
948 &pingpong_sort_dimension, 1606 &pingpong_sort_dimension,
949}; 1607};
950 1608
951#define NUM_AVAIL_SORTS ((int)ARRAY_SIZE(avail_sorts)) 1609static struct sort_dimension *page_sorts[] = {
1610 &page_sort_dimension,
1611 &page_callsite_sort_dimension,
1612 &page_hit_sort_dimension,
1613 &page_bytes_sort_dimension,
1614 &page_order_sort_dimension,
1615 &migrate_type_sort_dimension,
1616 &gfp_flags_sort_dimension,
1617};
952 1618
953static int sort_dimension__add(const char *tok, struct list_head *list) 1619static int slab_sort_dimension__add(const char *tok, struct list_head *list)
954{ 1620{
955 struct sort_dimension *sort; 1621 struct sort_dimension *sort;
956 int i; 1622 int i;
957 1623
958 for (i = 0; i < NUM_AVAIL_SORTS; i++) { 1624 for (i = 0; i < (int)ARRAY_SIZE(slab_sorts); i++) {
959 if (!strcmp(avail_sorts[i]->name, tok)) { 1625 if (!strcmp(slab_sorts[i]->name, tok)) {
960 sort = memdup(avail_sorts[i], sizeof(*avail_sorts[i])); 1626 sort = memdup(slab_sorts[i], sizeof(*slab_sorts[i]));
961 if (!sort) { 1627 if (!sort) {
962 pr_err("%s: memdup failed\n", __func__); 1628 pr_err("%s: memdup failed\n", __func__);
963 return -1; 1629 return -1;
@@ -970,7 +1636,53 @@ static int sort_dimension__add(const char *tok, struct list_head *list)
970 return -1; 1636 return -1;
971} 1637}
972 1638
973static int setup_sorting(struct list_head *sort_list, const char *arg) 1639static int page_sort_dimension__add(const char *tok, struct list_head *list)
1640{
1641 struct sort_dimension *sort;
1642 int i;
1643
1644 for (i = 0; i < (int)ARRAY_SIZE(page_sorts); i++) {
1645 if (!strcmp(page_sorts[i]->name, tok)) {
1646 sort = memdup(page_sorts[i], sizeof(*page_sorts[i]));
1647 if (!sort) {
1648 pr_err("%s: memdup failed\n", __func__);
1649 return -1;
1650 }
1651 list_add_tail(&sort->list, list);
1652 return 0;
1653 }
1654 }
1655
1656 return -1;
1657}
1658
1659static int setup_slab_sorting(struct list_head *sort_list, const char *arg)
1660{
1661 char *tok;
1662 char *str = strdup(arg);
1663 char *pos = str;
1664
1665 if (!str) {
1666 pr_err("%s: strdup failed\n", __func__);
1667 return -1;
1668 }
1669
1670 while (true) {
1671 tok = strsep(&pos, ",");
1672 if (!tok)
1673 break;
1674 if (slab_sort_dimension__add(tok, sort_list) < 0) {
1675 error("Unknown slab --sort key: '%s'", tok);
1676 free(str);
1677 return -1;
1678 }
1679 }
1680
1681 free(str);
1682 return 0;
1683}
1684
1685static int setup_page_sorting(struct list_head *sort_list, const char *arg)
974{ 1686{
975 char *tok; 1687 char *tok;
976 char *str = strdup(arg); 1688 char *str = strdup(arg);
@@ -985,8 +1697,8 @@ static int setup_sorting(struct list_head *sort_list, const char *arg)
985 tok = strsep(&pos, ","); 1697 tok = strsep(&pos, ",");
986 if (!tok) 1698 if (!tok)
987 break; 1699 break;
988 if (sort_dimension__add(tok, sort_list) < 0) { 1700 if (page_sort_dimension__add(tok, sort_list) < 0) {
989 error("Unknown --sort key: '%s'", tok); 1701 error("Unknown page --sort key: '%s'", tok);
990 free(str); 1702 free(str);
991 return -1; 1703 return -1;
992 } 1704 }
@@ -1002,10 +1714,18 @@ static int parse_sort_opt(const struct option *opt __maybe_unused,
1002 if (!arg) 1714 if (!arg)
1003 return -1; 1715 return -1;
1004 1716
1005 if (caller_flag > alloc_flag) 1717 if (kmem_page > kmem_slab ||
1006 return setup_sorting(&caller_sort, arg); 1718 (kmem_page == 0 && kmem_slab == 0 && kmem_default == KMEM_PAGE)) {
1007 else 1719 if (caller_flag > alloc_flag)
1008 return setup_sorting(&alloc_sort, arg); 1720 return setup_page_sorting(&page_caller_sort, arg);
1721 else
1722 return setup_page_sorting(&page_alloc_sort, arg);
1723 } else {
1724 if (caller_flag > alloc_flag)
1725 return setup_slab_sorting(&slab_caller_sort, arg);
1726 else
1727 return setup_slab_sorting(&slab_alloc_sort, arg);
1728 }
1009 1729
1010 return 0; 1730 return 0;
1011} 1731}
@@ -1084,7 +1804,7 @@ static int __cmd_record(int argc, const char **argv)
1084 if (kmem_slab) 1804 if (kmem_slab)
1085 rec_argc += ARRAY_SIZE(slab_events); 1805 rec_argc += ARRAY_SIZE(slab_events);
1086 if (kmem_page) 1806 if (kmem_page)
1087 rec_argc += ARRAY_SIZE(page_events); 1807 rec_argc += ARRAY_SIZE(page_events) + 1; /* for -g */
1088 1808
1089 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1809 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1090 1810
@@ -1099,6 +1819,8 @@ static int __cmd_record(int argc, const char **argv)
1099 rec_argv[i] = strdup(slab_events[j]); 1819 rec_argv[i] = strdup(slab_events[j]);
1100 } 1820 }
1101 if (kmem_page) { 1821 if (kmem_page) {
1822 rec_argv[i++] = strdup("-g");
1823
1102 for (j = 0; j < ARRAY_SIZE(page_events); j++, i++) 1824 for (j = 0; j < ARRAY_SIZE(page_events); j++, i++)
1103 rec_argv[i] = strdup(page_events[j]); 1825 rec_argv[i] = strdup(page_events[j]);
1104 } 1826 }
@@ -1109,9 +1831,26 @@ static int __cmd_record(int argc, const char **argv)
1109 return cmd_record(i, rec_argv, NULL); 1831 return cmd_record(i, rec_argv, NULL);
1110} 1832}
1111 1833
1834static int kmem_config(const char *var, const char *value, void *cb)
1835{
1836 if (!strcmp(var, "kmem.default")) {
1837 if (!strcmp(value, "slab"))
1838 kmem_default = KMEM_SLAB;
1839 else if (!strcmp(value, "page"))
1840 kmem_default = KMEM_PAGE;
1841 else
1842 pr_err("invalid default value ('slab' or 'page' required): %s\n",
1843 value);
1844 return 0;
1845 }
1846
1847 return perf_default_config(var, value, cb);
1848}
1849
1112int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) 1850int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
1113{ 1851{
1114 const char * const default_sort_order = "frag,hit,bytes"; 1852 const char * const default_slab_sort = "frag,hit,bytes";
1853 const char * const default_page_sort = "bytes,hit";
1115 struct perf_data_file file = { 1854 struct perf_data_file file = {
1116 .mode = PERF_DATA_MODE_READ, 1855 .mode = PERF_DATA_MODE_READ,
1117 }; 1856 };
@@ -1124,8 +1863,8 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
1124 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, 1863 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
1125 "show per-allocation statistics", parse_alloc_opt), 1864 "show per-allocation statistics", parse_alloc_opt),
1126 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", 1865 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
1127 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", 1866 "sort by keys: ptr, callsite, bytes, hit, pingpong, frag, "
1128 parse_sort_opt), 1867 "page, order, migtype, gfp", parse_sort_opt),
1129 OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt), 1868 OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt),
1130 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), 1869 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
1131 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"), 1870 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
@@ -1133,6 +1872,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
1133 parse_slab_opt), 1872 parse_slab_opt),
1134 OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator", 1873 OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator",
1135 parse_page_opt), 1874 parse_page_opt),
1875 OPT_BOOLEAN(0, "live", &live_page, "Show live page stat"),
1136 OPT_END() 1876 OPT_END()
1137 }; 1877 };
1138 const char *const kmem_subcommands[] = { "record", "stat", NULL }; 1878 const char *const kmem_subcommands[] = { "record", "stat", NULL };
@@ -1142,15 +1882,21 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
1142 }; 1882 };
1143 struct perf_session *session; 1883 struct perf_session *session;
1144 int ret = -1; 1884 int ret = -1;
1885 const char errmsg[] = "No %s allocation events found. Have you run 'perf kmem record --%s'?\n";
1145 1886
1887 perf_config(kmem_config, NULL);
1146 argc = parse_options_subcommand(argc, argv, kmem_options, 1888 argc = parse_options_subcommand(argc, argv, kmem_options,
1147 kmem_subcommands, kmem_usage, 0); 1889 kmem_subcommands, kmem_usage, 0);
1148 1890
1149 if (!argc) 1891 if (!argc)
1150 usage_with_options(kmem_usage, kmem_options); 1892 usage_with_options(kmem_usage, kmem_options);
1151 1893
1152 if (kmem_slab == 0 && kmem_page == 0) 1894 if (kmem_slab == 0 && kmem_page == 0) {
1153 kmem_slab = 1; /* for backward compatibility */ 1895 if (kmem_default == KMEM_SLAB)
1896 kmem_slab = 1;
1897 else
1898 kmem_page = 1;
1899 }
1154 1900
1155 if (!strncmp(argv[0], "rec", 3)) { 1901 if (!strncmp(argv[0], "rec", 3)) {
1156 symbol__init(NULL); 1902 symbol__init(NULL);
@@ -1159,19 +1905,30 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
1159 1905
1160 file.path = input_name; 1906 file.path = input_name;
1161 1907
1162 session = perf_session__new(&file, false, &perf_kmem); 1908 kmem_session = session = perf_session__new(&file, false, &perf_kmem);
1163 if (session == NULL) 1909 if (session == NULL)
1164 return -1; 1910 return -1;
1165 1911
1912 if (kmem_slab) {
1913 if (!perf_evlist__find_tracepoint_by_name(session->evlist,
1914 "kmem:kmalloc")) {
1915 pr_err(errmsg, "slab", "slab");
1916 return -1;
1917 }
1918 }
1919
1166 if (kmem_page) { 1920 if (kmem_page) {
1167 struct perf_evsel *evsel = perf_evlist__first(session->evlist); 1921 struct perf_evsel *evsel;
1168 1922
1169 if (evsel == NULL || evsel->tp_format == NULL) { 1923 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
1170 pr_err("invalid event found.. aborting\n"); 1924 "kmem:mm_page_alloc");
1925 if (evsel == NULL) {
1926 pr_err(errmsg, "page", "page");
1171 return -1; 1927 return -1;
1172 } 1928 }
1173 1929
1174 kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent); 1930 kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent);
1931 symbol_conf.use_callchain = true;
1175 } 1932 }
1176 1933
1177 symbol__init(&session->header.env); 1934 symbol__init(&session->header.env);
@@ -1182,11 +1939,21 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
1182 if (cpu__setup_cpunode_map()) 1939 if (cpu__setup_cpunode_map())
1183 goto out_delete; 1940 goto out_delete;
1184 1941
1185 if (list_empty(&caller_sort)) 1942 if (list_empty(&slab_caller_sort))
1186 setup_sorting(&caller_sort, default_sort_order); 1943 setup_slab_sorting(&slab_caller_sort, default_slab_sort);
1187 if (list_empty(&alloc_sort)) 1944 if (list_empty(&slab_alloc_sort))
1188 setup_sorting(&alloc_sort, default_sort_order); 1945 setup_slab_sorting(&slab_alloc_sort, default_slab_sort);
1189 1946 if (list_empty(&page_caller_sort))
1947 setup_page_sorting(&page_caller_sort, default_page_sort);
1948 if (list_empty(&page_alloc_sort))
1949 setup_page_sorting(&page_alloc_sort, default_page_sort);
1950
1951 if (kmem_page) {
1952 setup_page_sorting(&page_alloc_sort_input,
1953 "page,order,migtype,gfp");
1954 setup_page_sorting(&page_caller_sort_input,
1955 "callsite,order,migtype,gfp");
1956 }
1190 ret = __cmd_kmem(session); 1957 ret = __cmd_kmem(session);
1191 } else 1958 } else
1192 usage_with_options(kmem_usage, kmem_options); 1959 usage_with_options(kmem_usage, kmem_options);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index f7b1af67e9f6..53d475b1422e 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -44,22 +44,19 @@
44 44
45#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" 45#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
46#define DEFAULT_FUNC_FILTER "!_*" 46#define DEFAULT_FUNC_FILTER "!_*"
47#define DEFAULT_LIST_FILTER "*:*"
47 48
48/* Session management structure */ 49/* Session management structure */
49static struct { 50static struct {
51 int command; /* Command short_name */
50 bool list_events; 52 bool list_events;
51 bool force_add; 53 bool force_add;
52 bool show_lines;
53 bool show_vars;
54 bool show_ext_vars; 54 bool show_ext_vars;
55 bool show_funcs;
56 bool mod_events;
57 bool uprobes; 55 bool uprobes;
58 bool quiet; 56 bool quiet;
59 bool target_used; 57 bool target_used;
60 int nevents; 58 int nevents;
61 struct perf_probe_event events[MAX_PROBES]; 59 struct perf_probe_event events[MAX_PROBES];
62 struct strlist *dellist;
63 struct line_range line_range; 60 struct line_range line_range;
64 char *target; 61 char *target;
65 int max_probe_points; 62 int max_probe_points;
@@ -93,6 +90,28 @@ static int parse_probe_event(const char *str)
93 return ret; 90 return ret;
94} 91}
95 92
93static int params_add_filter(const char *str)
94{
95 const char *err = NULL;
96 int ret = 0;
97
98 pr_debug2("Add filter: %s\n", str);
99 if (!params.filter) {
100 params.filter = strfilter__new(str, &err);
101 if (!params.filter)
102 ret = err ? -EINVAL : -ENOMEM;
103 } else
104 ret = strfilter__or(params.filter, str, &err);
105
106 if (ret == -EINVAL) {
107 pr_err("Filter parse error at %td.\n", err - str + 1);
108 pr_err("Source: \"%s\"\n", str);
109 pr_err(" %*c\n", (int)(err - str + 1), '^');
110 }
111
112 return ret;
113}
114
96static int set_target(const char *ptr) 115static int set_target(const char *ptr)
97{ 116{
98 int found = 0; 117 int found = 0;
@@ -152,34 +171,11 @@ static int parse_probe_event_argv(int argc, const char **argv)
152 171
153 len += sprintf(&buf[len], "%s ", argv[i]); 172 len += sprintf(&buf[len], "%s ", argv[i]);
154 } 173 }
155 params.mod_events = true;
156 ret = parse_probe_event(buf); 174 ret = parse_probe_event(buf);
157 free(buf); 175 free(buf);
158 return ret; 176 return ret;
159} 177}
160 178
161static int opt_add_probe_event(const struct option *opt __maybe_unused,
162 const char *str, int unset __maybe_unused)
163{
164 if (str) {
165 params.mod_events = true;
166 return parse_probe_event(str);
167 } else
168 return 0;
169}
170
171static int opt_del_probe_event(const struct option *opt __maybe_unused,
172 const char *str, int unset __maybe_unused)
173{
174 if (str) {
175 params.mod_events = true;
176 if (!params.dellist)
177 params.dellist = strlist__new(true, NULL);
178 strlist__add(params.dellist, str);
179 }
180 return 0;
181}
182
183static int opt_set_target(const struct option *opt, const char *str, 179static int opt_set_target(const struct option *opt, const char *str,
184 int unset __maybe_unused) 180 int unset __maybe_unused)
185{ 181{
@@ -217,8 +213,10 @@ static int opt_set_target(const struct option *opt, const char *str,
217 return ret; 213 return ret;
218} 214}
219 215
216/* Command option callbacks */
217
220#ifdef HAVE_DWARF_SUPPORT 218#ifdef HAVE_DWARF_SUPPORT
221static int opt_show_lines(const struct option *opt __maybe_unused, 219static int opt_show_lines(const struct option *opt,
222 const char *str, int unset __maybe_unused) 220 const char *str, int unset __maybe_unused)
223{ 221{
224 int ret = 0; 222 int ret = 0;
@@ -226,19 +224,19 @@ static int opt_show_lines(const struct option *opt __maybe_unused,
226 if (!str) 224 if (!str)
227 return 0; 225 return 0;
228 226
229 if (params.show_lines) { 227 if (params.command == 'L') {
230 pr_warning("Warning: more than one --line options are" 228 pr_warning("Warning: more than one --line options are"
231 " detected. Only the first one is valid.\n"); 229 " detected. Only the first one is valid.\n");
232 return 0; 230 return 0;
233 } 231 }
234 232
235 params.show_lines = true; 233 params.command = opt->short_name;
236 ret = parse_line_range_desc(str, &params.line_range); 234 ret = parse_line_range_desc(str, &params.line_range);
237 235
238 return ret; 236 return ret;
239} 237}
240 238
241static int opt_show_vars(const struct option *opt __maybe_unused, 239static int opt_show_vars(const struct option *opt,
242 const char *str, int unset __maybe_unused) 240 const char *str, int unset __maybe_unused)
243{ 241{
244 struct perf_probe_event *pev = &params.events[params.nevents]; 242 struct perf_probe_event *pev = &params.events[params.nevents];
@@ -252,29 +250,39 @@ static int opt_show_vars(const struct option *opt __maybe_unused,
252 pr_err(" Error: '--vars' doesn't accept arguments.\n"); 250 pr_err(" Error: '--vars' doesn't accept arguments.\n");
253 return -EINVAL; 251 return -EINVAL;
254 } 252 }
255 params.show_vars = true; 253 params.command = opt->short_name;
256 254
257 return ret; 255 return ret;
258} 256}
259#endif 257#endif
258static int opt_add_probe_event(const struct option *opt,
259 const char *str, int unset __maybe_unused)
260{
261 if (str) {
262 params.command = opt->short_name;
263 return parse_probe_event(str);
264 }
265
266 return 0;
267}
268
269static int opt_set_filter_with_command(const struct option *opt,
270 const char *str, int unset)
271{
272 if (!unset)
273 params.command = opt->short_name;
274
275 if (str)
276 return params_add_filter(str);
277
278 return 0;
279}
260 280
261static int opt_set_filter(const struct option *opt __maybe_unused, 281static int opt_set_filter(const struct option *opt __maybe_unused,
262 const char *str, int unset __maybe_unused) 282 const char *str, int unset __maybe_unused)
263{ 283{
264 const char *err; 284 if (str)
265 285 return params_add_filter(str);
266 if (str) {
267 pr_debug2("Set filter: %s\n", str);
268 if (params.filter)
269 strfilter__delete(params.filter);
270 params.filter = strfilter__new(str, &err);
271 if (!params.filter) {
272 pr_err("Filter parse error at %td.\n", err - str + 1);
273 pr_err("Source: \"%s\"\n", str);
274 pr_err(" %*c\n", (int)(err - str + 1), '^');
275 return -EINVAL;
276 }
277 }
278 286
279 return 0; 287 return 0;
280} 288}
@@ -290,8 +298,6 @@ static void cleanup_params(void)
290 298
291 for (i = 0; i < params.nevents; i++) 299 for (i = 0; i < params.nevents; i++)
292 clear_perf_probe_event(params.events + i); 300 clear_perf_probe_event(params.events + i);
293 if (params.dellist)
294 strlist__delete(params.dellist);
295 line_range__clear(&params.line_range); 301 line_range__clear(&params.line_range);
296 free(params.target); 302 free(params.target);
297 if (params.filter) 303 if (params.filter)
@@ -316,22 +322,24 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
316 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 322 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
317 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 323 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
318 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 324 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
319 "perf probe --list", 325 "perf probe --list [GROUP:]EVENT ...",
320#ifdef HAVE_DWARF_SUPPORT 326#ifdef HAVE_DWARF_SUPPORT
321 "perf probe [<options>] --line 'LINEDESC'", 327 "perf probe [<options>] --line 'LINEDESC'",
322 "perf probe [<options>] --vars 'PROBEPOINT'", 328 "perf probe [<options>] --vars 'PROBEPOINT'",
323#endif 329#endif
330 "perf probe [<options>] --funcs",
324 NULL 331 NULL
325}; 332 };
326 struct option options[] = { 333 struct option options[] = {
327 OPT_INCR('v', "verbose", &verbose, 334 OPT_INCR('v', "verbose", &verbose,
328 "be more verbose (show parsed arguments, etc)"), 335 "be more verbose (show parsed arguments, etc)"),
329 OPT_BOOLEAN('q', "quiet", &params.quiet, 336 OPT_BOOLEAN('q', "quiet", &params.quiet,
330 "be quiet (do not show any mesages)"), 337 "be quiet (do not show any mesages)"),
331 OPT_BOOLEAN('l', "list", &params.list_events, 338 OPT_CALLBACK_DEFAULT('l', "list", NULL, "[GROUP:]EVENT",
332 "list up current probe events"), 339 "list up probe events",
340 opt_set_filter_with_command, DEFAULT_LIST_FILTER),
333 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 341 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
334 opt_del_probe_event), 342 opt_set_filter_with_command),
335 OPT_CALLBACK('a', "add", NULL, 343 OPT_CALLBACK('a', "add", NULL,
336#ifdef HAVE_DWARF_SUPPORT 344#ifdef HAVE_DWARF_SUPPORT
337 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" 345 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
@@ -378,8 +386,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
378 OPT__DRY_RUN(&probe_event_dry_run), 386 OPT__DRY_RUN(&probe_event_dry_run),
379 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 387 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
380 "Set how many probe points can be found for a probe."), 388 "Set how many probe points can be found for a probe."),
381 OPT_BOOLEAN('F', "funcs", &params.show_funcs, 389 OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]",
382 "Show potential probe-able functions."), 390 "Show potential probe-able functions.",
391 opt_set_filter_with_command, DEFAULT_FUNC_FILTER),
383 OPT_CALLBACK('\0', "filter", NULL, 392 OPT_CALLBACK('\0', "filter", NULL,
384 "[!]FILTER", "Set a filter (with --vars/funcs only)\n" 393 "[!]FILTER", "Set a filter (with --vars/funcs only)\n"
385 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" 394 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
@@ -402,6 +411,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
402 set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE); 411 set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
403 set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE); 412 set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
404#endif 413#endif
414 set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
405 415
406 argc = parse_options(argc, argv, options, probe_usage, 416 argc = parse_options(argc, argv, options, probe_usage,
407 PARSE_OPT_STOP_AT_NON_OPTION); 417 PARSE_OPT_STOP_AT_NON_OPTION);
@@ -410,11 +420,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
410 pr_warning(" Error: '-' is not supported.\n"); 420 pr_warning(" Error: '-' is not supported.\n");
411 usage_with_options(probe_usage, options); 421 usage_with_options(probe_usage, options);
412 } 422 }
423 if (params.command && params.command != 'a') {
424 pr_warning(" Error: another command except --add is set.\n");
425 usage_with_options(probe_usage, options);
426 }
413 ret = parse_probe_event_argv(argc, argv); 427 ret = parse_probe_event_argv(argc, argv);
414 if (ret < 0) { 428 if (ret < 0) {
415 pr_err_with_code(" Error: Command Parse Error.", ret); 429 pr_err_with_code(" Error: Command Parse Error.", ret);
416 return ret; 430 return ret;
417 } 431 }
432 params.command = 'a';
418 } 433 }
419 434
420 if (params.quiet) { 435 if (params.quiet) {
@@ -428,47 +443,35 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
428 if (params.max_probe_points == 0) 443 if (params.max_probe_points == 0)
429 params.max_probe_points = MAX_PROBES; 444 params.max_probe_points = MAX_PROBES;
430 445
431 if ((!params.nevents && !params.dellist && !params.list_events &&
432 !params.show_lines && !params.show_funcs))
433 usage_with_options(probe_usage, options);
434
435 /* 446 /*
436 * Only consider the user's kernel image path if given. 447 * Only consider the user's kernel image path if given.
437 */ 448 */
438 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 449 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
439 450
440 if (params.list_events) { 451 switch (params.command) {
452 case 'l':
441 if (params.uprobes) { 453 if (params.uprobes) {
442 pr_warning(" Error: Don't use --list with --exec.\n"); 454 pr_warning(" Error: Don't use --list with --exec.\n");
443 usage_with_options(probe_usage, options); 455 usage_with_options(probe_usage, options);
444 } 456 }
445 ret = show_perf_probe_events(); 457 ret = show_perf_probe_events(params.filter);
446 if (ret < 0) 458 if (ret < 0)
447 pr_err_with_code(" Error: Failed to show event list.", ret); 459 pr_err_with_code(" Error: Failed to show event list.", ret);
448 return ret; 460 return ret;
449 } 461 case 'F':
450 if (params.show_funcs) {
451 if (!params.filter)
452 params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
453 NULL);
454 ret = show_available_funcs(params.target, params.filter, 462 ret = show_available_funcs(params.target, params.filter,
455 params.uprobes); 463 params.uprobes);
456 strfilter__delete(params.filter);
457 params.filter = NULL;
458 if (ret < 0) 464 if (ret < 0)
459 pr_err_with_code(" Error: Failed to show functions.", ret); 465 pr_err_with_code(" Error: Failed to show functions.", ret);
460 return ret; 466 return ret;
461 }
462
463#ifdef HAVE_DWARF_SUPPORT 467#ifdef HAVE_DWARF_SUPPORT
464 if (params.show_lines) { 468 case 'L':
465 ret = show_line_range(&params.line_range, params.target, 469 ret = show_line_range(&params.line_range, params.target,
466 params.uprobes); 470 params.uprobes);
467 if (ret < 0) 471 if (ret < 0)
468 pr_err_with_code(" Error: Failed to show lines.", ret); 472 pr_err_with_code(" Error: Failed to show lines.", ret);
469 return ret; 473 return ret;
470 } 474 case 'V':
471 if (params.show_vars) {
472 if (!params.filter) 475 if (!params.filter)
473 params.filter = strfilter__new(DEFAULT_VAR_FILTER, 476 params.filter = strfilter__new(DEFAULT_VAR_FILTER,
474 NULL); 477 NULL);
@@ -478,23 +481,18 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
478 params.target, 481 params.target,
479 params.filter, 482 params.filter,
480 params.show_ext_vars); 483 params.show_ext_vars);
481 strfilter__delete(params.filter);
482 params.filter = NULL;
483 if (ret < 0) 484 if (ret < 0)
484 pr_err_with_code(" Error: Failed to show vars.", ret); 485 pr_err_with_code(" Error: Failed to show vars.", ret);
485 return ret; 486 return ret;
486 }
487#endif 487#endif
488 488 case 'd':
489 if (params.dellist) { 489 ret = del_perf_probe_events(params.filter);
490 ret = del_perf_probe_events(params.dellist);
491 if (ret < 0) { 490 if (ret < 0) {
492 pr_err_with_code(" Error: Failed to delete events.", ret); 491 pr_err_with_code(" Error: Failed to delete events.", ret);
493 return ret; 492 return ret;
494 } 493 }
495 } 494 break;
496 495 case 'a':
497 if (params.nevents) {
498 /* Ensure the last given target is used */ 496 /* Ensure the last given target is used */
499 if (params.target && !params.target_used) { 497 if (params.target && !params.target_used) {
500 pr_warning(" Error: -x/-m must follow the probe definitions.\n"); 498 pr_warning(" Error: -x/-m must follow the probe definitions.\n");
@@ -508,6 +506,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
508 pr_err_with_code(" Error: Failed to add events.", ret); 506 pr_err_with_code(" Error: Failed to add events.", ret);
509 return ret; 507 return ret;
510 } 508 }
509 break;
510 default:
511 usage_with_options(probe_usage, options);
511 } 512 }
512 return 0; 513 return 0;
513} 514}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index c3efdfb630b5..5dfe91395617 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -27,6 +27,7 @@
27#include "util/cpumap.h" 27#include "util/cpumap.h"
28#include "util/thread_map.h" 28#include "util/thread_map.h"
29#include "util/data.h" 29#include "util/data.h"
30#include "util/auxtrace.h"
30 31
31#include <unistd.h> 32#include <unistd.h>
32#include <sched.h> 33#include <sched.h>
@@ -38,6 +39,7 @@ struct record {
38 struct record_opts opts; 39 struct record_opts opts;
39 u64 bytes_written; 40 u64 bytes_written;
40 struct perf_data_file file; 41 struct perf_data_file file;
42 struct auxtrace_record *itr;
41 struct perf_evlist *evlist; 43 struct perf_evlist *evlist;
42 struct perf_session *session; 44 struct perf_session *session;
43 const char *progname; 45 const char *progname;
@@ -110,9 +112,12 @@ out:
110 return rc; 112 return rc;
111} 113}
112 114
113static volatile int done = 0; 115static volatile int done;
114static volatile int signr = -1; 116static volatile int signr = -1;
115static volatile int child_finished = 0; 117static volatile int child_finished;
118static volatile int auxtrace_snapshot_enabled;
119static volatile int auxtrace_snapshot_err;
120static volatile int auxtrace_record__snapshot_started;
116 121
117static void sig_handler(int sig) 122static void sig_handler(int sig)
118{ 123{
@@ -133,6 +138,133 @@ static void record__sig_exit(void)
133 raise(signr); 138 raise(signr);
134} 139}
135 140
141#ifdef HAVE_AUXTRACE_SUPPORT
142
143static int record__process_auxtrace(struct perf_tool *tool,
144 union perf_event *event, void *data1,
145 size_t len1, void *data2, size_t len2)
146{
147 struct record *rec = container_of(tool, struct record, tool);
148 struct perf_data_file *file = &rec->file;
149 size_t padding;
150 u8 pad[8] = {0};
151
152 if (!perf_data_file__is_pipe(file)) {
153 off_t file_offset;
154 int fd = perf_data_file__fd(file);
155 int err;
156
157 file_offset = lseek(fd, 0, SEEK_CUR);
158 if (file_offset == -1)
159 return -1;
160 err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index,
161 event, file_offset);
162 if (err)
163 return err;
164 }
165
166 /* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */
167 padding = (len1 + len2) & 7;
168 if (padding)
169 padding = 8 - padding;
170
171 record__write(rec, event, event->header.size);
172 record__write(rec, data1, len1);
173 if (len2)
174 record__write(rec, data2, len2);
175 record__write(rec, &pad, padding);
176
177 return 0;
178}
179
180static int record__auxtrace_mmap_read(struct record *rec,
181 struct auxtrace_mmap *mm)
182{
183 int ret;
184
185 ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
186 record__process_auxtrace);
187 if (ret < 0)
188 return ret;
189
190 if (ret)
191 rec->samples++;
192
193 return 0;
194}
195
196static int record__auxtrace_mmap_read_snapshot(struct record *rec,
197 struct auxtrace_mmap *mm)
198{
199 int ret;
200
201 ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
202 record__process_auxtrace,
203 rec->opts.auxtrace_snapshot_size);
204 if (ret < 0)
205 return ret;
206
207 if (ret)
208 rec->samples++;
209
210 return 0;
211}
212
213static int record__auxtrace_read_snapshot_all(struct record *rec)
214{
215 int i;
216 int rc = 0;
217
218 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
219 struct auxtrace_mmap *mm =
220 &rec->evlist->mmap[i].auxtrace_mmap;
221
222 if (!mm->base)
223 continue;
224
225 if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
226 rc = -1;
227 goto out;
228 }
229 }
230out:
231 return rc;
232}
233
234static void record__read_auxtrace_snapshot(struct record *rec)
235{
236 pr_debug("Recording AUX area tracing snapshot\n");
237 if (record__auxtrace_read_snapshot_all(rec) < 0) {
238 auxtrace_snapshot_err = -1;
239 } else {
240 auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
241 if (!auxtrace_snapshot_err)
242 auxtrace_snapshot_enabled = 1;
243 }
244}
245
246#else
247
248static inline
249int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
250 struct auxtrace_mmap *mm __maybe_unused)
251{
252 return 0;
253}
254
255static inline
256void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
257{
258}
259
260static inline
261int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
262{
263 return 0;
264}
265
266#endif
267
136static int record__open(struct record *rec) 268static int record__open(struct record *rec)
137{ 269{
138 char msg[512]; 270 char msg[512];
@@ -169,13 +301,16 @@ try_again:
169 goto out; 301 goto out;
170 } 302 }
171 303
172 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { 304 if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
305 opts->auxtrace_mmap_pages,
306 opts->auxtrace_snapshot_mode) < 0) {
173 if (errno == EPERM) { 307 if (errno == EPERM) {
174 pr_err("Permission error mapping pages.\n" 308 pr_err("Permission error mapping pages.\n"
175 "Consider increasing " 309 "Consider increasing "
176 "/proc/sys/kernel/perf_event_mlock_kb,\n" 310 "/proc/sys/kernel/perf_event_mlock_kb,\n"
177 "or try again with a smaller value of -m/--mmap_pages.\n" 311 "or try again with a smaller value of -m/--mmap_pages.\n"
178 "(current value: %u)\n", opts->mmap_pages); 312 "(current value: %u,%u)\n",
313 opts->mmap_pages, opts->auxtrace_mmap_pages);
179 rc = -errno; 314 rc = -errno;
180 } else { 315 } else {
181 pr_err("failed to mmap with %d (%s)\n", errno, 316 pr_err("failed to mmap with %d (%s)\n", errno,
@@ -270,12 +405,20 @@ static int record__mmap_read_all(struct record *rec)
270 int rc = 0; 405 int rc = 0;
271 406
272 for (i = 0; i < rec->evlist->nr_mmaps; i++) { 407 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
408 struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
409
273 if (rec->evlist->mmap[i].base) { 410 if (rec->evlist->mmap[i].base) {
274 if (record__mmap_read(rec, i) != 0) { 411 if (record__mmap_read(rec, i) != 0) {
275 rc = -1; 412 rc = -1;
276 goto out; 413 goto out;
277 } 414 }
278 } 415 }
416
417 if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
418 record__auxtrace_mmap_read(rec, mm) != 0) {
419 rc = -1;
420 goto out;
421 }
279 } 422 }
280 423
281 /* 424 /*
@@ -305,6 +448,9 @@ static void record__init_features(struct record *rec)
305 448
306 if (!rec->opts.branch_stack) 449 if (!rec->opts.branch_stack)
307 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 450 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
451
452 if (!rec->opts.full_auxtrace)
453 perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
308} 454}
309 455
310static volatile int workload_exec_errno; 456static volatile int workload_exec_errno;
@@ -323,6 +469,8 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
323 child_finished = 1; 469 child_finished = 1;
324} 470}
325 471
472static void snapshot_sig_handler(int sig);
473
326static int __cmd_record(struct record *rec, int argc, const char **argv) 474static int __cmd_record(struct record *rec, int argc, const char **argv)
327{ 475{
328 int err; 476 int err;
@@ -343,6 +491,10 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
343 signal(SIGCHLD, sig_handler); 491 signal(SIGCHLD, sig_handler);
344 signal(SIGINT, sig_handler); 492 signal(SIGINT, sig_handler);
345 signal(SIGTERM, sig_handler); 493 signal(SIGTERM, sig_handler);
494 if (rec->opts.auxtrace_snapshot_mode)
495 signal(SIGUSR2, snapshot_sig_handler);
496 else
497 signal(SIGUSR2, SIG_IGN);
346 498
347 session = perf_session__new(file, false, tool); 499 session = perf_session__new(file, false, tool);
348 if (session == NULL) { 500 if (session == NULL) {
@@ -421,6 +573,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
421 } 573 }
422 } 574 }
423 575
576 if (rec->opts.full_auxtrace) {
577 err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
578 session, process_synthesized_event);
579 if (err)
580 goto out_delete_session;
581 }
582
424 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 583 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
425 machine); 584 machine);
426 if (err < 0) 585 if (err < 0)
@@ -475,14 +634,27 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
475 perf_evlist__enable(rec->evlist); 634 perf_evlist__enable(rec->evlist);
476 } 635 }
477 636
637 auxtrace_snapshot_enabled = 1;
478 for (;;) { 638 for (;;) {
479 int hits = rec->samples; 639 int hits = rec->samples;
480 640
481 if (record__mmap_read_all(rec) < 0) { 641 if (record__mmap_read_all(rec) < 0) {
642 auxtrace_snapshot_enabled = 0;
482 err = -1; 643 err = -1;
483 goto out_child; 644 goto out_child;
484 } 645 }
485 646
647 if (auxtrace_record__snapshot_started) {
648 auxtrace_record__snapshot_started = 0;
649 if (!auxtrace_snapshot_err)
650 record__read_auxtrace_snapshot(rec);
651 if (auxtrace_snapshot_err) {
652 pr_err("AUX area tracing snapshot failed\n");
653 err = -1;
654 goto out_child;
655 }
656 }
657
486 if (hits == rec->samples) { 658 if (hits == rec->samples) {
487 if (done || draining) 659 if (done || draining)
488 break; 660 break;
@@ -505,10 +677,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
505 * disable events in this case. 677 * disable events in this case.
506 */ 678 */
507 if (done && !disabled && !target__none(&opts->target)) { 679 if (done && !disabled && !target__none(&opts->target)) {
680 auxtrace_snapshot_enabled = 0;
508 perf_evlist__disable(rec->evlist); 681 perf_evlist__disable(rec->evlist);
509 disabled = true; 682 disabled = true;
510 } 683 }
511 } 684 }
685 auxtrace_snapshot_enabled = 0;
512 686
513 if (forks && workload_exec_errno) { 687 if (forks && workload_exec_errno) {
514 char msg[STRERR_BUFSIZE]; 688 char msg[STRERR_BUFSIZE];
@@ -545,15 +719,23 @@ out_child:
545 if (!err && !file->is_pipe) { 719 if (!err && !file->is_pipe) {
546 rec->session->header.data_size += rec->bytes_written; 720 rec->session->header.data_size += rec->bytes_written;
547 721
548 if (!rec->no_buildid) 722 if (!rec->no_buildid) {
549 process_buildids(rec); 723 process_buildids(rec);
724 /*
725 * We take all buildids when the file contains
726 * AUX area tracing data because we do not decode the
727 * trace because it would take too long.
728 */
729 if (rec->opts.full_auxtrace)
730 dsos__hit_all(rec->session);
731 }
550 perf_session__write_header(rec->session, rec->evlist, fd, true); 732 perf_session__write_header(rec->session, rec->evlist, fd, true);
551 } 733 }
552 734
553 if (!err && !quiet) { 735 if (!err && !quiet) {
554 char samples[128]; 736 char samples[128];
555 737
556 if (rec->samples) 738 if (rec->samples && !rec->opts.full_auxtrace)
557 scnprintf(samples, sizeof(samples), 739 scnprintf(samples, sizeof(samples),
558 " (%" PRIu64 " samples)", rec->samples); 740 " (%" PRIu64 " samples)", rec->samples);
559 else 741 else
@@ -795,6 +977,49 @@ static int parse_clockid(const struct option *opt, const char *str, int unset)
795 return -1; 977 return -1;
796} 978}
797 979
980static int record__parse_mmap_pages(const struct option *opt,
981 const char *str,
982 int unset __maybe_unused)
983{
984 struct record_opts *opts = opt->value;
985 char *s, *p;
986 unsigned int mmap_pages;
987 int ret;
988
989 if (!str)
990 return -EINVAL;
991
992 s = strdup(str);
993 if (!s)
994 return -ENOMEM;
995
996 p = strchr(s, ',');
997 if (p)
998 *p = '\0';
999
1000 if (*s) {
1001 ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
1002 if (ret)
1003 goto out_free;
1004 opts->mmap_pages = mmap_pages;
1005 }
1006
1007 if (!p) {
1008 ret = 0;
1009 goto out_free;
1010 }
1011
1012 ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
1013 if (ret)
1014 goto out_free;
1015
1016 opts->auxtrace_mmap_pages = mmap_pages;
1017
1018out_free:
1019 free(s);
1020 return ret;
1021}
1022
798static const char * const __record_usage[] = { 1023static const char * const __record_usage[] = {
799 "perf record [<options>] [<command>]", 1024 "perf record [<options>] [<command>]",
800 "perf record [<options>] -- <command> [<options>]", 1025 "perf record [<options>] -- <command> [<options>]",
@@ -875,9 +1100,9 @@ struct option __record_options[] = {
875 &record.opts.no_inherit_set, 1100 &record.opts.no_inherit_set,
876 "child tasks do not inherit counters"), 1101 "child tasks do not inherit counters"),
877 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 1102 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
878 OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", 1103 OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
879 "number of mmap data pages", 1104 "number of mmap data pages and AUX area tracing mmap pages",
880 perf_evlist__parse_mmap_pages), 1105 record__parse_mmap_pages),
881 OPT_BOOLEAN(0, "group", &record.opts.group, 1106 OPT_BOOLEAN(0, "group", &record.opts.group,
882 "put the counters into a counter group"), 1107 "put the counters into a counter group"),
883 OPT_CALLBACK_NOOPT('g', NULL, &record.opts, 1108 OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
@@ -929,6 +1154,8 @@ struct option __record_options[] = {
929 OPT_CALLBACK('k', "clockid", &record.opts, 1154 OPT_CALLBACK('k', "clockid", &record.opts,
930 "clockid", "clockid to use for events, see clock_gettime()", 1155 "clockid", "clockid to use for events, see clock_gettime()",
931 parse_clockid), 1156 parse_clockid),
1157 OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
1158 "opts", "AUX area tracing Snapshot Mode", ""),
932 OPT_END() 1159 OPT_END()
933}; 1160};
934 1161
@@ -936,7 +1163,7 @@ struct option *record_options = __record_options;
936 1163
937int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 1164int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
938{ 1165{
939 int err = -ENOMEM; 1166 int err;
940 struct record *rec = &record; 1167 struct record *rec = &record;
941 char errbuf[BUFSIZ]; 1168 char errbuf[BUFSIZ];
942 1169
@@ -957,6 +1184,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
957 usage_with_options(record_usage, record_options); 1184 usage_with_options(record_usage, record_options);
958 } 1185 }
959 1186
1187 if (!rec->itr) {
1188 rec->itr = auxtrace_record__init(rec->evlist, &err);
1189 if (err)
1190 return err;
1191 }
1192
1193 err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts,
1194 rec->opts.auxtrace_snapshot_opts);
1195 if (err)
1196 return err;
1197
1198 err = -ENOMEM;
1199
960 symbol__init(NULL); 1200 symbol__init(NULL);
961 1201
962 if (symbol_conf.kptr_restrict) 1202 if (symbol_conf.kptr_restrict)
@@ -1002,6 +1242,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1002 if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0) 1242 if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1003 usage_with_options(record_usage, record_options); 1243 usage_with_options(record_usage, record_options);
1004 1244
1245 err = auxtrace_record__options(rec->itr, rec->evlist, &rec->opts);
1246 if (err)
1247 goto out_symbol_exit;
1248
1005 if (record_opts__config(&rec->opts)) { 1249 if (record_opts__config(&rec->opts)) {
1006 err = -EINVAL; 1250 err = -EINVAL;
1007 goto out_symbol_exit; 1251 goto out_symbol_exit;
@@ -1011,5 +1255,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1011out_symbol_exit: 1255out_symbol_exit:
1012 perf_evlist__delete(rec->evlist); 1256 perf_evlist__delete(rec->evlist);
1013 symbol__exit(); 1257 symbol__exit();
1258 auxtrace_record__free(rec->itr);
1014 return err; 1259 return err;
1015} 1260}
1261
1262static void snapshot_sig_handler(int sig __maybe_unused)
1263{
1264 if (!auxtrace_snapshot_enabled)
1265 return;
1266 auxtrace_snapshot_enabled = 0;
1267 auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
1268 auxtrace_record__snapshot_started = 1;
1269}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 476cdf7afcca..18cb0ff39b4e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -36,6 +36,8 @@
36#include "util/data.h" 36#include "util/data.h"
37#include "arch/common.h" 37#include "arch/common.h"
38 38
39#include "util/auxtrace.h"
40
39#include <dlfcn.h> 41#include <dlfcn.h>
40#include <linux/bitmap.h> 42#include <linux/bitmap.h>
41 43
@@ -585,6 +587,7 @@ parse_percent_limit(const struct option *opt, const char *str,
585int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) 587int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
586{ 588{
587 struct perf_session *session; 589 struct perf_session *session;
590 struct itrace_synth_opts itrace_synth_opts = { .set = 0, };
588 struct stat st; 591 struct stat st;
589 bool has_br_stack = false; 592 bool has_br_stack = false;
590 int branch_mode = -1; 593 int branch_mode = -1;
@@ -607,6 +610,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
607 .attr = perf_event__process_attr, 610 .attr = perf_event__process_attr,
608 .tracing_data = perf_event__process_tracing_data, 611 .tracing_data = perf_event__process_tracing_data,
609 .build_id = perf_event__process_build_id, 612 .build_id = perf_event__process_build_id,
613 .id_index = perf_event__process_id_index,
614 .auxtrace_info = perf_event__process_auxtrace_info,
615 .auxtrace = perf_event__process_auxtrace,
610 .ordered_events = true, 616 .ordered_events = true,
611 .ordering_requires_timestamps = true, 617 .ordering_requires_timestamps = true,
612 }, 618 },
@@ -717,6 +723,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
717 "Don't show entries under that percent", parse_percent_limit), 723 "Don't show entries under that percent", parse_percent_limit),
718 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", 724 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
719 "how to display percentage of filtered entries", parse_filter_percentage), 725 "how to display percentage of filtered entries", parse_filter_percentage),
726 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
727 "Instruction Tracing options",
728 itrace_parse_synth_opts),
720 OPT_END() 729 OPT_END()
721 }; 730 };
722 struct perf_data_file file = { 731 struct perf_data_file file = {
@@ -761,6 +770,8 @@ repeat:
761 report.queue_size); 770 report.queue_size);
762 } 771 }
763 772
773 session->itrace_synth_opts = &itrace_synth_opts;
774
764 report.session = session; 775 report.session = session;
765 776
766 has_br_stack = perf_header__has_feat(&session->header, 777 has_br_stack = perf_header__has_feat(&session->header,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 58f10b8e6ff2..6805098e3751 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -16,6 +16,7 @@
16#include "util/evsel.h" 16#include "util/evsel.h"
17#include "util/sort.h" 17#include "util/sort.h"
18#include "util/data.h" 18#include "util/data.h"
19#include "util/auxtrace.h"
19#include <linux/bitmap.h> 20#include <linux/bitmap.h>
20 21
21static char const *script_name; 22static char const *script_name;
@@ -26,6 +27,7 @@ static u64 nr_unordered;
26static bool no_callchain; 27static bool no_callchain;
27static bool latency_format; 28static bool latency_format;
28static bool system_wide; 29static bool system_wide;
30static bool print_flags;
29static const char *cpu_list; 31static const char *cpu_list;
30static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 32static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
31 33
@@ -146,9 +148,10 @@ static const char *output_field2str(enum perf_output_field field)
146 148
147#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) 149#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
148 150
149static int perf_evsel__check_stype(struct perf_evsel *evsel, 151static int perf_evsel__do_check_stype(struct perf_evsel *evsel,
150 u64 sample_type, const char *sample_msg, 152 u64 sample_type, const char *sample_msg,
151 enum perf_output_field field) 153 enum perf_output_field field,
154 bool allow_user_set)
152{ 155{
153 struct perf_event_attr *attr = &evsel->attr; 156 struct perf_event_attr *attr = &evsel->attr;
154 int type = attr->type; 157 int type = attr->type;
@@ -158,6 +161,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
158 return 0; 161 return 0;
159 162
160 if (output[type].user_set) { 163 if (output[type].user_set) {
164 if (allow_user_set)
165 return 0;
161 evname = perf_evsel__name(evsel); 166 evname = perf_evsel__name(evsel);
162 pr_err("Samples for '%s' event do not have %s attribute set. " 167 pr_err("Samples for '%s' event do not have %s attribute set. "
163 "Cannot print '%s' field.\n", 168 "Cannot print '%s' field.\n",
@@ -175,10 +180,22 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
175 return 0; 180 return 0;
176} 181}
177 182
183static int perf_evsel__check_stype(struct perf_evsel *evsel,
184 u64 sample_type, const char *sample_msg,
185 enum perf_output_field field)
186{
187 return perf_evsel__do_check_stype(evsel, sample_type, sample_msg, field,
188 false);
189}
190
178static int perf_evsel__check_attr(struct perf_evsel *evsel, 191static int perf_evsel__check_attr(struct perf_evsel *evsel,
179 struct perf_session *session) 192 struct perf_session *session)
180{ 193{
181 struct perf_event_attr *attr = &evsel->attr; 194 struct perf_event_attr *attr = &evsel->attr;
195 bool allow_user_set;
196
197 allow_user_set = perf_header__has_feat(&session->header,
198 HEADER_AUXTRACE);
182 199
183 if (PRINT_FIELD(TRACE) && 200 if (PRINT_FIELD(TRACE) &&
184 !perf_session__has_traces(session, "record -R")) 201 !perf_session__has_traces(session, "record -R"))
@@ -191,8 +208,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
191 } 208 }
192 209
193 if (PRINT_FIELD(ADDR) && 210 if (PRINT_FIELD(ADDR) &&
194 perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR", 211 perf_evsel__do_check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR",
195 PERF_OUTPUT_ADDR)) 212 PERF_OUTPUT_ADDR, allow_user_set))
196 return -EINVAL; 213 return -EINVAL;
197 214
198 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { 215 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
@@ -229,8 +246,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
229 return -EINVAL; 246 return -EINVAL;
230 247
231 if (PRINT_FIELD(CPU) && 248 if (PRINT_FIELD(CPU) &&
232 perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU", 249 perf_evsel__do_check_stype(evsel, PERF_SAMPLE_CPU, "CPU",
233 PERF_OUTPUT_CPU)) 250 PERF_OUTPUT_CPU, allow_user_set))
234 return -EINVAL; 251 return -EINVAL;
235 252
236 if (PRINT_FIELD(PERIOD) && 253 if (PRINT_FIELD(PERIOD) &&
@@ -445,6 +462,25 @@ static void print_sample_bts(union perf_event *event,
445 printf("\n"); 462 printf("\n");
446} 463}
447 464
465static void print_sample_flags(u32 flags)
466{
467 const char *chars = PERF_IP_FLAG_CHARS;
468 const int n = strlen(PERF_IP_FLAG_CHARS);
469 char str[33];
470 int i, pos = 0;
471
472 for (i = 0; i < n; i++, flags >>= 1) {
473 if (flags & 1)
474 str[pos++] = chars[i];
475 }
476 for (; i < 32; i++, flags >>= 1) {
477 if (flags & 1)
478 str[pos++] = '?';
479 }
480 str[pos] = 0;
481 printf(" %-4s ", str);
482}
483
448static void process_event(union perf_event *event, struct perf_sample *sample, 484static void process_event(union perf_event *event, struct perf_sample *sample,
449 struct perf_evsel *evsel, struct addr_location *al) 485 struct perf_evsel *evsel, struct addr_location *al)
450{ 486{
@@ -464,6 +500,9 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
464 printf("%s: ", evname ? evname : "[unknown]"); 500 printf("%s: ", evname ? evname : "[unknown]");
465 } 501 }
466 502
503 if (print_flags)
504 print_sample_flags(sample->flags);
505
467 if (is_bts_event(attr)) { 506 if (is_bts_event(attr)) {
468 print_sample_bts(event, sample, evsel, thread, al); 507 print_sample_bts(event, sample, evsel, thread, al);
469 return; 508 return;
@@ -999,12 +1038,15 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
999 } 1038 }
1000 } 1039 }
1001 1040
1002 tok = strtok(tok, ","); 1041 for (tok = strtok(tok, ","); tok; tok = strtok(NULL, ",")) {
1003 while (tok) {
1004 for (i = 0; i < imax; ++i) { 1042 for (i = 0; i < imax; ++i) {
1005 if (strcmp(tok, all_output_options[i].str) == 0) 1043 if (strcmp(tok, all_output_options[i].str) == 0)
1006 break; 1044 break;
1007 } 1045 }
1046 if (i == imax && strcmp(tok, "flags") == 0) {
1047 print_flags = true;
1048 continue;
1049 }
1008 if (i == imax) { 1050 if (i == imax) {
1009 fprintf(stderr, "Invalid field requested.\n"); 1051 fprintf(stderr, "Invalid field requested.\n");
1010 rc = -EINVAL; 1052 rc = -EINVAL;
@@ -1032,8 +1074,6 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
1032 } 1074 }
1033 output[type].fields |= all_output_options[i].field; 1075 output[type].fields |= all_output_options[i].field;
1034 } 1076 }
1035
1036 tok = strtok(NULL, ",");
1037 } 1077 }
1038 1078
1039 if (type >= 0) { 1079 if (type >= 0) {
@@ -1497,6 +1537,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1497 char *rec_script_path = NULL; 1537 char *rec_script_path = NULL;
1498 char *rep_script_path = NULL; 1538 char *rep_script_path = NULL;
1499 struct perf_session *session; 1539 struct perf_session *session;
1540 struct itrace_synth_opts itrace_synth_opts = { .set = false, };
1500 char *script_path = NULL; 1541 char *script_path = NULL;
1501 const char **__argv; 1542 const char **__argv;
1502 int i, j, err = 0; 1543 int i, j, err = 0;
@@ -1511,6 +1552,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1511 .attr = process_attr, 1552 .attr = process_attr,
1512 .tracing_data = perf_event__process_tracing_data, 1553 .tracing_data = perf_event__process_tracing_data,
1513 .build_id = perf_event__process_build_id, 1554 .build_id = perf_event__process_build_id,
1555 .id_index = perf_event__process_id_index,
1556 .auxtrace_info = perf_event__process_auxtrace_info,
1557 .auxtrace = perf_event__process_auxtrace,
1558 .auxtrace_error = perf_event__process_auxtrace_error,
1514 .ordered_events = true, 1559 .ordered_events = true,
1515 .ordering_requires_timestamps = true, 1560 .ordering_requires_timestamps = true,
1516 }, 1561 },
@@ -1549,7 +1594,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1549 "comma separated output fields prepend with 'type:'. " 1594 "comma separated output fields prepend with 'type:'. "
1550 "Valid types: hw,sw,trace,raw. " 1595 "Valid types: hw,sw,trace,raw. "
1551 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," 1596 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
1552 "addr,symoff,period", parse_output_fields), 1597 "addr,symoff,period,flags", parse_output_fields),
1553 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1598 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1554 "system-wide collection from all CPUs"), 1599 "system-wide collection from all CPUs"),
1555 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 1600 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
@@ -1570,6 +1615,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1570 OPT_BOOLEAN('\0', "show-mmap-events", &script.show_mmap_events, 1615 OPT_BOOLEAN('\0', "show-mmap-events", &script.show_mmap_events,
1571 "Show the mmap events"), 1616 "Show the mmap events"),
1572 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"), 1617 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
1618 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
1619 "Instruction Tracing options",
1620 itrace_parse_synth_opts),
1573 OPT_END() 1621 OPT_END()
1574 }; 1622 };
1575 const char * const script_subcommands[] = { "record", "report", NULL }; 1623 const char * const script_subcommands[] = { "record", "report", NULL };
@@ -1765,6 +1813,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1765 1813
1766 script.session = session; 1814 script.session = session;
1767 1815
1816 session->itrace_synth_opts = &itrace_synth_opts;
1817
1768 if (cpu_list) { 1818 if (cpu_list) {
1769 err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); 1819 err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
1770 if (err < 0) 1820 if (err < 0)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index f7b8218785f6..fd577f725d23 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -247,21 +247,50 @@ out_free:
247 return -1; 247 return -1;
248} 248}
249 249
250enum {
251 CTX_BIT_USER = 1 << 0,
252 CTX_BIT_KERNEL = 1 << 1,
253 CTX_BIT_HV = 1 << 2,
254 CTX_BIT_HOST = 1 << 3,
255 CTX_BIT_IDLE = 1 << 4,
256 CTX_BIT_MAX = 1 << 5,
257};
258
259#define NUM_CTX CTX_BIT_MAX
260
250static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 261static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
251static struct stats runtime_cycles_stats[MAX_NR_CPUS]; 262static struct stats runtime_cycles_stats[NUM_CTX][MAX_NR_CPUS];
252static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; 263static struct stats runtime_stalled_cycles_front_stats[NUM_CTX][MAX_NR_CPUS];
253static struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS]; 264static struct stats runtime_stalled_cycles_back_stats[NUM_CTX][MAX_NR_CPUS];
254static struct stats runtime_branches_stats[MAX_NR_CPUS]; 265static struct stats runtime_branches_stats[NUM_CTX][MAX_NR_CPUS];
255static struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; 266static struct stats runtime_cacherefs_stats[NUM_CTX][MAX_NR_CPUS];
256static struct stats runtime_l1_dcache_stats[MAX_NR_CPUS]; 267static struct stats runtime_l1_dcache_stats[NUM_CTX][MAX_NR_CPUS];
257static struct stats runtime_l1_icache_stats[MAX_NR_CPUS]; 268static struct stats runtime_l1_icache_stats[NUM_CTX][MAX_NR_CPUS];
258static struct stats runtime_ll_cache_stats[MAX_NR_CPUS]; 269static struct stats runtime_ll_cache_stats[NUM_CTX][MAX_NR_CPUS];
259static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; 270static struct stats runtime_itlb_cache_stats[NUM_CTX][MAX_NR_CPUS];
260static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 271static struct stats runtime_dtlb_cache_stats[NUM_CTX][MAX_NR_CPUS];
261static struct stats runtime_cycles_in_tx_stats[MAX_NR_CPUS]; 272static struct stats runtime_cycles_in_tx_stats[NUM_CTX][MAX_NR_CPUS];
262static struct stats walltime_nsecs_stats; 273static struct stats walltime_nsecs_stats;
263static struct stats runtime_transaction_stats[MAX_NR_CPUS]; 274static struct stats runtime_transaction_stats[NUM_CTX][MAX_NR_CPUS];
264static struct stats runtime_elision_stats[MAX_NR_CPUS]; 275static struct stats runtime_elision_stats[NUM_CTX][MAX_NR_CPUS];
276
277static int evsel_context(struct perf_evsel *evsel)
278{
279 int ctx = 0;
280
281 if (evsel->attr.exclude_kernel)
282 ctx |= CTX_BIT_KERNEL;
283 if (evsel->attr.exclude_user)
284 ctx |= CTX_BIT_USER;
285 if (evsel->attr.exclude_hv)
286 ctx |= CTX_BIT_HV;
287 if (evsel->attr.exclude_host)
288 ctx |= CTX_BIT_HOST;
289 if (evsel->attr.exclude_idle)
290 ctx |= CTX_BIT_IDLE;
291
292 return ctx;
293}
265 294
266static void perf_stat__reset_stats(struct perf_evlist *evlist) 295static void perf_stat__reset_stats(struct perf_evlist *evlist)
267{ 296{
@@ -356,37 +385,39 @@ static struct perf_evsel *nth_evsel(int n)
356static void update_shadow_stats(struct perf_evsel *counter, u64 *count, 385static void update_shadow_stats(struct perf_evsel *counter, u64 *count,
357 int cpu) 386 int cpu)
358{ 387{
388 int ctx = evsel_context(counter);
389
359 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) 390 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK))
360 update_stats(&runtime_nsecs_stats[cpu], count[0]); 391 update_stats(&runtime_nsecs_stats[cpu], count[0]);
361 else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) 392 else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
362 update_stats(&runtime_cycles_stats[cpu], count[0]); 393 update_stats(&runtime_cycles_stats[ctx][cpu], count[0]);
363 else if (transaction_run && 394 else if (transaction_run &&
364 perf_evsel__cmp(counter, nth_evsel(T_CYCLES_IN_TX))) 395 perf_evsel__cmp(counter, nth_evsel(T_CYCLES_IN_TX)))
365 update_stats(&runtime_cycles_in_tx_stats[cpu], count[0]); 396 update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
366 else if (transaction_run && 397 else if (transaction_run &&
367 perf_evsel__cmp(counter, nth_evsel(T_TRANSACTION_START))) 398 perf_evsel__cmp(counter, nth_evsel(T_TRANSACTION_START)))
368 update_stats(&runtime_transaction_stats[cpu], count[0]); 399 update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
369 else if (transaction_run && 400 else if (transaction_run &&
370 perf_evsel__cmp(counter, nth_evsel(T_ELISION_START))) 401 perf_evsel__cmp(counter, nth_evsel(T_ELISION_START)))
371 update_stats(&runtime_elision_stats[cpu], count[0]); 402 update_stats(&runtime_elision_stats[ctx][cpu], count[0]);
372 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) 403 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
373 update_stats(&runtime_stalled_cycles_front_stats[cpu], count[0]); 404 update_stats(&runtime_stalled_cycles_front_stats[ctx][cpu], count[0]);
374 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND)) 405 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
375 update_stats(&runtime_stalled_cycles_back_stats[cpu], count[0]); 406 update_stats(&runtime_stalled_cycles_back_stats[ctx][cpu], count[0]);
376 else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) 407 else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
377 update_stats(&runtime_branches_stats[cpu], count[0]); 408 update_stats(&runtime_branches_stats[ctx][cpu], count[0]);
378 else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES)) 409 else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES))
379 update_stats(&runtime_cacherefs_stats[cpu], count[0]); 410 update_stats(&runtime_cacherefs_stats[ctx][cpu], count[0]);
380 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1D)) 411 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1D))
381 update_stats(&runtime_l1_dcache_stats[cpu], count[0]); 412 update_stats(&runtime_l1_dcache_stats[ctx][cpu], count[0]);
382 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1I)) 413 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1I))
383 update_stats(&runtime_l1_icache_stats[cpu], count[0]); 414 update_stats(&runtime_ll_cache_stats[ctx][cpu], count[0]);
384 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_LL)) 415 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_LL))
385 update_stats(&runtime_ll_cache_stats[cpu], count[0]); 416 update_stats(&runtime_ll_cache_stats[ctx][cpu], count[0]);
386 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_DTLB)) 417 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_DTLB))
387 update_stats(&runtime_dtlb_cache_stats[cpu], count[0]); 418 update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]);
388 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) 419 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
389 update_stats(&runtime_itlb_cache_stats[cpu], count[0]); 420 update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]);
390} 421}
391 422
392static void zero_per_pkg(struct perf_evsel *counter) 423static void zero_per_pkg(struct perf_evsel *counter)
@@ -908,8 +939,9 @@ static void print_stalled_cycles_frontend(int cpu,
908{ 939{
909 double total, ratio = 0.0; 940 double total, ratio = 0.0;
910 const char *color; 941 const char *color;
942 int ctx = evsel_context(evsel);
911 943
912 total = avg_stats(&runtime_cycles_stats[cpu]); 944 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
913 945
914 if (total) 946 if (total)
915 ratio = avg / total * 100.0; 947 ratio = avg / total * 100.0;
@@ -927,8 +959,9 @@ static void print_stalled_cycles_backend(int cpu,
927{ 959{
928 double total, ratio = 0.0; 960 double total, ratio = 0.0;
929 const char *color; 961 const char *color;
962 int ctx = evsel_context(evsel);
930 963
931 total = avg_stats(&runtime_cycles_stats[cpu]); 964 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
932 965
933 if (total) 966 if (total)
934 ratio = avg / total * 100.0; 967 ratio = avg / total * 100.0;
@@ -946,8 +979,9 @@ static void print_branch_misses(int cpu,
946{ 979{
947 double total, ratio = 0.0; 980 double total, ratio = 0.0;
948 const char *color; 981 const char *color;
982 int ctx = evsel_context(evsel);
949 983
950 total = avg_stats(&runtime_branches_stats[cpu]); 984 total = avg_stats(&runtime_branches_stats[ctx][cpu]);
951 985
952 if (total) 986 if (total)
953 ratio = avg / total * 100.0; 987 ratio = avg / total * 100.0;
@@ -965,8 +999,9 @@ static void print_l1_dcache_misses(int cpu,
965{ 999{
966 double total, ratio = 0.0; 1000 double total, ratio = 0.0;
967 const char *color; 1001 const char *color;
1002 int ctx = evsel_context(evsel);
968 1003
969 total = avg_stats(&runtime_l1_dcache_stats[cpu]); 1004 total = avg_stats(&runtime_l1_dcache_stats[ctx][cpu]);
970 1005
971 if (total) 1006 if (total)
972 ratio = avg / total * 100.0; 1007 ratio = avg / total * 100.0;
@@ -984,8 +1019,9 @@ static void print_l1_icache_misses(int cpu,
984{ 1019{
985 double total, ratio = 0.0; 1020 double total, ratio = 0.0;
986 const char *color; 1021 const char *color;
1022 int ctx = evsel_context(evsel);
987 1023
988 total = avg_stats(&runtime_l1_icache_stats[cpu]); 1024 total = avg_stats(&runtime_l1_icache_stats[ctx][cpu]);
989 1025
990 if (total) 1026 if (total)
991 ratio = avg / total * 100.0; 1027 ratio = avg / total * 100.0;
@@ -1003,8 +1039,9 @@ static void print_dtlb_cache_misses(int cpu,
1003{ 1039{
1004 double total, ratio = 0.0; 1040 double total, ratio = 0.0;
1005 const char *color; 1041 const char *color;
1042 int ctx = evsel_context(evsel);
1006 1043
1007 total = avg_stats(&runtime_dtlb_cache_stats[cpu]); 1044 total = avg_stats(&runtime_dtlb_cache_stats[ctx][cpu]);
1008 1045
1009 if (total) 1046 if (total)
1010 ratio = avg / total * 100.0; 1047 ratio = avg / total * 100.0;
@@ -1022,8 +1059,9 @@ static void print_itlb_cache_misses(int cpu,
1022{ 1059{
1023 double total, ratio = 0.0; 1060 double total, ratio = 0.0;
1024 const char *color; 1061 const char *color;
1062 int ctx = evsel_context(evsel);
1025 1063
1026 total = avg_stats(&runtime_itlb_cache_stats[cpu]); 1064 total = avg_stats(&runtime_itlb_cache_stats[ctx][cpu]);
1027 1065
1028 if (total) 1066 if (total)
1029 ratio = avg / total * 100.0; 1067 ratio = avg / total * 100.0;
@@ -1041,8 +1079,9 @@ static void print_ll_cache_misses(int cpu,
1041{ 1079{
1042 double total, ratio = 0.0; 1080 double total, ratio = 0.0;
1043 const char *color; 1081 const char *color;
1082 int ctx = evsel_context(evsel);
1044 1083
1045 total = avg_stats(&runtime_ll_cache_stats[cpu]); 1084 total = avg_stats(&runtime_ll_cache_stats[ctx][cpu]);
1046 1085
1047 if (total) 1086 if (total)
1048 ratio = avg / total * 100.0; 1087 ratio = avg / total * 100.0;
@@ -1060,6 +1099,7 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
1060 double sc = evsel->scale; 1099 double sc = evsel->scale;
1061 const char *fmt; 1100 const char *fmt;
1062 int cpu = cpu_map__id_to_cpu(id); 1101 int cpu = cpu_map__id_to_cpu(id);
1102 int ctx = evsel_context(evsel);
1063 1103
1064 if (csv_output) { 1104 if (csv_output) {
1065 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; 1105 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s";
@@ -1091,15 +1131,15 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
1091 return; 1131 return;
1092 1132
1093 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { 1133 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
1094 total = avg_stats(&runtime_cycles_stats[cpu]); 1134 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
1095 if (total) { 1135 if (total) {
1096 ratio = avg / total; 1136 ratio = avg / total;
1097 fprintf(output, " # %5.2f insns per cycle ", ratio); 1137 fprintf(output, " # %5.2f insns per cycle ", ratio);
1098 } else { 1138 } else {
1099 fprintf(output, " "); 1139 fprintf(output, " ");
1100 } 1140 }
1101 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); 1141 total = avg_stats(&runtime_stalled_cycles_front_stats[ctx][cpu]);
1102 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); 1142 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[ctx][cpu]));
1103 1143
1104 if (total && avg) { 1144 if (total && avg) {
1105 ratio = total / avg; 1145 ratio = total / avg;
@@ -1110,46 +1150,46 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
1110 } 1150 }
1111 1151
1112 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 1152 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
1113 runtime_branches_stats[cpu].n != 0) { 1153 runtime_branches_stats[ctx][cpu].n != 0) {
1114 print_branch_misses(cpu, evsel, avg); 1154 print_branch_misses(cpu, evsel, avg);
1115 } else if ( 1155 } else if (
1116 evsel->attr.type == PERF_TYPE_HW_CACHE && 1156 evsel->attr.type == PERF_TYPE_HW_CACHE &&
1117 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D | 1157 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D |
1118 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 1158 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
1119 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 1159 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
1120 runtime_l1_dcache_stats[cpu].n != 0) { 1160 runtime_l1_dcache_stats[ctx][cpu].n != 0) {
1121 print_l1_dcache_misses(cpu, evsel, avg); 1161 print_l1_dcache_misses(cpu, evsel, avg);
1122 } else if ( 1162 } else if (
1123 evsel->attr.type == PERF_TYPE_HW_CACHE && 1163 evsel->attr.type == PERF_TYPE_HW_CACHE &&
1124 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I | 1164 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I |
1125 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 1165 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
1126 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 1166 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
1127 runtime_l1_icache_stats[cpu].n != 0) { 1167 runtime_l1_icache_stats[ctx][cpu].n != 0) {
1128 print_l1_icache_misses(cpu, evsel, avg); 1168 print_l1_icache_misses(cpu, evsel, avg);
1129 } else if ( 1169 } else if (
1130 evsel->attr.type == PERF_TYPE_HW_CACHE && 1170 evsel->attr.type == PERF_TYPE_HW_CACHE &&
1131 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB | 1171 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
1132 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 1172 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
1133 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 1173 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
1134 runtime_dtlb_cache_stats[cpu].n != 0) { 1174 runtime_dtlb_cache_stats[ctx][cpu].n != 0) {
1135 print_dtlb_cache_misses(cpu, evsel, avg); 1175 print_dtlb_cache_misses(cpu, evsel, avg);
1136 } else if ( 1176 } else if (
1137 evsel->attr.type == PERF_TYPE_HW_CACHE && 1177 evsel->attr.type == PERF_TYPE_HW_CACHE &&
1138 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB | 1178 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
1139 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 1179 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
1140 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 1180 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
1141 runtime_itlb_cache_stats[cpu].n != 0) { 1181 runtime_itlb_cache_stats[ctx][cpu].n != 0) {
1142 print_itlb_cache_misses(cpu, evsel, avg); 1182 print_itlb_cache_misses(cpu, evsel, avg);
1143 } else if ( 1183 } else if (
1144 evsel->attr.type == PERF_TYPE_HW_CACHE && 1184 evsel->attr.type == PERF_TYPE_HW_CACHE &&
1145 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL | 1185 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL |
1146 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 1186 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
1147 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 1187 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) &&
1148 runtime_ll_cache_stats[cpu].n != 0) { 1188 runtime_ll_cache_stats[ctx][cpu].n != 0) {
1149 print_ll_cache_misses(cpu, evsel, avg); 1189 print_ll_cache_misses(cpu, evsel, avg);
1150 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && 1190 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) &&
1151 runtime_cacherefs_stats[cpu].n != 0) { 1191 runtime_cacherefs_stats[ctx][cpu].n != 0) {
1152 total = avg_stats(&runtime_cacherefs_stats[cpu]); 1192 total = avg_stats(&runtime_cacherefs_stats[ctx][cpu]);
1153 1193
1154 if (total) 1194 if (total)
1155 ratio = avg * 100 / total; 1195 ratio = avg * 100 / total;
@@ -1171,15 +1211,15 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
1171 } 1211 }
1172 } else if (transaction_run && 1212 } else if (transaction_run &&
1173 perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX))) { 1213 perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX))) {
1174 total = avg_stats(&runtime_cycles_stats[cpu]); 1214 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
1175 if (total) 1215 if (total)
1176 fprintf(output, 1216 fprintf(output,
1177 " # %5.2f%% transactional cycles ", 1217 " # %5.2f%% transactional cycles ",
1178 100.0 * (avg / total)); 1218 100.0 * (avg / total));
1179 } else if (transaction_run && 1219 } else if (transaction_run &&
1180 perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX_CP))) { 1220 perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX_CP))) {
1181 total = avg_stats(&runtime_cycles_stats[cpu]); 1221 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
1182 total2 = avg_stats(&runtime_cycles_in_tx_stats[cpu]); 1222 total2 = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
1183 if (total2 < avg) 1223 if (total2 < avg)
1184 total2 = avg; 1224 total2 = avg;
1185 if (total) 1225 if (total)
@@ -1189,8 +1229,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
1189 } else if (transaction_run && 1229 } else if (transaction_run &&
1190 perf_evsel__cmp(evsel, nth_evsel(T_TRANSACTION_START)) && 1230 perf_evsel__cmp(evsel, nth_evsel(T_TRANSACTION_START)) &&
1191 avg > 0 && 1231 avg > 0 &&
1192 runtime_cycles_in_tx_stats[cpu].n != 0) { 1232 runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
1193 total = avg_stats(&runtime_cycles_in_tx_stats[cpu]); 1233 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
1194 1234
1195 if (total) 1235 if (total)
1196 ratio = total / avg; 1236 ratio = total / avg;
@@ -1199,8 +1239,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
1199 } else if (transaction_run && 1239 } else if (transaction_run &&
1200 perf_evsel__cmp(evsel, nth_evsel(T_ELISION_START)) && 1240 perf_evsel__cmp(evsel, nth_evsel(T_ELISION_START)) &&
1201 avg > 0 && 1241 avg > 0 &&
1202 runtime_cycles_in_tx_stats[cpu].n != 0) { 1242 runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
1203 total = avg_stats(&runtime_cycles_in_tx_stats[cpu]); 1243 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
1204 1244
1205 if (total) 1245 if (total)
1206 ratio = total / avg; 1246 ratio = total / avg;
@@ -1541,7 +1581,7 @@ static int setup_events(const char * const *attrs, unsigned len)
1541 unsigned i; 1581 unsigned i;
1542 1582
1543 for (i = 0; i < len; i++) { 1583 for (i = 0; i < len; i++) {
1544 if (parse_events(evsel_list, attrs[i])) 1584 if (parse_events(evsel_list, attrs[i], NULL))
1545 return -1; 1585 return -1;
1546 } 1586 }
1547 return 0; 1587 return 0;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index e124741be187..d1139b6bd534 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -2660,16 +2660,15 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2660 OPT_BOOLEAN(0, "comm", &trace.show_comm, 2660 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2661 "show the thread COMM next to its id"), 2661 "show the thread COMM next to its id"),
2662 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"), 2662 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
2663 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", 2663 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
2664 "list of events to trace"),
2665 OPT_STRING('o', "output", &output_name, "file", "output file name"), 2664 OPT_STRING('o', "output", &output_name, "file", "output file name"),
2666 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"), 2665 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
2667 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", 2666 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2668 "trace events on existing process id"), 2667 "trace events on existing process id"),
2669 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid", 2668 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
2670 "trace events on existing thread id"), 2669 "trace events on existing thread id"),
2671 OPT_CALLBACK(0, "filter-pids", &trace, "float", 2670 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2672 "show only events with duration > N.M ms", trace__set_filter_pids), 2671 "pids to filter (by the kernel)", trace__set_filter_pids),
2673 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide, 2672 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
2674 "system-wide collection from all CPUs"), 2673 "system-wide collection from all CPUs"),
2675 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu", 2674 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 59a98c643240..435b6ca85b1f 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -610,6 +610,11 @@ ifdef LIBBABELTRACE
610 endif 610 endif
611endif 611endif
612 612
613ifndef NO_AUXTRACE
614 $(call detected,CONFIG_AUXTRACE)
615 CFLAGS += -DHAVE_AUXTRACE_SUPPORT
616endif
617
613# Among the variables below, these: 618# Among the variables below, these:
614# perfexecdir 619# perfexecdir
615# template_dir 620# template_dir
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index e14bb637255c..aa79fb8a16d4 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -54,12 +54,17 @@ struct record_opts {
54 bool period; 54 bool period;
55 bool sample_intr_regs; 55 bool sample_intr_regs;
56 bool running_time; 56 bool running_time;
57 bool full_auxtrace;
58 bool auxtrace_snapshot_mode;
57 unsigned int freq; 59 unsigned int freq;
58 unsigned int mmap_pages; 60 unsigned int mmap_pages;
61 unsigned int auxtrace_mmap_pages;
59 unsigned int user_freq; 62 unsigned int user_freq;
60 u64 branch_stack; 63 u64 branch_stack;
61 u64 default_interval; 64 u64 default_interval;
62 u64 user_interval; 65 u64 user_interval;
66 size_t auxtrace_snapshot_size;
67 const char *auxtrace_snapshot_opts;
63 bool sample_transaction; 68 bool sample_transaction;
64 unsigned initial_delay; 69 unsigned initial_delay;
65 bool use_clockid; 70 bool use_clockid;
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index f671ec37a7c4..ca0e480e741b 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -482,7 +482,7 @@ static int do_test_code_reading(bool try_kcore)
482 else 482 else
483 str = "cycles"; 483 str = "cycles";
484 pr_debug("Parsing event '%s'\n", str); 484 pr_debug("Parsing event '%s'\n", str);
485 ret = parse_events(evlist, str); 485 ret = parse_events(evlist, str, NULL);
486 if (ret < 0) { 486 if (ret < 0) {
487 pr_debug("parse_events failed\n"); 487 pr_debug("parse_events failed\n");
488 goto out_err; 488 goto out_err;
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index b8d8341b383e..3fa715987a5e 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -23,7 +23,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
23 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 23 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
24 __perf_evsel__hw_cache_type_op_res_name(type, op, i, 24 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
25 name, sizeof(name)); 25 name, sizeof(name));
26 err = parse_events(evlist, name); 26 err = parse_events(evlist, name, NULL);
27 if (err) 27 if (err)
28 ret = err; 28 ret = err;
29 } 29 }
@@ -71,7 +71,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
71 return -ENOMEM; 71 return -ENOMEM;
72 72
73 for (i = 0; i < nr_names; ++i) { 73 for (i = 0; i < nr_names; ++i) {
74 err = parse_events(evlist, names[i]); 74 err = parse_events(evlist, names[i], NULL);
75 if (err) { 75 if (err) {
76 pr_debug("failed to parse event '%s', err %d\n", 76 pr_debug("failed to parse event '%s', err %d\n",
77 names[i], err); 77 names[i], err);
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 18619966454c..b08a95a5ca1a 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -695,7 +695,7 @@ int test__hists_cumulate(void)
695 695
696 TEST_ASSERT_VAL("No memory", evlist); 696 TEST_ASSERT_VAL("No memory", evlist);
697 697
698 err = parse_events(evlist, "cpu-clock"); 698 err = parse_events(evlist, "cpu-clock", NULL);
699 if (err) 699 if (err)
700 goto out; 700 goto out;
701 701
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 59e53db7914c..108488cd71fa 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -108,10 +108,10 @@ int test__hists_filter(void)
108 108
109 TEST_ASSERT_VAL("No memory", evlist); 109 TEST_ASSERT_VAL("No memory", evlist);
110 110
111 err = parse_events(evlist, "cpu-clock"); 111 err = parse_events(evlist, "cpu-clock", NULL);
112 if (err) 112 if (err)
113 goto out; 113 goto out;
114 err = parse_events(evlist, "task-clock"); 114 err = parse_events(evlist, "task-clock", NULL);
115 if (err) 115 if (err)
116 goto out; 116 goto out;
117 117
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 278ba8344c23..34c61e4d3352 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -282,10 +282,10 @@ int test__hists_link(void)
282 if (evlist == NULL) 282 if (evlist == NULL)
283 return -ENOMEM; 283 return -ENOMEM;
284 284
285 err = parse_events(evlist, "cpu-clock"); 285 err = parse_events(evlist, "cpu-clock", NULL);
286 if (err) 286 if (err)
287 goto out; 287 goto out;
288 err = parse_events(evlist, "task-clock"); 288 err = parse_events(evlist, "task-clock", NULL);
289 if (err) 289 if (err)
290 goto out; 290 goto out;
291 291
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index b52c9faea224..d8a23db80094 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -590,7 +590,7 @@ int test__hists_output(void)
590 590
591 TEST_ASSERT_VAL("No memory", evlist); 591 TEST_ASSERT_VAL("No memory", evlist);
592 592
593 err = parse_events(evlist, "cpu-clock"); 593 err = parse_events(evlist, "cpu-clock", NULL);
594 if (err) 594 if (err)
595 goto out; 595 goto out;
596 596
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 7a5ab7b0b8f6..5b171d1e338b 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -78,8 +78,8 @@ int test__keep_tracking(void)
78 78
79 perf_evlist__set_maps(evlist, cpus, threads); 79 perf_evlist__set_maps(evlist, cpus, threads);
80 80
81 CHECK__(parse_events(evlist, "dummy:u")); 81 CHECK__(parse_events(evlist, "dummy:u", NULL));
82 CHECK__(parse_events(evlist, "cycles:u")); 82 CHECK__(parse_events(evlist, "cycles:u", NULL));
83 83
84 perf_evlist__config(evlist, &opts); 84 perf_evlist__config(evlist, &opts);
85 85
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index bff85324f799..65280d28662e 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -32,6 +32,7 @@ make_no_backtrace := NO_BACKTRACE=1
32make_no_libnuma := NO_LIBNUMA=1 32make_no_libnuma := NO_LIBNUMA=1
33make_no_libaudit := NO_LIBAUDIT=1 33make_no_libaudit := NO_LIBAUDIT=1
34make_no_libbionic := NO_LIBBIONIC=1 34make_no_libbionic := NO_LIBBIONIC=1
35make_no_auxtrace := NO_AUXTRACE=1
35make_tags := tags 36make_tags := tags
36make_cscope := cscope 37make_cscope := cscope
37make_help := help 38make_help := help
@@ -52,7 +53,7 @@ make_static := LDFLAGS=-static
52make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 53make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
53make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 54make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
54make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 55make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
55make_minimal += NO_LIBDW_DWARF_UNWIND=1 56make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1
56 57
57# $(run) contains all available tests 58# $(run) contains all available tests
58run := make_pure 59run := make_pure
@@ -74,6 +75,7 @@ run += make_no_backtrace
74run += make_no_libnuma 75run += make_no_libnuma
75run += make_no_libaudit 76run += make_no_libaudit
76run += make_no_libbionic 77run += make_no_libbionic
78run += make_no_auxtrace
77run += make_help 79run += make_help
78run += make_doc 80run += make_doc
79run += make_perf_o 81run += make_perf_o
@@ -223,7 +225,19 @@ tarpkg:
223 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 225 echo "- $@: $$cmd" && echo $$cmd > $@ && \
224 ( eval $$cmd ) >> $@ 2>&1 226 ( eval $$cmd ) >> $@ 2>&1
225 227
226all: $(run) $(run_O) tarpkg 228make_kernelsrc:
229 @echo " - make -C <kernelsrc> tools/perf"
230 $(call clean); \
231 (make -C ../.. tools/perf) > $@ 2>&1 && \
232 test -x perf && rm -f $@ || (cat $@ ; false)
233
234make_kernelsrc_tools:
235 @echo " - make -C <kernelsrc>/tools perf"
236 $(call clean); \
237 (make -C ../../tools perf) > $@ 2>&1 && \
238 test -x perf && rm -f $@ || (cat $@ ; false)
239
240all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools
227 @echo OK 241 @echo OK
228 242
229out: $(run_O) 243out: $(run_O)
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 3de744961739..82d2a1636f7f 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1571,7 +1571,7 @@ static int test_event(struct evlist_test *e)
1571 if (evlist == NULL) 1571 if (evlist == NULL)
1572 return -ENOMEM; 1572 return -ENOMEM;
1573 1573
1574 ret = parse_events(evlist, e->name); 1574 ret = parse_events(evlist, e->name, NULL);
1575 if (ret) { 1575 if (ret) {
1576 pr_debug("failed to parse event '%s', err %d\n", 1576 pr_debug("failed to parse event '%s', err %d\n",
1577 e->name, ret); 1577 e->name, ret);
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index f238442b238a..5f49484f1abc 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -68,7 +68,7 @@ int test__perf_time_to_tsc(void)
68 68
69 perf_evlist__set_maps(evlist, cpus, threads); 69 perf_evlist__set_maps(evlist, cpus, threads);
70 70
71 CHECK__(parse_events(evlist, "cycles:u")); 71 CHECK__(parse_events(evlist, "cycles:u", NULL));
72 72
73 perf_evlist__config(evlist, &opts); 73 perf_evlist__config(evlist, &opts);
74 74
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index eeb68bb1972d..faa04e9d5d5f 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -152,7 +152,8 @@ int test__pmu(void)
152 if (ret) 152 if (ret)
153 break; 153 break;
154 154
155 ret = perf_pmu__config_terms(&formats, &attr, terms, false); 155 ret = perf_pmu__config_terms(&formats, &attr, terms,
156 false, NULL);
156 if (ret) 157 if (ret)
157 break; 158 break;
158 159
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index cc68648c7c55..0d31403ea593 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -347,7 +347,7 @@ int test__switch_tracking(void)
347 perf_evlist__set_maps(evlist, cpus, threads); 347 perf_evlist__set_maps(evlist, cpus, threads);
348 348
349 /* First event */ 349 /* First event */
350 err = parse_events(evlist, "cpu-clock:u"); 350 err = parse_events(evlist, "cpu-clock:u", NULL);
351 if (err) { 351 if (err) {
352 pr_debug("Failed to parse event dummy:u\n"); 352 pr_debug("Failed to parse event dummy:u\n");
353 goto out_err; 353 goto out_err;
@@ -356,7 +356,7 @@ int test__switch_tracking(void)
356 cpu_clocks_evsel = perf_evlist__last(evlist); 356 cpu_clocks_evsel = perf_evlist__last(evlist);
357 357
358 /* Second event */ 358 /* Second event */
359 err = parse_events(evlist, "cycles:u"); 359 err = parse_events(evlist, "cycles:u", NULL);
360 if (err) { 360 if (err) {
361 pr_debug("Failed to parse event cycles:u\n"); 361 pr_debug("Failed to parse event cycles:u\n");
362 goto out_err; 362 goto out_err;
@@ -371,7 +371,7 @@ int test__switch_tracking(void)
371 goto out; 371 goto out;
372 } 372 }
373 373
374 err = parse_events(evlist, sched_switch); 374 err = parse_events(evlist, sched_switch, NULL);
375 if (err) { 375 if (err) {
376 pr_debug("Failed to parse event %s\n", sched_switch); 376 pr_debug("Failed to parse event %s\n", sched_switch);
377 goto out_err; 377 goto out_err;
@@ -401,7 +401,7 @@ int test__switch_tracking(void)
401 perf_evsel__set_sample_bit(cycles_evsel, TIME); 401 perf_evsel__set_sample_bit(cycles_evsel, TIME);
402 402
403 /* Fourth event */ 403 /* Fourth event */
404 err = parse_events(evlist, "dummy:u"); 404 err = parse_events(evlist, "dummy:u", NULL);
405 if (err) { 405 if (err) {
406 pr_debug("Failed to parse event dummy:u\n"); 406 pr_debug("Failed to parse event dummy:u\n");
407 goto out_err; 407 goto out_err;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 995b7a8596b1..f981cb8f0158 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -25,6 +25,9 @@ struct hist_browser {
25 struct hists *hists; 25 struct hists *hists;
26 struct hist_entry *he_selection; 26 struct hist_entry *he_selection;
27 struct map_symbol *selection; 27 struct map_symbol *selection;
28 struct hist_browser_timer *hbt;
29 struct pstack *pstack;
30 struct perf_session_env *env;
28 int print_seq; 31 int print_seq;
29 bool show_dso; 32 bool show_dso;
30 bool show_headers; 33 bool show_headers;
@@ -60,7 +63,7 @@ static int hist_browser__get_folding(struct hist_browser *browser)
60 struct hist_entry *he = 63 struct hist_entry *he =
61 rb_entry(nd, struct hist_entry, rb_node); 64 rb_entry(nd, struct hist_entry, rb_node);
62 65
63 if (he->ms.unfolded) 66 if (he->unfolded)
64 unfolded_rows += he->nr_rows; 67 unfolded_rows += he->nr_rows;
65 } 68 }
66 return unfolded_rows; 69 return unfolded_rows;
@@ -136,24 +139,19 @@ static char tree__folded_sign(bool unfolded)
136 return unfolded ? '-' : '+'; 139 return unfolded ? '-' : '+';
137} 140}
138 141
139static char map_symbol__folded(const struct map_symbol *ms)
140{
141 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
142}
143
144static char hist_entry__folded(const struct hist_entry *he) 142static char hist_entry__folded(const struct hist_entry *he)
145{ 143{
146 return map_symbol__folded(&he->ms); 144 return he->has_children ? tree__folded_sign(he->unfolded) : ' ';
147} 145}
148 146
149static char callchain_list__folded(const struct callchain_list *cl) 147static char callchain_list__folded(const struct callchain_list *cl)
150{ 148{
151 return map_symbol__folded(&cl->ms); 149 return cl->has_children ? tree__folded_sign(cl->unfolded) : ' ';
152} 150}
153 151
154static void map_symbol__set_folding(struct map_symbol *ms, bool unfold) 152static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
155{ 153{
156 ms->unfolded = unfold ? ms->has_children : false; 154 cl->unfolded = unfold ? cl->has_children : false;
157} 155}
158 156
159static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 157static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
@@ -189,7 +187,7 @@ static int callchain_node__count_rows(struct callchain_node *node)
189 187
190 list_for_each_entry(chain, &node->val, list) { 188 list_for_each_entry(chain, &node->val, list) {
191 ++n; 189 ++n;
192 unfolded = chain->ms.unfolded; 190 unfolded = chain->unfolded;
193 } 191 }
194 192
195 if (unfolded) 193 if (unfolded)
@@ -211,15 +209,27 @@ static int callchain__count_rows(struct rb_root *chain)
211 return n; 209 return n;
212} 210}
213 211
214static bool map_symbol__toggle_fold(struct map_symbol *ms) 212static bool hist_entry__toggle_fold(struct hist_entry *he)
215{ 213{
216 if (!ms) 214 if (!he)
217 return false; 215 return false;
218 216
219 if (!ms->has_children) 217 if (!he->has_children)
220 return false; 218 return false;
221 219
222 ms->unfolded = !ms->unfolded; 220 he->unfolded = !he->unfolded;
221 return true;
222}
223
224static bool callchain_list__toggle_fold(struct callchain_list *cl)
225{
226 if (!cl)
227 return false;
228
229 if (!cl->has_children)
230 return false;
231
232 cl->unfolded = !cl->unfolded;
223 return true; 233 return true;
224} 234}
225 235
@@ -235,10 +245,10 @@ static void callchain_node__init_have_children_rb_tree(struct callchain_node *no
235 list_for_each_entry(chain, &child->val, list) { 245 list_for_each_entry(chain, &child->val, list) {
236 if (first) { 246 if (first) {
237 first = false; 247 first = false;
238 chain->ms.has_children = chain->list.next != &child->val || 248 chain->has_children = chain->list.next != &child->val ||
239 !RB_EMPTY_ROOT(&child->rb_root); 249 !RB_EMPTY_ROOT(&child->rb_root);
240 } else 250 } else
241 chain->ms.has_children = chain->list.next == &child->val && 251 chain->has_children = chain->list.next == &child->val &&
242 !RB_EMPTY_ROOT(&child->rb_root); 252 !RB_EMPTY_ROOT(&child->rb_root);
243 } 253 }
244 254
@@ -252,11 +262,11 @@ static void callchain_node__init_have_children(struct callchain_node *node,
252 struct callchain_list *chain; 262 struct callchain_list *chain;
253 263
254 chain = list_entry(node->val.next, struct callchain_list, list); 264 chain = list_entry(node->val.next, struct callchain_list, list);
255 chain->ms.has_children = has_sibling; 265 chain->has_children = has_sibling;
256 266
257 if (!list_empty(&node->val)) { 267 if (!list_empty(&node->val)) {
258 chain = list_entry(node->val.prev, struct callchain_list, list); 268 chain = list_entry(node->val.prev, struct callchain_list, list);
259 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); 269 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
260 } 270 }
261 271
262 callchain_node__init_have_children_rb_tree(node); 272 callchain_node__init_have_children_rb_tree(node);
@@ -276,7 +286,7 @@ static void callchain__init_have_children(struct rb_root *root)
276static void hist_entry__init_have_children(struct hist_entry *he) 286static void hist_entry__init_have_children(struct hist_entry *he)
277{ 287{
278 if (!he->init_have_children) { 288 if (!he->init_have_children) {
279 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 289 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
280 callchain__init_have_children(&he->sorted_chain); 290 callchain__init_have_children(&he->sorted_chain);
281 he->init_have_children = true; 291 he->init_have_children = true;
282 } 292 }
@@ -284,14 +294,22 @@ static void hist_entry__init_have_children(struct hist_entry *he)
284 294
285static bool hist_browser__toggle_fold(struct hist_browser *browser) 295static bool hist_browser__toggle_fold(struct hist_browser *browser)
286{ 296{
287 if (map_symbol__toggle_fold(browser->selection)) { 297 struct hist_entry *he = browser->he_selection;
288 struct hist_entry *he = browser->he_selection; 298 struct map_symbol *ms = browser->selection;
299 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
300 bool has_children;
289 301
302 if (ms == &he->ms)
303 has_children = hist_entry__toggle_fold(he);
304 else
305 has_children = callchain_list__toggle_fold(cl);
306
307 if (has_children) {
290 hist_entry__init_have_children(he); 308 hist_entry__init_have_children(he);
291 browser->b.nr_entries -= he->nr_rows; 309 browser->b.nr_entries -= he->nr_rows;
292 browser->nr_callchain_rows -= he->nr_rows; 310 browser->nr_callchain_rows -= he->nr_rows;
293 311
294 if (he->ms.unfolded) 312 if (he->unfolded)
295 he->nr_rows = callchain__count_rows(&he->sorted_chain); 313 he->nr_rows = callchain__count_rows(&he->sorted_chain);
296 else 314 else
297 he->nr_rows = 0; 315 he->nr_rows = 0;
@@ -318,8 +336,8 @@ static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool
318 336
319 list_for_each_entry(chain, &child->val, list) { 337 list_for_each_entry(chain, &child->val, list) {
320 ++n; 338 ++n;
321 map_symbol__set_folding(&chain->ms, unfold); 339 callchain_list__set_folding(chain, unfold);
322 has_children = chain->ms.has_children; 340 has_children = chain->has_children;
323 } 341 }
324 342
325 if (has_children) 343 if (has_children)
@@ -337,8 +355,8 @@ static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
337 355
338 list_for_each_entry(chain, &node->val, list) { 356 list_for_each_entry(chain, &node->val, list) {
339 ++n; 357 ++n;
340 map_symbol__set_folding(&chain->ms, unfold); 358 callchain_list__set_folding(chain, unfold);
341 has_children = chain->ms.has_children; 359 has_children = chain->has_children;
342 } 360 }
343 361
344 if (has_children) 362 if (has_children)
@@ -363,9 +381,9 @@ static int callchain__set_folding(struct rb_root *chain, bool unfold)
363static void hist_entry__set_folding(struct hist_entry *he, bool unfold) 381static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
364{ 382{
365 hist_entry__init_have_children(he); 383 hist_entry__init_have_children(he);
366 map_symbol__set_folding(&he->ms, unfold); 384 he->unfolded = unfold ? he->has_children : false;
367 385
368 if (he->ms.has_children) { 386 if (he->has_children) {
369 int n = callchain__set_folding(&he->sorted_chain, unfold); 387 int n = callchain__set_folding(&he->sorted_chain, unfold);
370 he->nr_rows = unfold ? n : 0; 388 he->nr_rows = unfold ? n : 0;
371 } else 389 } else
@@ -406,11 +424,11 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
406 "Or reduce the sampling frequency."); 424 "Or reduce the sampling frequency.");
407} 425}
408 426
409static int hist_browser__run(struct hist_browser *browser, 427static int hist_browser__run(struct hist_browser *browser)
410 struct hist_browser_timer *hbt)
411{ 428{
412 int key; 429 int key;
413 char title[160]; 430 char title[160];
431 struct hist_browser_timer *hbt = browser->hbt;
414 int delay_secs = hbt ? hbt->refresh : 0; 432 int delay_secs = hbt ? hbt->refresh : 0;
415 433
416 browser->b.entries = &browser->hists->entries; 434 browser->b.entries = &browser->hists->entries;
@@ -1016,7 +1034,7 @@ do_offset:
1016 if (offset > 0) { 1034 if (offset > 0) {
1017 do { 1035 do {
1018 h = rb_entry(nd, struct hist_entry, rb_node); 1036 h = rb_entry(nd, struct hist_entry, rb_node);
1019 if (h->ms.unfolded) { 1037 if (h->unfolded) {
1020 u16 remaining = h->nr_rows - h->row_offset; 1038 u16 remaining = h->nr_rows - h->row_offset;
1021 if (offset > remaining) { 1039 if (offset > remaining) {
1022 offset -= remaining; 1040 offset -= remaining;
@@ -1037,7 +1055,7 @@ do_offset:
1037 } else if (offset < 0) { 1055 } else if (offset < 0) {
1038 while (1) { 1056 while (1) {
1039 h = rb_entry(nd, struct hist_entry, rb_node); 1057 h = rb_entry(nd, struct hist_entry, rb_node);
1040 if (h->ms.unfolded) { 1058 if (h->unfolded) {
1041 if (first) { 1059 if (first) {
1042 if (-offset > h->row_offset) { 1060 if (-offset > h->row_offset) {
1043 offset += h->row_offset; 1061 offset += h->row_offset;
@@ -1074,7 +1092,7 @@ do_offset:
1074 * row_offset at its last entry. 1092 * row_offset at its last entry.
1075 */ 1093 */
1076 h = rb_entry(nd, struct hist_entry, rb_node); 1094 h = rb_entry(nd, struct hist_entry, rb_node);
1077 if (h->ms.unfolded) 1095 if (h->unfolded)
1078 h->row_offset = h->nr_rows; 1096 h->row_offset = h->nr_rows;
1079 break; 1097 break;
1080 } 1098 }
@@ -1195,7 +1213,9 @@ static int hist_browser__dump(struct hist_browser *browser)
1195 return 0; 1213 return 0;
1196} 1214}
1197 1215
1198static struct hist_browser *hist_browser__new(struct hists *hists) 1216static struct hist_browser *hist_browser__new(struct hists *hists,
1217 struct hist_browser_timer *hbt,
1218 struct perf_session_env *env)
1199{ 1219{
1200 struct hist_browser *browser = zalloc(sizeof(*browser)); 1220 struct hist_browser *browser = zalloc(sizeof(*browser));
1201 1221
@@ -1206,6 +1226,8 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
1206 browser->b.seek = ui_browser__hists_seek; 1226 browser->b.seek = ui_browser__hists_seek;
1207 browser->b.use_navkeypressed = true; 1227 browser->b.use_navkeypressed = true;
1208 browser->show_headers = symbol_conf.show_hist_headers; 1228 browser->show_headers = symbol_conf.show_hist_headers;
1229 browser->hbt = hbt;
1230 browser->env = env;
1209 } 1231 }
1210 1232
1211 return browser; 1233 return browser;
@@ -1395,6 +1417,257 @@ close_file_and_continue:
1395 return ret; 1417 return ret;
1396} 1418}
1397 1419
1420struct popup_action {
1421 struct thread *thread;
1422 struct dso *dso;
1423 struct map_symbol ms;
1424
1425 int (*fn)(struct hist_browser *browser, struct popup_action *act);
1426};
1427
1428static int
1429do_annotate(struct hist_browser *browser, struct popup_action *act)
1430{
1431 struct perf_evsel *evsel;
1432 struct annotation *notes;
1433 struct hist_entry *he;
1434 int err;
1435
1436 if (!objdump_path && perf_session_env__lookup_objdump(browser->env))
1437 return 0;
1438
1439 notes = symbol__annotation(act->ms.sym);
1440 if (!notes->src)
1441 return 0;
1442
1443 evsel = hists_to_evsel(browser->hists);
1444 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
1445 he = hist_browser__selected_entry(browser);
1446 /*
1447 * offer option to annotate the other branch source or target
1448 * (if they exists) when returning from annotate
1449 */
1450 if ((err == 'q' || err == CTRL('c')) && he->branch_info)
1451 return 1;
1452
1453 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1454 if (err)
1455 ui_browser__handle_resize(&browser->b);
1456 return 0;
1457}
1458
1459static int
1460add_annotate_opt(struct hist_browser *browser __maybe_unused,
1461 struct popup_action *act, char **optstr,
1462 struct map *map, struct symbol *sym)
1463{
1464 if (sym == NULL || map->dso->annotate_warned)
1465 return 0;
1466
1467 if (asprintf(optstr, "Annotate %s", sym->name) < 0)
1468 return 0;
1469
1470 act->ms.map = map;
1471 act->ms.sym = sym;
1472 act->fn = do_annotate;
1473 return 1;
1474}
1475
1476static int
1477do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1478{
1479 struct thread *thread = act->thread;
1480
1481 if (browser->hists->thread_filter) {
1482 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1483 perf_hpp__set_elide(HISTC_THREAD, false);
1484 thread__zput(browser->hists->thread_filter);
1485 ui_helpline__pop();
1486 } else {
1487 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1488 thread->comm_set ? thread__comm_str(thread) : "",
1489 thread->tid);
1490 browser->hists->thread_filter = thread__get(thread);
1491 perf_hpp__set_elide(HISTC_THREAD, false);
1492 pstack__push(browser->pstack, &browser->hists->thread_filter);
1493 }
1494
1495 hists__filter_by_thread(browser->hists);
1496 hist_browser__reset(browser);
1497 return 0;
1498}
1499
1500static int
1501add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1502 char **optstr, struct thread *thread)
1503{
1504 if (thread == NULL)
1505 return 0;
1506
1507 if (asprintf(optstr, "Zoom %s %s(%d) thread",
1508 browser->hists->thread_filter ? "out of" : "into",
1509 thread->comm_set ? thread__comm_str(thread) : "",
1510 thread->tid) < 0)
1511 return 0;
1512
1513 act->thread = thread;
1514 act->fn = do_zoom_thread;
1515 return 1;
1516}
1517
1518static int
1519do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1520{
1521 struct dso *dso = act->dso;
1522
1523 if (browser->hists->dso_filter) {
1524 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1525 perf_hpp__set_elide(HISTC_DSO, false);
1526 browser->hists->dso_filter = NULL;
1527 ui_helpline__pop();
1528 } else {
1529 if (dso == NULL)
1530 return 0;
1531 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1532 dso->kernel ? "the Kernel" : dso->short_name);
1533 browser->hists->dso_filter = dso;
1534 perf_hpp__set_elide(HISTC_DSO, true);
1535 pstack__push(browser->pstack, &browser->hists->dso_filter);
1536 }
1537
1538 hists__filter_by_dso(browser->hists);
1539 hist_browser__reset(browser);
1540 return 0;
1541}
1542
1543static int
1544add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1545 char **optstr, struct dso *dso)
1546{
1547 if (dso == NULL)
1548 return 0;
1549
1550 if (asprintf(optstr, "Zoom %s %s DSO",
1551 browser->hists->dso_filter ? "out of" : "into",
1552 dso->kernel ? "the Kernel" : dso->short_name) < 0)
1553 return 0;
1554
1555 act->dso = dso;
1556 act->fn = do_zoom_dso;
1557 return 1;
1558}
1559
1560static int
1561do_browse_map(struct hist_browser *browser __maybe_unused,
1562 struct popup_action *act)
1563{
1564 map__browse(act->ms.map);
1565 return 0;
1566}
1567
1568static int
1569add_map_opt(struct hist_browser *browser __maybe_unused,
1570 struct popup_action *act, char **optstr, struct map *map)
1571{
1572 if (map == NULL)
1573 return 0;
1574
1575 if (asprintf(optstr, "Browse map details") < 0)
1576 return 0;
1577
1578 act->ms.map = map;
1579 act->fn = do_browse_map;
1580 return 1;
1581}
1582
1583static int
1584do_run_script(struct hist_browser *browser __maybe_unused,
1585 struct popup_action *act)
1586{
1587 char script_opt[64];
1588 memset(script_opt, 0, sizeof(script_opt));
1589
1590 if (act->thread) {
1591 scnprintf(script_opt, sizeof(script_opt), " -c %s ",
1592 thread__comm_str(act->thread));
1593 } else if (act->ms.sym) {
1594 scnprintf(script_opt, sizeof(script_opt), " -S %s ",
1595 act->ms.sym->name);
1596 }
1597
1598 script_browse(script_opt);
1599 return 0;
1600}
1601
1602static int
1603add_script_opt(struct hist_browser *browser __maybe_unused,
1604 struct popup_action *act, char **optstr,
1605 struct thread *thread, struct symbol *sym)
1606{
1607 if (thread) {
1608 if (asprintf(optstr, "Run scripts for samples of thread [%s]",
1609 thread__comm_str(thread)) < 0)
1610 return 0;
1611 } else if (sym) {
1612 if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
1613 sym->name) < 0)
1614 return 0;
1615 } else {
1616 if (asprintf(optstr, "Run scripts for all samples") < 0)
1617 return 0;
1618 }
1619
1620 act->thread = thread;
1621 act->ms.sym = sym;
1622 act->fn = do_run_script;
1623 return 1;
1624}
1625
1626static int
1627do_switch_data(struct hist_browser *browser __maybe_unused,
1628 struct popup_action *act __maybe_unused)
1629{
1630 if (switch_data_file()) {
1631 ui__warning("Won't switch the data files due to\n"
1632 "no valid data file get selected!\n");
1633 return 0;
1634 }
1635
1636 return K_SWITCH_INPUT_DATA;
1637}
1638
1639static int
1640add_switch_opt(struct hist_browser *browser,
1641 struct popup_action *act, char **optstr)
1642{
1643 if (!is_report_browser(browser->hbt))
1644 return 0;
1645
1646 if (asprintf(optstr, "Switch to another data file in PWD") < 0)
1647 return 0;
1648
1649 act->fn = do_switch_data;
1650 return 1;
1651}
1652
1653static int
1654do_exit_browser(struct hist_browser *browser __maybe_unused,
1655 struct popup_action *act __maybe_unused)
1656{
1657 return 0;
1658}
1659
1660static int
1661add_exit_opt(struct hist_browser *browser __maybe_unused,
1662 struct popup_action *act, char **optstr)
1663{
1664 if (asprintf(optstr, "Exit") < 0)
1665 return 0;
1666
1667 act->fn = do_exit_browser;
1668 return 1;
1669}
1670
1398static void hist_browser__update_nr_entries(struct hist_browser *hb) 1671static void hist_browser__update_nr_entries(struct hist_browser *hb)
1399{ 1672{
1400 u64 nr_entries = 0; 1673 u64 nr_entries = 0;
@@ -1421,14 +1694,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1421 struct perf_session_env *env) 1694 struct perf_session_env *env)
1422{ 1695{
1423 struct hists *hists = evsel__hists(evsel); 1696 struct hists *hists = evsel__hists(evsel);
1424 struct hist_browser *browser = hist_browser__new(hists); 1697 struct hist_browser *browser = hist_browser__new(hists, hbt, env);
1425 struct branch_info *bi; 1698 struct branch_info *bi;
1426 struct pstack *fstack; 1699#define MAX_OPTIONS 16
1427 char *options[16]; 1700 char *options[MAX_OPTIONS];
1701 struct popup_action actions[MAX_OPTIONS];
1428 int nr_options = 0; 1702 int nr_options = 0;
1429 int key = -1; 1703 int key = -1;
1430 char buf[64]; 1704 char buf[64];
1431 char script_opt[64];
1432 int delay_secs = hbt ? hbt->refresh : 0; 1705 int delay_secs = hbt ? hbt->refresh : 0;
1433 struct perf_hpp_fmt *fmt; 1706 struct perf_hpp_fmt *fmt;
1434 1707
@@ -1473,13 +1746,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1473 hist_browser__update_nr_entries(browser); 1746 hist_browser__update_nr_entries(browser);
1474 } 1747 }
1475 1748
1476 fstack = pstack__new(2); 1749 browser->pstack = pstack__new(2);
1477 if (fstack == NULL) 1750 if (browser->pstack == NULL)
1478 goto out; 1751 goto out;
1479 1752
1480 ui_helpline__push(helpline); 1753 ui_helpline__push(helpline);
1481 1754
1482 memset(options, 0, sizeof(options)); 1755 memset(options, 0, sizeof(options));
1756 memset(actions, 0, sizeof(actions));
1483 1757
1484 perf_hpp__for_each_format(fmt) 1758 perf_hpp__for_each_format(fmt)
1485 perf_hpp__reset_width(fmt, hists); 1759 perf_hpp__reset_width(fmt, hists);
@@ -1489,16 +1763,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1489 1763
1490 while (1) { 1764 while (1) {
1491 struct thread *thread = NULL; 1765 struct thread *thread = NULL;
1492 const struct dso *dso = NULL; 1766 struct dso *dso = NULL;
1493 int choice = 0, 1767 int choice = 0;
1494 annotate = -2, zoom_dso = -2, zoom_thread = -2,
1495 annotate_f = -2, annotate_t = -2, browse_map = -2;
1496 int scripts_comm = -2, scripts_symbol = -2,
1497 scripts_all = -2, switch_data = -2;
1498 1768
1499 nr_options = 0; 1769 nr_options = 0;
1500 1770
1501 key = hist_browser__run(browser, hbt); 1771 key = hist_browser__run(browser);
1502 1772
1503 if (browser->he_selection != NULL) { 1773 if (browser->he_selection != NULL) {
1504 thread = hist_browser__selected_thread(browser); 1774 thread = hist_browser__selected_thread(browser);
@@ -1526,17 +1796,25 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1526 browser->selection->sym == NULL || 1796 browser->selection->sym == NULL ||
1527 browser->selection->map->dso->annotate_warned) 1797 browser->selection->map->dso->annotate_warned)
1528 continue; 1798 continue;
1529 goto do_annotate; 1799
1800 actions->ms.map = browser->selection->map;
1801 actions->ms.sym = browser->selection->sym;
1802 do_annotate(browser, actions);
1803 continue;
1530 case 'P': 1804 case 'P':
1531 hist_browser__dump(browser); 1805 hist_browser__dump(browser);
1532 continue; 1806 continue;
1533 case 'd': 1807 case 'd':
1534 goto zoom_dso; 1808 actions->dso = dso;
1809 do_zoom_dso(browser, actions);
1810 continue;
1535 case 'V': 1811 case 'V':
1536 browser->show_dso = !browser->show_dso; 1812 browser->show_dso = !browser->show_dso;
1537 continue; 1813 continue;
1538 case 't': 1814 case 't':
1539 goto zoom_thread; 1815 actions->thread = thread;
1816 do_zoom_thread(browser, actions);
1817 continue;
1540 case '/': 1818 case '/':
1541 if (ui_browser__input_window("Symbol to show", 1819 if (ui_browser__input_window("Symbol to show",
1542 "Please enter the name of symbol you want to see", 1820 "Please enter the name of symbol you want to see",
@@ -1548,12 +1826,18 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1548 } 1826 }
1549 continue; 1827 continue;
1550 case 'r': 1828 case 'r':
1551 if (is_report_browser(hbt)) 1829 if (is_report_browser(hbt)) {
1552 goto do_scripts; 1830 actions->thread = NULL;
1831 actions->ms.sym = NULL;
1832 do_run_script(browser, actions);
1833 }
1553 continue; 1834 continue;
1554 case 's': 1835 case 's':
1555 if (is_report_browser(hbt)) 1836 if (is_report_browser(hbt)) {
1556 goto do_data_switch; 1837 key = do_switch_data(browser, actions);
1838 if (key == K_SWITCH_INPUT_DATA)
1839 goto out_free_stack;
1840 }
1557 continue; 1841 continue;
1558 case 'i': 1842 case 'i':
1559 /* env->arch is NULL for live-mode (i.e. perf top) */ 1843 /* env->arch is NULL for live-mode (i.e. perf top) */
@@ -1583,7 +1867,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1583 case K_LEFT: { 1867 case K_LEFT: {
1584 const void *top; 1868 const void *top;
1585 1869
1586 if (pstack__empty(fstack)) { 1870 if (pstack__empty(browser->pstack)) {
1587 /* 1871 /*
1588 * Go back to the perf_evsel_menu__run or other user 1872 * Go back to the perf_evsel_menu__run or other user
1589 */ 1873 */
@@ -1591,11 +1875,17 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1591 goto out_free_stack; 1875 goto out_free_stack;
1592 continue; 1876 continue;
1593 } 1877 }
1594 top = pstack__pop(fstack); 1878 top = pstack__peek(browser->pstack);
1595 if (top == &browser->hists->dso_filter) 1879 if (top == &browser->hists->dso_filter) {
1596 goto zoom_out_dso; 1880 /*
1881 * No need to set actions->dso here since
1882 * it's just to remove the current filter.
1883 * Ditto for thread below.
1884 */
1885 do_zoom_dso(browser, actions);
1886 }
1597 if (top == &browser->hists->thread_filter) 1887 if (top == &browser->hists->thread_filter)
1598 goto zoom_out_thread; 1888 do_zoom_thread(browser, actions);
1599 continue; 1889 continue;
1600 } 1890 }
1601 case K_ESC: 1891 case K_ESC:
@@ -1623,196 +1913,71 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1623 if (bi == NULL) 1913 if (bi == NULL)
1624 goto skip_annotation; 1914 goto skip_annotation;
1625 1915
1626 if (bi->from.sym != NULL && 1916 nr_options += add_annotate_opt(browser,
1627 !bi->from.map->dso->annotate_warned && 1917 &actions[nr_options],
1628 asprintf(&options[nr_options], "Annotate %s", bi->from.sym->name) > 0) { 1918 &options[nr_options],
1629 annotate_f = nr_options++; 1919 bi->from.map,
1630 } 1920 bi->from.sym);
1631 1921 if (bi->to.sym != bi->from.sym)
1632 if (bi->to.sym != NULL && 1922 nr_options += add_annotate_opt(browser,
1633 !bi->to.map->dso->annotate_warned && 1923 &actions[nr_options],
1634 (bi->to.sym != bi->from.sym || 1924 &options[nr_options],
1635 bi->to.map->dso != bi->from.map->dso) && 1925 bi->to.map,
1636 asprintf(&options[nr_options], "Annotate %s", bi->to.sym->name) > 0) { 1926 bi->to.sym);
1637 annotate_t = nr_options++;
1638 }
1639 } else { 1927 } else {
1640 if (browser->selection->sym != NULL && 1928 nr_options += add_annotate_opt(browser,
1641 !browser->selection->map->dso->annotate_warned) { 1929 &actions[nr_options],
1642 struct annotation *notes; 1930 &options[nr_options],
1643 1931 browser->selection->map,
1644 notes = symbol__annotation(browser->selection->sym); 1932 browser->selection->sym);
1645
1646 if (notes->src &&
1647 asprintf(&options[nr_options], "Annotate %s",
1648 browser->selection->sym->name) > 0) {
1649 annotate = nr_options++;
1650 }
1651 }
1652 } 1933 }
1653skip_annotation: 1934skip_annotation:
1654 if (thread != NULL && 1935 nr_options += add_thread_opt(browser, &actions[nr_options],
1655 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1936 &options[nr_options], thread);
1656 (browser->hists->thread_filter ? "out of" : "into"), 1937 nr_options += add_dso_opt(browser, &actions[nr_options],
1657 (thread->comm_set ? thread__comm_str(thread) : ""), 1938 &options[nr_options], dso);
1658 thread->tid) > 0) 1939 nr_options += add_map_opt(browser, &actions[nr_options],
1659 zoom_thread = nr_options++; 1940 &options[nr_options],
1660 1941 browser->selection->map);
1661 if (dso != NULL &&
1662 asprintf(&options[nr_options], "Zoom %s %s DSO",
1663 (browser->hists->dso_filter ? "out of" : "into"),
1664 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1665 zoom_dso = nr_options++;
1666
1667 if (browser->selection != NULL &&
1668 browser->selection->map != NULL &&
1669 asprintf(&options[nr_options], "Browse map details") > 0)
1670 browse_map = nr_options++;
1671 1942
1672 /* perf script support */ 1943 /* perf script support */
1673 if (browser->he_selection) { 1944 if (browser->he_selection) {
1674 struct symbol *sym; 1945 nr_options += add_script_opt(browser,
1675 1946 &actions[nr_options],
1676 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", 1947 &options[nr_options],
1677 thread__comm_str(browser->he_selection->thread)) > 0) 1948 thread, NULL);
1678 scripts_comm = nr_options++; 1949 nr_options += add_script_opt(browser,
1679 1950 &actions[nr_options],
1680 sym = browser->he_selection->ms.sym; 1951 &options[nr_options],
1681 if (sym && sym->namelen && 1952 NULL, browser->selection->sym);
1682 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1683 sym->name) > 0)
1684 scripts_symbol = nr_options++;
1685 } 1953 }
1686 1954 nr_options += add_script_opt(browser, &actions[nr_options],
1687 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) 1955 &options[nr_options], NULL, NULL);
1688 scripts_all = nr_options++; 1956 nr_options += add_switch_opt(browser, &actions[nr_options],
1689 1957 &options[nr_options]);
1690 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1691 "Switch to another data file in PWD") > 0)
1692 switch_data = nr_options++;
1693add_exit_option: 1958add_exit_option:
1694 options[nr_options++] = (char *)"Exit"; 1959 nr_options += add_exit_opt(browser, &actions[nr_options],
1695retry_popup_menu: 1960 &options[nr_options]);
1696 choice = ui__popup_menu(nr_options, options);
1697
1698 if (choice == nr_options - 1)
1699 break;
1700 1961
1701 if (choice == -1) { 1962 do {
1702 free_popup_options(options, nr_options - 1); 1963 struct popup_action *act;
1703 continue;
1704 }
1705
1706 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
1707 struct hist_entry *he;
1708 struct annotation *notes;
1709 struct map_symbol ms;
1710 int err;
1711do_annotate:
1712 if (!objdump_path && perf_session_env__lookup_objdump(env))
1713 continue;
1714
1715 he = hist_browser__selected_entry(browser);
1716 if (he == NULL)
1717 continue;
1718
1719 if (choice == annotate_f) {
1720 ms.map = he->branch_info->from.map;
1721 ms.sym = he->branch_info->from.sym;
1722 } else if (choice == annotate_t) {
1723 ms.map = he->branch_info->to.map;
1724 ms.sym = he->branch_info->to.sym;
1725 } else {
1726 ms = *browser->selection;
1727 }
1728
1729 notes = symbol__annotation(ms.sym);
1730 if (!notes->src)
1731 continue;
1732
1733 err = map_symbol__tui_annotate(&ms, evsel, hbt);
1734 /*
1735 * offer option to annotate the other branch source or target
1736 * (if they exists) when returning from annotate
1737 */
1738 if ((err == 'q' || err == CTRL('c'))
1739 && annotate_t != -2 && annotate_f != -2)
1740 goto retry_popup_menu;
1741
1742 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1743 if (err)
1744 ui_browser__handle_resize(&browser->b);
1745
1746 } else if (choice == browse_map)
1747 map__browse(browser->selection->map);
1748 else if (choice == zoom_dso) {
1749zoom_dso:
1750 if (browser->hists->dso_filter) {
1751 pstack__remove(fstack, &browser->hists->dso_filter);
1752zoom_out_dso:
1753 ui_helpline__pop();
1754 browser->hists->dso_filter = NULL;
1755 perf_hpp__set_elide(HISTC_DSO, false);
1756 } else {
1757 if (dso == NULL)
1758 continue;
1759 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1760 dso->kernel ? "the Kernel" : dso->short_name);
1761 browser->hists->dso_filter = dso;
1762 perf_hpp__set_elide(HISTC_DSO, true);
1763 pstack__push(fstack, &browser->hists->dso_filter);
1764 }
1765 hists__filter_by_dso(hists);
1766 hist_browser__reset(browser);
1767 } else if (choice == zoom_thread) {
1768zoom_thread:
1769 if (browser->hists->thread_filter) {
1770 pstack__remove(fstack, &browser->hists->thread_filter);
1771zoom_out_thread:
1772 ui_helpline__pop();
1773 thread__zput(browser->hists->thread_filter);
1774 perf_hpp__set_elide(HISTC_THREAD, false);
1775 } else {
1776 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1777 thread->comm_set ? thread__comm_str(thread) : "",
1778 thread->tid);
1779 browser->hists->thread_filter = thread__get(thread);
1780 perf_hpp__set_elide(HISTC_THREAD, false);
1781 pstack__push(fstack, &browser->hists->thread_filter);
1782 }
1783 hists__filter_by_thread(hists);
1784 hist_browser__reset(browser);
1785 }
1786 /* perf scripts support */
1787 else if (choice == scripts_all || choice == scripts_comm ||
1788 choice == scripts_symbol) {
1789do_scripts:
1790 memset(script_opt, 0, 64);
1791 1964
1792 if (choice == scripts_comm) 1965 choice = ui__popup_menu(nr_options, options);
1793 sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread)); 1966 if (choice == -1 || choice >= nr_options)
1967 break;
1794 1968
1795 if (choice == scripts_symbol) 1969 act = &actions[choice];
1796 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); 1970 key = act->fn(browser, act);
1971 } while (key == 1);
1797 1972
1798 script_browse(script_opt); 1973 if (key == K_SWITCH_INPUT_DATA)
1799 } 1974 break;
1800 /* Switch to another data file */
1801 else if (choice == switch_data) {
1802do_data_switch:
1803 if (!switch_data_file()) {
1804 key = K_SWITCH_INPUT_DATA;
1805 break;
1806 } else
1807 ui__warning("Won't switch the data files due to\n"
1808 "no valid data file get selected!\n");
1809 }
1810 } 1975 }
1811out_free_stack: 1976out_free_stack:
1812 pstack__delete(fstack); 1977 pstack__delete(browser->pstack);
1813out: 1978out:
1814 hist_browser__delete(browser); 1979 hist_browser__delete(browser);
1815 free_popup_options(options, nr_options - 1); 1980 free_popup_options(options, MAX_OPTIONS);
1816 return key; 1981 return key;
1817} 1982}
1818 1983
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 797490a40075..d552203aead0 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -74,6 +74,7 @@ libperf-y += data.o
74libperf-$(CONFIG_X86) += tsc.o 74libperf-$(CONFIG_X86) += tsc.o
75libperf-y += cloexec.o 75libperf-y += cloexec.o
76libperf-y += thread-stack.o 76libperf-y += thread-stack.o
77libperf-$(CONFIG_AUXTRACE) += auxtrace.o
77 78
78libperf-$(CONFIG_LIBELF) += symbol-elf.o 79libperf-$(CONFIG_LIBELF) += symbol-elf.o
79libperf-$(CONFIG_LIBELF) += probe-event.o 80libperf-$(CONFIG_LIBELF) += probe-event.o
@@ -117,7 +118,7 @@ $(OUTPUT)util/pmu-bison.c: util/pmu.y
117 118
118CFLAGS_parse-events-flex.o += -w 119CFLAGS_parse-events-flex.o += -w
119CFLAGS_pmu-flex.o += -w 120CFLAGS_pmu-flex.o += -w
120CFLAGS_parse-events-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w 121CFLAGS_parse-events-bison.o += -DYYENABLE_NLS=0 -w
121CFLAGS_pmu-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w 122CFLAGS_pmu-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
122 123
123$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c 124$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
new file mode 100644
index 000000000000..df66966cfde7
--- /dev/null
+++ b/tools/perf/util/auxtrace.c
@@ -0,0 +1,1352 @@
1/*
2 * auxtrace.c: AUX area trace support
3 * Copyright (c) 2013-2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <sys/types.h>
17#include <sys/mman.h>
18#include <stdbool.h>
19
20#include <linux/kernel.h>
21#include <linux/perf_event.h>
22#include <linux/types.h>
23#include <linux/bitops.h>
24#include <linux/log2.h>
25#include <linux/string.h>
26
27#include <sys/param.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31#include <limits.h>
32#include <errno.h>
33#include <linux/list.h>
34
35#include "../perf.h"
36#include "util.h"
37#include "evlist.h"
38#include "cpumap.h"
39#include "thread_map.h"
40#include "asm/bug.h"
41#include "auxtrace.h"
42
43#include <linux/hash.h>
44
45#include "event.h"
46#include "session.h"
47#include "debug.h"
48#include "parse-options.h"
49
50int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
51 struct auxtrace_mmap_params *mp,
52 void *userpg, int fd)
53{
54 struct perf_event_mmap_page *pc = userpg;
55
56#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
57 pr_err("Cannot use AUX area tracing mmaps\n");
58 return -1;
59#endif
60
61 WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n");
62
63 mm->userpg = userpg;
64 mm->mask = mp->mask;
65 mm->len = mp->len;
66 mm->prev = 0;
67 mm->idx = mp->idx;
68 mm->tid = mp->tid;
69 mm->cpu = mp->cpu;
70
71 if (!mp->len) {
72 mm->base = NULL;
73 return 0;
74 }
75
76 pc->aux_offset = mp->offset;
77 pc->aux_size = mp->len;
78
79 mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset);
80 if (mm->base == MAP_FAILED) {
81 pr_debug2("failed to mmap AUX area\n");
82 mm->base = NULL;
83 return -1;
84 }
85
86 return 0;
87}
88
89void auxtrace_mmap__munmap(struct auxtrace_mmap *mm)
90{
91 if (mm->base) {
92 munmap(mm->base, mm->len);
93 mm->base = NULL;
94 }
95}
96
97void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
98 off_t auxtrace_offset,
99 unsigned int auxtrace_pages,
100 bool auxtrace_overwrite)
101{
102 if (auxtrace_pages) {
103 mp->offset = auxtrace_offset;
104 mp->len = auxtrace_pages * (size_t)page_size;
105 mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0;
106 mp->prot = PROT_READ | (auxtrace_overwrite ? 0 : PROT_WRITE);
107 pr_debug2("AUX area mmap length %zu\n", mp->len);
108 } else {
109 mp->len = 0;
110 }
111}
112
113void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
114 struct perf_evlist *evlist, int idx,
115 bool per_cpu)
116{
117 mp->idx = idx;
118
119 if (per_cpu) {
120 mp->cpu = evlist->cpus->map[idx];
121 if (evlist->threads)
122 mp->tid = evlist->threads->map[0];
123 else
124 mp->tid = -1;
125 } else {
126 mp->cpu = -1;
127 mp->tid = evlist->threads->map[idx];
128 }
129}
130
131#define AUXTRACE_INIT_NR_QUEUES 32
132
133static struct auxtrace_queue *auxtrace_alloc_queue_array(unsigned int nr_queues)
134{
135 struct auxtrace_queue *queue_array;
136 unsigned int max_nr_queues, i;
137
138 max_nr_queues = UINT_MAX / sizeof(struct auxtrace_queue);
139 if (nr_queues > max_nr_queues)
140 return NULL;
141
142 queue_array = calloc(nr_queues, sizeof(struct auxtrace_queue));
143 if (!queue_array)
144 return NULL;
145
146 for (i = 0; i < nr_queues; i++) {
147 INIT_LIST_HEAD(&queue_array[i].head);
148 queue_array[i].priv = NULL;
149 }
150
151 return queue_array;
152}
153
154int auxtrace_queues__init(struct auxtrace_queues *queues)
155{
156 queues->nr_queues = AUXTRACE_INIT_NR_QUEUES;
157 queues->queue_array = auxtrace_alloc_queue_array(queues->nr_queues);
158 if (!queues->queue_array)
159 return -ENOMEM;
160 return 0;
161}
162
163static int auxtrace_queues__grow(struct auxtrace_queues *queues,
164 unsigned int new_nr_queues)
165{
166 unsigned int nr_queues = queues->nr_queues;
167 struct auxtrace_queue *queue_array;
168 unsigned int i;
169
170 if (!nr_queues)
171 nr_queues = AUXTRACE_INIT_NR_QUEUES;
172
173 while (nr_queues && nr_queues < new_nr_queues)
174 nr_queues <<= 1;
175
176 if (nr_queues < queues->nr_queues || nr_queues < new_nr_queues)
177 return -EINVAL;
178
179 queue_array = auxtrace_alloc_queue_array(nr_queues);
180 if (!queue_array)
181 return -ENOMEM;
182
183 for (i = 0; i < queues->nr_queues; i++) {
184 list_splice_tail(&queues->queue_array[i].head,
185 &queue_array[i].head);
186 queue_array[i].priv = queues->queue_array[i].priv;
187 }
188
189 queues->nr_queues = nr_queues;
190 queues->queue_array = queue_array;
191
192 return 0;
193}
194
195static void *auxtrace_copy_data(u64 size, struct perf_session *session)
196{
197 int fd = perf_data_file__fd(session->file);
198 void *p;
199 ssize_t ret;
200
201 if (size > SSIZE_MAX)
202 return NULL;
203
204 p = malloc(size);
205 if (!p)
206 return NULL;
207
208 ret = readn(fd, p, size);
209 if (ret != (ssize_t)size) {
210 free(p);
211 return NULL;
212 }
213
214 return p;
215}
216
217static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues,
218 unsigned int idx,
219 struct auxtrace_buffer *buffer)
220{
221 struct auxtrace_queue *queue;
222 int err;
223
224 if (idx >= queues->nr_queues) {
225 err = auxtrace_queues__grow(queues, idx + 1);
226 if (err)
227 return err;
228 }
229
230 queue = &queues->queue_array[idx];
231
232 if (!queue->set) {
233 queue->set = true;
234 queue->tid = buffer->tid;
235 queue->cpu = buffer->cpu;
236 } else if (buffer->cpu != queue->cpu || buffer->tid != queue->tid) {
237 pr_err("auxtrace queue conflict: cpu %d, tid %d vs cpu %d, tid %d\n",
238 queue->cpu, queue->tid, buffer->cpu, buffer->tid);
239 return -EINVAL;
240 }
241
242 buffer->buffer_nr = queues->next_buffer_nr++;
243
244 list_add_tail(&buffer->list, &queue->head);
245
246 queues->new_data = true;
247 queues->populated = true;
248
249 return 0;
250}
251
252/* Limit buffers to 32MiB on 32-bit */
253#define BUFFER_LIMIT_FOR_32_BIT (32 * 1024 * 1024)
254
255static int auxtrace_queues__split_buffer(struct auxtrace_queues *queues,
256 unsigned int idx,
257 struct auxtrace_buffer *buffer)
258{
259 u64 sz = buffer->size;
260 bool consecutive = false;
261 struct auxtrace_buffer *b;
262 int err;
263
264 while (sz > BUFFER_LIMIT_FOR_32_BIT) {
265 b = memdup(buffer, sizeof(struct auxtrace_buffer));
266 if (!b)
267 return -ENOMEM;
268 b->size = BUFFER_LIMIT_FOR_32_BIT;
269 b->consecutive = consecutive;
270 err = auxtrace_queues__add_buffer(queues, idx, b);
271 if (err) {
272 auxtrace_buffer__free(b);
273 return err;
274 }
275 buffer->data_offset += BUFFER_LIMIT_FOR_32_BIT;
276 sz -= BUFFER_LIMIT_FOR_32_BIT;
277 consecutive = true;
278 }
279
280 buffer->size = sz;
281 buffer->consecutive = consecutive;
282
283 return 0;
284}
285
286static int auxtrace_queues__add_event_buffer(struct auxtrace_queues *queues,
287 struct perf_session *session,
288 unsigned int idx,
289 struct auxtrace_buffer *buffer)
290{
291 if (session->one_mmap) {
292 buffer->data = buffer->data_offset - session->one_mmap_offset +
293 session->one_mmap_addr;
294 } else if (perf_data_file__is_pipe(session->file)) {
295 buffer->data = auxtrace_copy_data(buffer->size, session);
296 if (!buffer->data)
297 return -ENOMEM;
298 buffer->data_needs_freeing = true;
299 } else if (BITS_PER_LONG == 32 &&
300 buffer->size > BUFFER_LIMIT_FOR_32_BIT) {
301 int err;
302
303 err = auxtrace_queues__split_buffer(queues, idx, buffer);
304 if (err)
305 return err;
306 }
307
308 return auxtrace_queues__add_buffer(queues, idx, buffer);
309}
310
311int auxtrace_queues__add_event(struct auxtrace_queues *queues,
312 struct perf_session *session,
313 union perf_event *event, off_t data_offset,
314 struct auxtrace_buffer **buffer_ptr)
315{
316 struct auxtrace_buffer *buffer;
317 unsigned int idx;
318 int err;
319
320 buffer = zalloc(sizeof(struct auxtrace_buffer));
321 if (!buffer)
322 return -ENOMEM;
323
324 buffer->pid = -1;
325 buffer->tid = event->auxtrace.tid;
326 buffer->cpu = event->auxtrace.cpu;
327 buffer->data_offset = data_offset;
328 buffer->offset = event->auxtrace.offset;
329 buffer->reference = event->auxtrace.reference;
330 buffer->size = event->auxtrace.size;
331 idx = event->auxtrace.idx;
332
333 err = auxtrace_queues__add_event_buffer(queues, session, idx, buffer);
334 if (err)
335 goto out_err;
336
337 if (buffer_ptr)
338 *buffer_ptr = buffer;
339
340 return 0;
341
342out_err:
343 auxtrace_buffer__free(buffer);
344 return err;
345}
346
347static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues,
348 struct perf_session *session,
349 off_t file_offset, size_t sz)
350{
351 union perf_event *event;
352 int err;
353 char buf[PERF_SAMPLE_MAX_SIZE];
354
355 err = perf_session__peek_event(session, file_offset, buf,
356 PERF_SAMPLE_MAX_SIZE, &event, NULL);
357 if (err)
358 return err;
359
360 if (event->header.type == PERF_RECORD_AUXTRACE) {
361 if (event->header.size < sizeof(struct auxtrace_event) ||
362 event->header.size != sz) {
363 err = -EINVAL;
364 goto out;
365 }
366 file_offset += event->header.size;
367 err = auxtrace_queues__add_event(queues, session, event,
368 file_offset, NULL);
369 }
370out:
371 return err;
372}
373
374void auxtrace_queues__free(struct auxtrace_queues *queues)
375{
376 unsigned int i;
377
378 for (i = 0; i < queues->nr_queues; i++) {
379 while (!list_empty(&queues->queue_array[i].head)) {
380 struct auxtrace_buffer *buffer;
381
382 buffer = list_entry(queues->queue_array[i].head.next,
383 struct auxtrace_buffer, list);
384 list_del(&buffer->list);
385 auxtrace_buffer__free(buffer);
386 }
387 }
388
389 zfree(&queues->queue_array);
390 queues->nr_queues = 0;
391}
392
393static void auxtrace_heapify(struct auxtrace_heap_item *heap_array,
394 unsigned int pos, unsigned int queue_nr,
395 u64 ordinal)
396{
397 unsigned int parent;
398
399 while (pos) {
400 parent = (pos - 1) >> 1;
401 if (heap_array[parent].ordinal <= ordinal)
402 break;
403 heap_array[pos] = heap_array[parent];
404 pos = parent;
405 }
406 heap_array[pos].queue_nr = queue_nr;
407 heap_array[pos].ordinal = ordinal;
408}
409
410int auxtrace_heap__add(struct auxtrace_heap *heap, unsigned int queue_nr,
411 u64 ordinal)
412{
413 struct auxtrace_heap_item *heap_array;
414
415 if (queue_nr >= heap->heap_sz) {
416 unsigned int heap_sz = AUXTRACE_INIT_NR_QUEUES;
417
418 while (heap_sz <= queue_nr)
419 heap_sz <<= 1;
420 heap_array = realloc(heap->heap_array,
421 heap_sz * sizeof(struct auxtrace_heap_item));
422 if (!heap_array)
423 return -ENOMEM;
424 heap->heap_array = heap_array;
425 heap->heap_sz = heap_sz;
426 }
427
428 auxtrace_heapify(heap->heap_array, heap->heap_cnt++, queue_nr, ordinal);
429
430 return 0;
431}
432
433void auxtrace_heap__free(struct auxtrace_heap *heap)
434{
435 zfree(&heap->heap_array);
436 heap->heap_cnt = 0;
437 heap->heap_sz = 0;
438}
439
440void auxtrace_heap__pop(struct auxtrace_heap *heap)
441{
442 unsigned int pos, last, heap_cnt = heap->heap_cnt;
443 struct auxtrace_heap_item *heap_array;
444
445 if (!heap_cnt)
446 return;
447
448 heap->heap_cnt -= 1;
449
450 heap_array = heap->heap_array;
451
452 pos = 0;
453 while (1) {
454 unsigned int left, right;
455
456 left = (pos << 1) + 1;
457 if (left >= heap_cnt)
458 break;
459 right = left + 1;
460 if (right >= heap_cnt) {
461 heap_array[pos] = heap_array[left];
462 return;
463 }
464 if (heap_array[left].ordinal < heap_array[right].ordinal) {
465 heap_array[pos] = heap_array[left];
466 pos = left;
467 } else {
468 heap_array[pos] = heap_array[right];
469 pos = right;
470 }
471 }
472
473 last = heap_cnt - 1;
474 auxtrace_heapify(heap_array, pos, heap_array[last].queue_nr,
475 heap_array[last].ordinal);
476}
477
478size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr)
479{
480 if (itr)
481 return itr->info_priv_size(itr);
482 return 0;
483}
484
485static int auxtrace_not_supported(void)
486{
487 pr_err("AUX area tracing is not supported on this architecture\n");
488 return -EINVAL;
489}
490
491int auxtrace_record__info_fill(struct auxtrace_record *itr,
492 struct perf_session *session,
493 struct auxtrace_info_event *auxtrace_info,
494 size_t priv_size)
495{
496 if (itr)
497 return itr->info_fill(itr, session, auxtrace_info, priv_size);
498 return auxtrace_not_supported();
499}
500
501void auxtrace_record__free(struct auxtrace_record *itr)
502{
503 if (itr)
504 itr->free(itr);
505}
506
507int auxtrace_record__snapshot_start(struct auxtrace_record *itr)
508{
509 if (itr && itr->snapshot_start)
510 return itr->snapshot_start(itr);
511 return 0;
512}
513
514int auxtrace_record__snapshot_finish(struct auxtrace_record *itr)
515{
516 if (itr && itr->snapshot_finish)
517 return itr->snapshot_finish(itr);
518 return 0;
519}
520
521int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,
522 struct auxtrace_mmap *mm,
523 unsigned char *data, u64 *head, u64 *old)
524{
525 if (itr && itr->find_snapshot)
526 return itr->find_snapshot(itr, idx, mm, data, head, old);
527 return 0;
528}
529
530int auxtrace_record__options(struct auxtrace_record *itr,
531 struct perf_evlist *evlist,
532 struct record_opts *opts)
533{
534 if (itr)
535 return itr->recording_options(itr, evlist, opts);
536 return 0;
537}
538
539u64 auxtrace_record__reference(struct auxtrace_record *itr)
540{
541 if (itr)
542 return itr->reference(itr);
543 return 0;
544}
545
546int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
547 struct record_opts *opts, const char *str)
548{
549 if (!str)
550 return 0;
551
552 if (itr)
553 return itr->parse_snapshot_options(itr, opts, str);
554
555 pr_err("No AUX area tracing to snapshot\n");
556 return -EINVAL;
557}
558
559struct auxtrace_record *__weak
560auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
561{
562 *err = 0;
563 return NULL;
564}
565
566static int auxtrace_index__alloc(struct list_head *head)
567{
568 struct auxtrace_index *auxtrace_index;
569
570 auxtrace_index = malloc(sizeof(struct auxtrace_index));
571 if (!auxtrace_index)
572 return -ENOMEM;
573
574 auxtrace_index->nr = 0;
575 INIT_LIST_HEAD(&auxtrace_index->list);
576
577 list_add_tail(&auxtrace_index->list, head);
578
579 return 0;
580}
581
582void auxtrace_index__free(struct list_head *head)
583{
584 struct auxtrace_index *auxtrace_index, *n;
585
586 list_for_each_entry_safe(auxtrace_index, n, head, list) {
587 list_del(&auxtrace_index->list);
588 free(auxtrace_index);
589 }
590}
591
592static struct auxtrace_index *auxtrace_index__last(struct list_head *head)
593{
594 struct auxtrace_index *auxtrace_index;
595 int err;
596
597 if (list_empty(head)) {
598 err = auxtrace_index__alloc(head);
599 if (err)
600 return NULL;
601 }
602
603 auxtrace_index = list_entry(head->prev, struct auxtrace_index, list);
604
605 if (auxtrace_index->nr >= PERF_AUXTRACE_INDEX_ENTRY_COUNT) {
606 err = auxtrace_index__alloc(head);
607 if (err)
608 return NULL;
609 auxtrace_index = list_entry(head->prev, struct auxtrace_index,
610 list);
611 }
612
613 return auxtrace_index;
614}
615
616int auxtrace_index__auxtrace_event(struct list_head *head,
617 union perf_event *event, off_t file_offset)
618{
619 struct auxtrace_index *auxtrace_index;
620 size_t nr;
621
622 auxtrace_index = auxtrace_index__last(head);
623 if (!auxtrace_index)
624 return -ENOMEM;
625
626 nr = auxtrace_index->nr;
627 auxtrace_index->entries[nr].file_offset = file_offset;
628 auxtrace_index->entries[nr].sz = event->header.size;
629 auxtrace_index->nr += 1;
630
631 return 0;
632}
633
634static int auxtrace_index__do_write(int fd,
635 struct auxtrace_index *auxtrace_index)
636{
637 struct auxtrace_index_entry ent;
638 size_t i;
639
640 for (i = 0; i < auxtrace_index->nr; i++) {
641 ent.file_offset = auxtrace_index->entries[i].file_offset;
642 ent.sz = auxtrace_index->entries[i].sz;
643 if (writen(fd, &ent, sizeof(ent)) != sizeof(ent))
644 return -errno;
645 }
646 return 0;
647}
648
649int auxtrace_index__write(int fd, struct list_head *head)
650{
651 struct auxtrace_index *auxtrace_index;
652 u64 total = 0;
653 int err;
654
655 list_for_each_entry(auxtrace_index, head, list)
656 total += auxtrace_index->nr;
657
658 if (writen(fd, &total, sizeof(total)) != sizeof(total))
659 return -errno;
660
661 list_for_each_entry(auxtrace_index, head, list) {
662 err = auxtrace_index__do_write(fd, auxtrace_index);
663 if (err)
664 return err;
665 }
666
667 return 0;
668}
669
670static int auxtrace_index__process_entry(int fd, struct list_head *head,
671 bool needs_swap)
672{
673 struct auxtrace_index *auxtrace_index;
674 struct auxtrace_index_entry ent;
675 size_t nr;
676
677 if (readn(fd, &ent, sizeof(ent)) != sizeof(ent))
678 return -1;
679
680 auxtrace_index = auxtrace_index__last(head);
681 if (!auxtrace_index)
682 return -1;
683
684 nr = auxtrace_index->nr;
685 if (needs_swap) {
686 auxtrace_index->entries[nr].file_offset =
687 bswap_64(ent.file_offset);
688 auxtrace_index->entries[nr].sz = bswap_64(ent.sz);
689 } else {
690 auxtrace_index->entries[nr].file_offset = ent.file_offset;
691 auxtrace_index->entries[nr].sz = ent.sz;
692 }
693
694 auxtrace_index->nr = nr + 1;
695
696 return 0;
697}
698
699int auxtrace_index__process(int fd, u64 size, struct perf_session *session,
700 bool needs_swap)
701{
702 struct list_head *head = &session->auxtrace_index;
703 u64 nr;
704
705 if (readn(fd, &nr, sizeof(u64)) != sizeof(u64))
706 return -1;
707
708 if (needs_swap)
709 nr = bswap_64(nr);
710
711 if (sizeof(u64) + nr * sizeof(struct auxtrace_index_entry) > size)
712 return -1;
713
714 while (nr--) {
715 int err;
716
717 err = auxtrace_index__process_entry(fd, head, needs_swap);
718 if (err)
719 return -1;
720 }
721
722 return 0;
723}
724
725static int auxtrace_queues__process_index_entry(struct auxtrace_queues *queues,
726 struct perf_session *session,
727 struct auxtrace_index_entry *ent)
728{
729 return auxtrace_queues__add_indexed_event(queues, session,
730 ent->file_offset, ent->sz);
731}
732
733int auxtrace_queues__process_index(struct auxtrace_queues *queues,
734 struct perf_session *session)
735{
736 struct auxtrace_index *auxtrace_index;
737 struct auxtrace_index_entry *ent;
738 size_t i;
739 int err;
740
741 list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) {
742 for (i = 0; i < auxtrace_index->nr; i++) {
743 ent = &auxtrace_index->entries[i];
744 err = auxtrace_queues__process_index_entry(queues,
745 session,
746 ent);
747 if (err)
748 return err;
749 }
750 }
751 return 0;
752}
753
754struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue,
755 struct auxtrace_buffer *buffer)
756{
757 if (buffer) {
758 if (list_is_last(&buffer->list, &queue->head))
759 return NULL;
760 return list_entry(buffer->list.next, struct auxtrace_buffer,
761 list);
762 } else {
763 if (list_empty(&queue->head))
764 return NULL;
765 return list_entry(queue->head.next, struct auxtrace_buffer,
766 list);
767 }
768}
769
770void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd)
771{
772 size_t adj = buffer->data_offset & (page_size - 1);
773 size_t size = buffer->size + adj;
774 off_t file_offset = buffer->data_offset - adj;
775 void *addr;
776
777 if (buffer->data)
778 return buffer->data;
779
780 addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, file_offset);
781 if (addr == MAP_FAILED)
782 return NULL;
783
784 buffer->mmap_addr = addr;
785 buffer->mmap_size = size;
786
787 buffer->data = addr + adj;
788
789 return buffer->data;
790}
791
792void auxtrace_buffer__put_data(struct auxtrace_buffer *buffer)
793{
794 if (!buffer->data || !buffer->mmap_addr)
795 return;
796 munmap(buffer->mmap_addr, buffer->mmap_size);
797 buffer->mmap_addr = NULL;
798 buffer->mmap_size = 0;
799 buffer->data = NULL;
800 buffer->use_data = NULL;
801}
802
803void auxtrace_buffer__drop_data(struct auxtrace_buffer *buffer)
804{
805 auxtrace_buffer__put_data(buffer);
806 if (buffer->data_needs_freeing) {
807 buffer->data_needs_freeing = false;
808 zfree(&buffer->data);
809 buffer->use_data = NULL;
810 buffer->size = 0;
811 }
812}
813
814void auxtrace_buffer__free(struct auxtrace_buffer *buffer)
815{
816 auxtrace_buffer__drop_data(buffer);
817 free(buffer);
818}
819
820void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type,
821 int code, int cpu, pid_t pid, pid_t tid, u64 ip,
822 const char *msg)
823{
824 size_t size;
825
826 memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event));
827
828 auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR;
829 auxtrace_error->type = type;
830 auxtrace_error->code = code;
831 auxtrace_error->cpu = cpu;
832 auxtrace_error->pid = pid;
833 auxtrace_error->tid = tid;
834 auxtrace_error->ip = ip;
835 strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG);
836
837 size = (void *)auxtrace_error->msg - (void *)auxtrace_error +
838 strlen(auxtrace_error->msg) + 1;
839 auxtrace_error->header.size = PERF_ALIGN(size, sizeof(u64));
840}
841
842int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
843 struct perf_tool *tool,
844 struct perf_session *session,
845 perf_event__handler_t process)
846{
847 union perf_event *ev;
848 size_t priv_size;
849 int err;
850
851 pr_debug2("Synthesizing auxtrace information\n");
852 priv_size = auxtrace_record__info_priv_size(itr);
853 ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size);
854 if (!ev)
855 return -ENOMEM;
856
857 ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO;
858 ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) +
859 priv_size;
860 err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info,
861 priv_size);
862 if (err)
863 goto out_free;
864
865 err = process(tool, ev, NULL, NULL);
866out_free:
867 free(ev);
868 return err;
869}
870
871static bool auxtrace__dont_decode(struct perf_session *session)
872{
873 return !session->itrace_synth_opts ||
874 session->itrace_synth_opts->dont_decode;
875}
876
877int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
878 union perf_event *event,
879 struct perf_session *session __maybe_unused)
880{
881 enum auxtrace_type type = event->auxtrace_info.type;
882
883 if (dump_trace)
884 fprintf(stdout, " type: %u\n", type);
885
886 switch (type) {
887 case PERF_AUXTRACE_UNKNOWN:
888 default:
889 return -EINVAL;
890 }
891}
892
893s64 perf_event__process_auxtrace(struct perf_tool *tool,
894 union perf_event *event,
895 struct perf_session *session)
896{
897 s64 err;
898
899 if (dump_trace)
900 fprintf(stdout, " size: %#"PRIx64" offset: %#"PRIx64" ref: %#"PRIx64" idx: %u tid: %d cpu: %d\n",
901 event->auxtrace.size, event->auxtrace.offset,
902 event->auxtrace.reference, event->auxtrace.idx,
903 event->auxtrace.tid, event->auxtrace.cpu);
904
905 if (auxtrace__dont_decode(session))
906 return event->auxtrace.size;
907
908 if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE)
909 return -EINVAL;
910
911 err = session->auxtrace->process_auxtrace_event(session, event, tool);
912 if (err < 0)
913 return err;
914
915 return event->auxtrace.size;
916}
917
918#define PERF_ITRACE_DEFAULT_PERIOD_TYPE PERF_ITRACE_PERIOD_NANOSECS
919#define PERF_ITRACE_DEFAULT_PERIOD 100000
920#define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16
921#define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024
922
923void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts)
924{
925 synth_opts->instructions = true;
926 synth_opts->branches = true;
927 synth_opts->transactions = true;
928 synth_opts->errors = true;
929 synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE;
930 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
931 synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
932}
933
934/*
935 * Please check tools/perf/Documentation/perf-script.txt for information
936 * about the options parsed here, which is introduced after this cset,
937 * when support in 'perf script' for these options is introduced.
938 */
939int itrace_parse_synth_opts(const struct option *opt, const char *str,
940 int unset)
941{
942 struct itrace_synth_opts *synth_opts = opt->value;
943 const char *p;
944 char *endptr;
945
946 synth_opts->set = true;
947
948 if (unset) {
949 synth_opts->dont_decode = true;
950 return 0;
951 }
952
953 if (!str) {
954 itrace_synth_opts__set_default(synth_opts);
955 return 0;
956 }
957
958 for (p = str; *p;) {
959 switch (*p++) {
960 case 'i':
961 synth_opts->instructions = true;
962 while (*p == ' ' || *p == ',')
963 p += 1;
964 if (isdigit(*p)) {
965 synth_opts->period = strtoull(p, &endptr, 10);
966 p = endptr;
967 while (*p == ' ' || *p == ',')
968 p += 1;
969 switch (*p++) {
970 case 'i':
971 synth_opts->period_type =
972 PERF_ITRACE_PERIOD_INSTRUCTIONS;
973 break;
974 case 't':
975 synth_opts->period_type =
976 PERF_ITRACE_PERIOD_TICKS;
977 break;
978 case 'm':
979 synth_opts->period *= 1000;
980 /* Fall through */
981 case 'u':
982 synth_opts->period *= 1000;
983 /* Fall through */
984 case 'n':
985 if (*p++ != 's')
986 goto out_err;
987 synth_opts->period_type =
988 PERF_ITRACE_PERIOD_NANOSECS;
989 break;
990 case '\0':
991 goto out;
992 default:
993 goto out_err;
994 }
995 }
996 break;
997 case 'b':
998 synth_opts->branches = true;
999 break;
1000 case 'x':
1001 synth_opts->transactions = true;
1002 break;
1003 case 'e':
1004 synth_opts->errors = true;
1005 break;
1006 case 'd':
1007 synth_opts->log = true;
1008 break;
1009 case 'c':
1010 synth_opts->branches = true;
1011 synth_opts->calls = true;
1012 break;
1013 case 'r':
1014 synth_opts->branches = true;
1015 synth_opts->returns = true;
1016 break;
1017 case 'g':
1018 synth_opts->callchain = true;
1019 synth_opts->callchain_sz =
1020 PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
1021 while (*p == ' ' || *p == ',')
1022 p += 1;
1023 if (isdigit(*p)) {
1024 unsigned int val;
1025
1026 val = strtoul(p, &endptr, 10);
1027 p = endptr;
1028 if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ)
1029 goto out_err;
1030 synth_opts->callchain_sz = val;
1031 }
1032 break;
1033 case ' ':
1034 case ',':
1035 break;
1036 default:
1037 goto out_err;
1038 }
1039 }
1040out:
1041 if (synth_opts->instructions) {
1042 if (!synth_opts->period_type)
1043 synth_opts->period_type =
1044 PERF_ITRACE_DEFAULT_PERIOD_TYPE;
1045 if (!synth_opts->period)
1046 synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
1047 }
1048
1049 return 0;
1050
1051out_err:
1052 pr_err("Bad Instruction Tracing options '%s'\n", str);
1053 return -EINVAL;
1054}
1055
1056static const char * const auxtrace_error_type_name[] = {
1057 [PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace",
1058};
1059
1060static const char *auxtrace_error_name(int type)
1061{
1062 const char *error_type_name = NULL;
1063
1064 if (type < PERF_AUXTRACE_ERROR_MAX)
1065 error_type_name = auxtrace_error_type_name[type];
1066 if (!error_type_name)
1067 error_type_name = "unknown AUX";
1068 return error_type_name;
1069}
1070
1071size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp)
1072{
1073 struct auxtrace_error_event *e = &event->auxtrace_error;
1074 int ret;
1075
1076 ret = fprintf(fp, " %s error type %u",
1077 auxtrace_error_name(e->type), e->type);
1078 ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n",
1079 e->cpu, e->pid, e->tid, e->ip, e->code, e->msg);
1080 return ret;
1081}
1082
1083void perf_session__auxtrace_error_inc(struct perf_session *session,
1084 union perf_event *event)
1085{
1086 struct auxtrace_error_event *e = &event->auxtrace_error;
1087
1088 if (e->type < PERF_AUXTRACE_ERROR_MAX)
1089 session->evlist->stats.nr_auxtrace_errors[e->type] += 1;
1090}
1091
1092void events_stats__auxtrace_error_warn(const struct events_stats *stats)
1093{
1094 int i;
1095
1096 for (i = 0; i < PERF_AUXTRACE_ERROR_MAX; i++) {
1097 if (!stats->nr_auxtrace_errors[i])
1098 continue;
1099 ui__warning("%u %s errors\n",
1100 stats->nr_auxtrace_errors[i],
1101 auxtrace_error_name(i));
1102 }
1103}
1104
1105int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
1106 union perf_event *event,
1107 struct perf_session *session)
1108{
1109 if (auxtrace__dont_decode(session))
1110 return 0;
1111
1112 perf_event__fprintf_auxtrace_error(event, stdout);
1113 return 0;
1114}
1115
1116static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
1117 struct auxtrace_record *itr,
1118 struct perf_tool *tool, process_auxtrace_t fn,
1119 bool snapshot, size_t snapshot_size)
1120{
1121 u64 head, old = mm->prev, offset, ref;
1122 unsigned char *data = mm->base;
1123 size_t size, head_off, old_off, len1, len2, padding;
1124 union perf_event ev;
1125 void *data1, *data2;
1126
1127 if (snapshot) {
1128 head = auxtrace_mmap__read_snapshot_head(mm);
1129 if (auxtrace_record__find_snapshot(itr, mm->idx, mm, data,
1130 &head, &old))
1131 return -1;
1132 } else {
1133 head = auxtrace_mmap__read_head(mm);
1134 }
1135
1136 if (old == head)
1137 return 0;
1138
1139 pr_debug3("auxtrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n",
1140 mm->idx, old, head, head - old);
1141
1142 if (mm->mask) {
1143 head_off = head & mm->mask;
1144 old_off = old & mm->mask;
1145 } else {
1146 head_off = head % mm->len;
1147 old_off = old % mm->len;
1148 }
1149
1150 if (head_off > old_off)
1151 size = head_off - old_off;
1152 else
1153 size = mm->len - (old_off - head_off);
1154
1155 if (snapshot && size > snapshot_size)
1156 size = snapshot_size;
1157
1158 ref = auxtrace_record__reference(itr);
1159
1160 if (head > old || size <= head || mm->mask) {
1161 offset = head - size;
1162 } else {
1163 /*
1164 * When the buffer size is not a power of 2, 'head' wraps at the
1165 * highest multiple of the buffer size, so we have to subtract
1166 * the remainder here.
1167 */
1168 u64 rem = (0ULL - mm->len) % mm->len;
1169
1170 offset = head - size - rem;
1171 }
1172
1173 if (size > head_off) {
1174 len1 = size - head_off;
1175 data1 = &data[mm->len - len1];
1176 len2 = head_off;
1177 data2 = &data[0];
1178 } else {
1179 len1 = size;
1180 data1 = &data[head_off - len1];
1181 len2 = 0;
1182 data2 = NULL;
1183 }
1184
1185 /* padding must be written by fn() e.g. record__process_auxtrace() */
1186 padding = size & 7;
1187 if (padding)
1188 padding = 8 - padding;
1189
1190 memset(&ev, 0, sizeof(ev));
1191 ev.auxtrace.header.type = PERF_RECORD_AUXTRACE;
1192 ev.auxtrace.header.size = sizeof(ev.auxtrace);
1193 ev.auxtrace.size = size + padding;
1194 ev.auxtrace.offset = offset;
1195 ev.auxtrace.reference = ref;
1196 ev.auxtrace.idx = mm->idx;
1197 ev.auxtrace.tid = mm->tid;
1198 ev.auxtrace.cpu = mm->cpu;
1199
1200 if (fn(tool, &ev, data1, len1, data2, len2))
1201 return -1;
1202
1203 mm->prev = head;
1204
1205 if (!snapshot) {
1206 auxtrace_mmap__write_tail(mm, head);
1207 if (itr->read_finish) {
1208 int err;
1209
1210 err = itr->read_finish(itr, mm->idx);
1211 if (err < 0)
1212 return err;
1213 }
1214 }
1215
1216 return 1;
1217}
1218
1219int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
1220 struct perf_tool *tool, process_auxtrace_t fn)
1221{
1222 return __auxtrace_mmap__read(mm, itr, tool, fn, false, 0);
1223}
1224
1225int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm,
1226 struct auxtrace_record *itr,
1227 struct perf_tool *tool, process_auxtrace_t fn,
1228 size_t snapshot_size)
1229{
1230 return __auxtrace_mmap__read(mm, itr, tool, fn, true, snapshot_size);
1231}
1232
1233/**
1234 * struct auxtrace_cache - hash table to implement a cache
1235 * @hashtable: the hashtable
1236 * @sz: hashtable size (number of hlists)
1237 * @entry_size: size of an entry
1238 * @limit: limit the number of entries to this maximum, when reached the cache
1239 * is dropped and caching begins again with an empty cache
1240 * @cnt: current number of entries
1241 * @bits: hashtable size (@sz = 2^@bits)
1242 */
1243struct auxtrace_cache {
1244 struct hlist_head *hashtable;
1245 size_t sz;
1246 size_t entry_size;
1247 size_t limit;
1248 size_t cnt;
1249 unsigned int bits;
1250};
1251
1252struct auxtrace_cache *auxtrace_cache__new(unsigned int bits, size_t entry_size,
1253 unsigned int limit_percent)
1254{
1255 struct auxtrace_cache *c;
1256 struct hlist_head *ht;
1257 size_t sz, i;
1258
1259 c = zalloc(sizeof(struct auxtrace_cache));
1260 if (!c)
1261 return NULL;
1262
1263 sz = 1UL << bits;
1264
1265 ht = calloc(sz, sizeof(struct hlist_head));
1266 if (!ht)
1267 goto out_free;
1268
1269 for (i = 0; i < sz; i++)
1270 INIT_HLIST_HEAD(&ht[i]);
1271
1272 c->hashtable = ht;
1273 c->sz = sz;
1274 c->entry_size = entry_size;
1275 c->limit = (c->sz * limit_percent) / 100;
1276 c->bits = bits;
1277
1278 return c;
1279
1280out_free:
1281 free(c);
1282 return NULL;
1283}
1284
1285static void auxtrace_cache__drop(struct auxtrace_cache *c)
1286{
1287 struct auxtrace_cache_entry *entry;
1288 struct hlist_node *tmp;
1289 size_t i;
1290
1291 if (!c)
1292 return;
1293
1294 for (i = 0; i < c->sz; i++) {
1295 hlist_for_each_entry_safe(entry, tmp, &c->hashtable[i], hash) {
1296 hlist_del(&entry->hash);
1297 auxtrace_cache__free_entry(c, entry);
1298 }
1299 }
1300
1301 c->cnt = 0;
1302}
1303
1304void auxtrace_cache__free(struct auxtrace_cache *c)
1305{
1306 if (!c)
1307 return;
1308
1309 auxtrace_cache__drop(c);
1310 free(c->hashtable);
1311 free(c);
1312}
1313
1314void *auxtrace_cache__alloc_entry(struct auxtrace_cache *c)
1315{
1316 return malloc(c->entry_size);
1317}
1318
1319void auxtrace_cache__free_entry(struct auxtrace_cache *c __maybe_unused,
1320 void *entry)
1321{
1322 free(entry);
1323}
1324
1325int auxtrace_cache__add(struct auxtrace_cache *c, u32 key,
1326 struct auxtrace_cache_entry *entry)
1327{
1328 if (c->limit && ++c->cnt > c->limit)
1329 auxtrace_cache__drop(c);
1330
1331 entry->key = key;
1332 hlist_add_head(&entry->hash, &c->hashtable[hash_32(key, c->bits)]);
1333
1334 return 0;
1335}
1336
1337void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key)
1338{
1339 struct auxtrace_cache_entry *entry;
1340 struct hlist_head *hlist;
1341
1342 if (!c)
1343 return NULL;
1344
1345 hlist = &c->hashtable[hash_32(key, c->bits)];
1346 hlist_for_each_entry(entry, hlist, hash) {
1347 if (entry->key == key)
1348 return entry;
1349 }
1350
1351 return NULL;
1352}
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
new file mode 100644
index 000000000000..a171abbe7301
--- /dev/null
+++ b/tools/perf/util/auxtrace.h
@@ -0,0 +1,643 @@
1/*
2 * auxtrace.h: AUX area trace support
3 * Copyright (c) 2013-2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#ifndef __PERF_AUXTRACE_H
17#define __PERF_AUXTRACE_H
18
19#include <sys/types.h>
20#include <stdbool.h>
21#include <stddef.h>
22#include <linux/list.h>
23#include <linux/perf_event.h>
24#include <linux/types.h>
25
26#include "../perf.h"
27#include "event.h"
28#include "session.h"
29#include "debug.h"
30
31union perf_event;
32struct perf_session;
33struct perf_evlist;
34struct perf_tool;
35struct option;
36struct record_opts;
37struct auxtrace_info_event;
38struct events_stats;
39
40enum auxtrace_type {
41 PERF_AUXTRACE_UNKNOWN,
42};
43
44enum itrace_period_type {
45 PERF_ITRACE_PERIOD_INSTRUCTIONS,
46 PERF_ITRACE_PERIOD_TICKS,
47 PERF_ITRACE_PERIOD_NANOSECS,
48};
49
50/**
51 * struct itrace_synth_opts - AUX area tracing synthesis options.
52 * @set: indicates whether or not options have been set
53 * @inject: indicates the event (not just the sample) must be fully synthesized
54 * because 'perf inject' will write it out
55 * @instructions: whether to synthesize 'instructions' events
56 * @branches: whether to synthesize 'branches' events
57 * @transactions: whether to synthesize events for transactions
58 * @errors: whether to synthesize decoder error events
59 * @dont_decode: whether to skip decoding entirely
60 * @log: write a decoding log
61 * @calls: limit branch samples to calls (can be combined with @returns)
62 * @returns: limit branch samples to returns (can be combined with @calls)
63 * @callchain: add callchain to 'instructions' events
64 * @callchain_sz: maximum callchain size
65 * @period: 'instructions' events period
66 * @period_type: 'instructions' events period type
67 */
68struct itrace_synth_opts {
69 bool set;
70 bool inject;
71 bool instructions;
72 bool branches;
73 bool transactions;
74 bool errors;
75 bool dont_decode;
76 bool log;
77 bool calls;
78 bool returns;
79 bool callchain;
80 unsigned int callchain_sz;
81 unsigned long long period;
82 enum itrace_period_type period_type;
83};
84
85/**
86 * struct auxtrace_index_entry - indexes a AUX area tracing event within a
87 * perf.data file.
88 * @file_offset: offset within the perf.data file
89 * @sz: size of the event
90 */
91struct auxtrace_index_entry {
92 u64 file_offset;
93 u64 sz;
94};
95
96#define PERF_AUXTRACE_INDEX_ENTRY_COUNT 256
97
98/**
99 * struct auxtrace_index - index of AUX area tracing events within a perf.data
100 * file.
101 * @list: linking a number of arrays of entries
102 * @nr: number of entries
103 * @entries: array of entries
104 */
105struct auxtrace_index {
106 struct list_head list;
107 size_t nr;
108 struct auxtrace_index_entry entries[PERF_AUXTRACE_INDEX_ENTRY_COUNT];
109};
110
111/**
112 * struct auxtrace - session callbacks to allow AUX area data decoding.
113 * @process_event: lets the decoder see all session events
114 * @flush_events: process any remaining data
115 * @free_events: free resources associated with event processing
116 * @free: free resources associated with the session
117 */
118struct auxtrace {
119 int (*process_event)(struct perf_session *session,
120 union perf_event *event,
121 struct perf_sample *sample,
122 struct perf_tool *tool);
123 int (*process_auxtrace_event)(struct perf_session *session,
124 union perf_event *event,
125 struct perf_tool *tool);
126 int (*flush_events)(struct perf_session *session,
127 struct perf_tool *tool);
128 void (*free_events)(struct perf_session *session);
129 void (*free)(struct perf_session *session);
130};
131
132/**
133 * struct auxtrace_buffer - a buffer containing AUX area tracing data.
134 * @list: buffers are queued in a list held by struct auxtrace_queue
135 * @size: size of the buffer in bytes
136 * @pid: in per-thread mode, the pid this buffer is associated with
137 * @tid: in per-thread mode, the tid this buffer is associated with
138 * @cpu: in per-cpu mode, the cpu this buffer is associated with
139 * @data: actual buffer data (can be null if the data has not been loaded)
140 * @data_offset: file offset at which the buffer can be read
141 * @mmap_addr: mmap address at which the buffer can be read
142 * @mmap_size: size of the mmap at @mmap_addr
143 * @data_needs_freeing: @data was malloc'd so free it when it is no longer
144 * needed
145 * @consecutive: the original data was split up and this buffer is consecutive
146 * to the previous buffer
147 * @offset: offset as determined by aux_head / aux_tail members of struct
148 * perf_event_mmap_page
149 * @reference: an implementation-specific reference determined when the data is
150 * recorded
151 * @buffer_nr: used to number each buffer
152 * @use_size: implementation actually only uses this number of bytes
153 * @use_data: implementation actually only uses data starting at this address
154 */
155struct auxtrace_buffer {
156 struct list_head list;
157 size_t size;
158 pid_t pid;
159 pid_t tid;
160 int cpu;
161 void *data;
162 off_t data_offset;
163 void *mmap_addr;
164 size_t mmap_size;
165 bool data_needs_freeing;
166 bool consecutive;
167 u64 offset;
168 u64 reference;
169 u64 buffer_nr;
170 size_t use_size;
171 void *use_data;
172};
173
174/**
175 * struct auxtrace_queue - a queue of AUX area tracing data buffers.
176 * @head: head of buffer list
177 * @tid: in per-thread mode, the tid this queue is associated with
178 * @cpu: in per-cpu mode, the cpu this queue is associated with
179 * @set: %true once this queue has been dedicated to a specific thread or cpu
180 * @priv: implementation-specific data
181 */
182struct auxtrace_queue {
183 struct list_head head;
184 pid_t tid;
185 int cpu;
186 bool set;
187 void *priv;
188};
189
190/**
191 * struct auxtrace_queues - an array of AUX area tracing queues.
192 * @queue_array: array of queues
193 * @nr_queues: number of queues
194 * @new_data: set whenever new data is queued
195 * @populated: queues have been fully populated using the auxtrace_index
196 * @next_buffer_nr: used to number each buffer
197 */
198struct auxtrace_queues {
199 struct auxtrace_queue *queue_array;
200 unsigned int nr_queues;
201 bool new_data;
202 bool populated;
203 u64 next_buffer_nr;
204};
205
206/**
207 * struct auxtrace_heap_item - element of struct auxtrace_heap.
208 * @queue_nr: queue number
209 * @ordinal: value used for sorting (lowest ordinal is top of the heap) expected
210 * to be a timestamp
211 */
212struct auxtrace_heap_item {
213 unsigned int queue_nr;
214 u64 ordinal;
215};
216
217/**
218 * struct auxtrace_heap - a heap suitable for sorting AUX area tracing queues.
219 * @heap_array: the heap
220 * @heap_cnt: the number of elements in the heap
221 * @heap_sz: maximum number of elements (grows as needed)
222 */
223struct auxtrace_heap {
224 struct auxtrace_heap_item *heap_array;
225 unsigned int heap_cnt;
226 unsigned int heap_sz;
227};
228
229/**
230 * struct auxtrace_mmap - records an mmap of the auxtrace buffer.
231 * @base: address of mapped area
232 * @userpg: pointer to buffer's perf_event_mmap_page
233 * @mask: %0 if @len is not a power of two, otherwise (@len - %1)
234 * @len: size of mapped area
235 * @prev: previous aux_head
236 * @idx: index of this mmap
237 * @tid: tid for a per-thread mmap (also set if there is only 1 tid on a per-cpu
238 * mmap) otherwise %0
239 * @cpu: cpu number for a per-cpu mmap otherwise %-1
240 */
241struct auxtrace_mmap {
242 void *base;
243 void *userpg;
244 size_t mask;
245 size_t len;
246 u64 prev;
247 int idx;
248 pid_t tid;
249 int cpu;
250};
251
252/**
253 * struct auxtrace_mmap_params - parameters to set up struct auxtrace_mmap.
254 * @mask: %0 if @len is not a power of two, otherwise (@len - %1)
255 * @offset: file offset of mapped area
256 * @len: size of mapped area
257 * @prot: mmap memory protection
258 * @idx: index of this mmap
259 * @tid: tid for a per-thread mmap (also set if there is only 1 tid on a per-cpu
260 * mmap) otherwise %0
261 * @cpu: cpu number for a per-cpu mmap otherwise %-1
262 */
263struct auxtrace_mmap_params {
264 size_t mask;
265 off_t offset;
266 size_t len;
267 int prot;
268 int idx;
269 pid_t tid;
270 int cpu;
271};
272
273/**
274 * struct auxtrace_record - callbacks for recording AUX area data.
275 * @recording_options: validate and process recording options
276 * @info_priv_size: return the size of the private data in auxtrace_info_event
277 * @info_fill: fill-in the private data in auxtrace_info_event
278 * @free: free this auxtrace record structure
279 * @snapshot_start: starting a snapshot
280 * @snapshot_finish: finishing a snapshot
281 * @find_snapshot: find data to snapshot within auxtrace mmap
282 * @parse_snapshot_options: parse snapshot options
283 * @reference: provide a 64-bit reference number for auxtrace_event
284 * @read_finish: called after reading from an auxtrace mmap
285 */
286struct auxtrace_record {
287 int (*recording_options)(struct auxtrace_record *itr,
288 struct perf_evlist *evlist,
289 struct record_opts *opts);
290 size_t (*info_priv_size)(struct auxtrace_record *itr);
291 int (*info_fill)(struct auxtrace_record *itr,
292 struct perf_session *session,
293 struct auxtrace_info_event *auxtrace_info,
294 size_t priv_size);
295 void (*free)(struct auxtrace_record *itr);
296 int (*snapshot_start)(struct auxtrace_record *itr);
297 int (*snapshot_finish)(struct auxtrace_record *itr);
298 int (*find_snapshot)(struct auxtrace_record *itr, int idx,
299 struct auxtrace_mmap *mm, unsigned char *data,
300 u64 *head, u64 *old);
301 int (*parse_snapshot_options)(struct auxtrace_record *itr,
302 struct record_opts *opts,
303 const char *str);
304 u64 (*reference)(struct auxtrace_record *itr);
305 int (*read_finish)(struct auxtrace_record *itr, int idx);
306};
307
308#ifdef HAVE_AUXTRACE_SUPPORT
309
310/*
311 * In snapshot mode the mmapped page is read-only which makes using
312 * __sync_val_compare_and_swap() problematic. However, snapshot mode expects
313 * the buffer is not updated while the snapshot is made (e.g. Intel PT disables
314 * the event) so there is not a race anyway.
315 */
316static inline u64 auxtrace_mmap__read_snapshot_head(struct auxtrace_mmap *mm)
317{
318 struct perf_event_mmap_page *pc = mm->userpg;
319 u64 head = ACCESS_ONCE(pc->aux_head);
320
321 /* Ensure all reads are done after we read the head */
322 rmb();
323 return head;
324}
325
326static inline u64 auxtrace_mmap__read_head(struct auxtrace_mmap *mm)
327{
328 struct perf_event_mmap_page *pc = mm->userpg;
329#if BITS_PER_LONG == 64 || !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
330 u64 head = ACCESS_ONCE(pc->aux_head);
331#else
332 u64 head = __sync_val_compare_and_swap(&pc->aux_head, 0, 0);
333#endif
334
335 /* Ensure all reads are done after we read the head */
336 rmb();
337 return head;
338}
339
340static inline void auxtrace_mmap__write_tail(struct auxtrace_mmap *mm, u64 tail)
341{
342 struct perf_event_mmap_page *pc = mm->userpg;
343#if BITS_PER_LONG != 64 && defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
344 u64 old_tail;
345#endif
346
347 /* Ensure all reads are done before we write the tail out */
348 mb();
349#if BITS_PER_LONG == 64 || !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
350 pc->aux_tail = tail;
351#else
352 do {
353 old_tail = __sync_val_compare_and_swap(&pc->aux_tail, 0, 0);
354 } while (!__sync_bool_compare_and_swap(&pc->aux_tail, old_tail, tail));
355#endif
356}
357
358int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
359 struct auxtrace_mmap_params *mp,
360 void *userpg, int fd);
361void auxtrace_mmap__munmap(struct auxtrace_mmap *mm);
362void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
363 off_t auxtrace_offset,
364 unsigned int auxtrace_pages,
365 bool auxtrace_overwrite);
366void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
367 struct perf_evlist *evlist, int idx,
368 bool per_cpu);
369
370typedef int (*process_auxtrace_t)(struct perf_tool *tool,
371 union perf_event *event, void *data1,
372 size_t len1, void *data2, size_t len2);
373
374int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
375 struct perf_tool *tool, process_auxtrace_t fn);
376
377int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm,
378 struct auxtrace_record *itr,
379 struct perf_tool *tool, process_auxtrace_t fn,
380 size_t snapshot_size);
381
382int auxtrace_queues__init(struct auxtrace_queues *queues);
383int auxtrace_queues__add_event(struct auxtrace_queues *queues,
384 struct perf_session *session,
385 union perf_event *event, off_t data_offset,
386 struct auxtrace_buffer **buffer_ptr);
387void auxtrace_queues__free(struct auxtrace_queues *queues);
388int auxtrace_queues__process_index(struct auxtrace_queues *queues,
389 struct perf_session *session);
390struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue,
391 struct auxtrace_buffer *buffer);
392void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd);
393void auxtrace_buffer__put_data(struct auxtrace_buffer *buffer);
394void auxtrace_buffer__drop_data(struct auxtrace_buffer *buffer);
395void auxtrace_buffer__free(struct auxtrace_buffer *buffer);
396
397int auxtrace_heap__add(struct auxtrace_heap *heap, unsigned int queue_nr,
398 u64 ordinal);
399void auxtrace_heap__pop(struct auxtrace_heap *heap);
400void auxtrace_heap__free(struct auxtrace_heap *heap);
401
402struct auxtrace_cache_entry {
403 struct hlist_node hash;
404 u32 key;
405};
406
407struct auxtrace_cache *auxtrace_cache__new(unsigned int bits, size_t entry_size,
408 unsigned int limit_percent);
409void auxtrace_cache__free(struct auxtrace_cache *auxtrace_cache);
410void *auxtrace_cache__alloc_entry(struct auxtrace_cache *c);
411void auxtrace_cache__free_entry(struct auxtrace_cache *c, void *entry);
412int auxtrace_cache__add(struct auxtrace_cache *c, u32 key,
413 struct auxtrace_cache_entry *entry);
414void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key);
415
416struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist,
417 int *err);
418
419int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
420 struct record_opts *opts,
421 const char *str);
422int auxtrace_record__options(struct auxtrace_record *itr,
423 struct perf_evlist *evlist,
424 struct record_opts *opts);
425size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr);
426int auxtrace_record__info_fill(struct auxtrace_record *itr,
427 struct perf_session *session,
428 struct auxtrace_info_event *auxtrace_info,
429 size_t priv_size);
430void auxtrace_record__free(struct auxtrace_record *itr);
431int auxtrace_record__snapshot_start(struct auxtrace_record *itr);
432int auxtrace_record__snapshot_finish(struct auxtrace_record *itr);
433int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,
434 struct auxtrace_mmap *mm,
435 unsigned char *data, u64 *head, u64 *old);
436u64 auxtrace_record__reference(struct auxtrace_record *itr);
437
438int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event,
439 off_t file_offset);
440int auxtrace_index__write(int fd, struct list_head *head);
441int auxtrace_index__process(int fd, u64 size, struct perf_session *session,
442 bool needs_swap);
443void auxtrace_index__free(struct list_head *head);
444
445void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type,
446 int code, int cpu, pid_t pid, pid_t tid, u64 ip,
447 const char *msg);
448
449int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
450 struct perf_tool *tool,
451 struct perf_session *session,
452 perf_event__handler_t process);
453int perf_event__process_auxtrace_info(struct perf_tool *tool,
454 union perf_event *event,
455 struct perf_session *session);
456s64 perf_event__process_auxtrace(struct perf_tool *tool,
457 union perf_event *event,
458 struct perf_session *session);
459int perf_event__process_auxtrace_error(struct perf_tool *tool,
460 union perf_event *event,
461 struct perf_session *session);
462int itrace_parse_synth_opts(const struct option *opt, const char *str,
463 int unset);
464void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts);
465
466size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp);
467void perf_session__auxtrace_error_inc(struct perf_session *session,
468 union perf_event *event);
469void events_stats__auxtrace_error_warn(const struct events_stats *stats);
470
471static inline int auxtrace__process_event(struct perf_session *session,
472 union perf_event *event,
473 struct perf_sample *sample,
474 struct perf_tool *tool)
475{
476 if (!session->auxtrace)
477 return 0;
478
479 return session->auxtrace->process_event(session, event, sample, tool);
480}
481
482static inline int auxtrace__flush_events(struct perf_session *session,
483 struct perf_tool *tool)
484{
485 if (!session->auxtrace)
486 return 0;
487
488 return session->auxtrace->flush_events(session, tool);
489}
490
491static inline void auxtrace__free_events(struct perf_session *session)
492{
493 if (!session->auxtrace)
494 return;
495
496 return session->auxtrace->free_events(session);
497}
498
499static inline void auxtrace__free(struct perf_session *session)
500{
501 if (!session->auxtrace)
502 return;
503
504 return session->auxtrace->free(session);
505}
506
507#else
508
509static inline struct auxtrace_record *
510auxtrace_record__init(struct perf_evlist *evlist __maybe_unused,
511 int *err __maybe_unused)
512{
513 *err = 0;
514 return NULL;
515}
516
517static inline
518void auxtrace_record__free(struct auxtrace_record *itr __maybe_unused)
519{
520}
521
522static inline int
523perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr __maybe_unused,
524 struct perf_tool *tool __maybe_unused,
525 struct perf_session *session __maybe_unused,
526 perf_event__handler_t process __maybe_unused)
527{
528 return -EINVAL;
529}
530
531static inline
532int auxtrace_record__options(struct auxtrace_record *itr __maybe_unused,
533 struct perf_evlist *evlist __maybe_unused,
534 struct record_opts *opts __maybe_unused)
535{
536 return 0;
537}
538
539#define perf_event__process_auxtrace_info 0
540#define perf_event__process_auxtrace 0
541#define perf_event__process_auxtrace_error 0
542
543static inline
544void perf_session__auxtrace_error_inc(struct perf_session *session
545 __maybe_unused,
546 union perf_event *event
547 __maybe_unused)
548{
549}
550
551static inline
552void events_stats__auxtrace_error_warn(const struct events_stats *stats
553 __maybe_unused)
554{
555}
556
557static inline
558int itrace_parse_synth_opts(const struct option *opt __maybe_unused,
559 const char *str __maybe_unused,
560 int unset __maybe_unused)
561{
562 pr_err("AUX area tracing not supported\n");
563 return -EINVAL;
564}
565
566static inline
567int auxtrace_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused,
568 struct record_opts *opts __maybe_unused,
569 const char *str)
570{
571 if (!str)
572 return 0;
573 pr_err("AUX area tracing not supported\n");
574 return -EINVAL;
575}
576
577static inline
578int auxtrace__process_event(struct perf_session *session __maybe_unused,
579 union perf_event *event __maybe_unused,
580 struct perf_sample *sample __maybe_unused,
581 struct perf_tool *tool __maybe_unused)
582{
583 return 0;
584}
585
586static inline
587int auxtrace__flush_events(struct perf_session *session __maybe_unused,
588 struct perf_tool *tool __maybe_unused)
589{
590 return 0;
591}
592
593static inline
594void auxtrace__free_events(struct perf_session *session __maybe_unused)
595{
596}
597
598static inline
599void auxtrace_cache__free(struct auxtrace_cache *auxtrace_cache __maybe_unused)
600{
601}
602
603static inline
604void auxtrace__free(struct perf_session *session __maybe_unused)
605{
606}
607
608static inline
609int auxtrace_index__write(int fd __maybe_unused,
610 struct list_head *head __maybe_unused)
611{
612 return -EINVAL;
613}
614
615static inline
616int auxtrace_index__process(int fd __maybe_unused,
617 u64 size __maybe_unused,
618 struct perf_session *session __maybe_unused,
619 bool needs_swap __maybe_unused)
620{
621 return -EINVAL;
622}
623
624static inline
625void auxtrace_index__free(struct list_head *head __maybe_unused)
626{
627}
628
629int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
630 struct auxtrace_mmap_params *mp,
631 void *userpg, int fd);
632void auxtrace_mmap__munmap(struct auxtrace_mmap *mm);
633void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
634 off_t auxtrace_offset,
635 unsigned int auxtrace_pages,
636 bool auxtrace_overwrite);
637void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
638 struct perf_evlist *evlist, int idx,
639 bool per_cpu);
640
641#endif
642
643#endif
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 6033a0a212ca..679c2c6d8ade 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -72,6 +72,10 @@ extern struct callchain_param callchain_param;
72struct callchain_list { 72struct callchain_list {
73 u64 ip; 73 u64 ip;
74 struct map_symbol ms; 74 struct map_symbol ms;
75 struct /* for TUI */ {
76 bool unfolded;
77 bool has_children;
78 };
75 char *srcline; 79 char *srcline;
76 struct list_head list; 80 struct list_head list;
77}; 81};
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index dd17c9a32fbc..5bfc1198ab46 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -14,6 +14,7 @@
14#include <babeltrace/ctf-writer/event.h> 14#include <babeltrace/ctf-writer/event.h>
15#include <babeltrace/ctf-writer/event-types.h> 15#include <babeltrace/ctf-writer/event-types.h>
16#include <babeltrace/ctf-writer/event-fields.h> 16#include <babeltrace/ctf-writer/event-fields.h>
17#include <babeltrace/ctf-ir/utils.h>
17#include <babeltrace/ctf/events.h> 18#include <babeltrace/ctf/events.h>
18#include <traceevent/event-parse.h> 19#include <traceevent/event-parse.h>
19#include "asm/bug.h" 20#include "asm/bug.h"
@@ -38,12 +39,21 @@ struct evsel_priv {
38 struct bt_ctf_event_class *event_class; 39 struct bt_ctf_event_class *event_class;
39}; 40};
40 41
42#define MAX_CPUS 4096
43
44struct ctf_stream {
45 struct bt_ctf_stream *stream;
46 int cpu;
47 u32 count;
48};
49
41struct ctf_writer { 50struct ctf_writer {
42 /* writer primitives */ 51 /* writer primitives */
43 struct bt_ctf_writer *writer; 52 struct bt_ctf_writer *writer;
44 struct bt_ctf_stream *stream; 53 struct ctf_stream **stream;
45 struct bt_ctf_stream_class *stream_class; 54 int stream_cnt;
46 struct bt_ctf_clock *clock; 55 struct bt_ctf_stream_class *stream_class;
56 struct bt_ctf_clock *clock;
47 57
48 /* data types */ 58 /* data types */
49 union { 59 union {
@@ -65,6 +75,9 @@ struct convert {
65 75
66 u64 events_size; 76 u64 events_size;
67 u64 events_count; 77 u64 events_count;
78
79 /* Ordered events configured queue size. */
80 u64 queue_size;
68}; 81};
69 82
70static int value_set(struct bt_ctf_field_type *type, 83static int value_set(struct bt_ctf_field_type *type,
@@ -153,6 +166,43 @@ get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
153 return cw->data.u32; 166 return cw->data.u32;
154} 167}
155 168
169static unsigned long long adjust_signedness(unsigned long long value_int, int size)
170{
171 unsigned long long value_mask;
172
173 /*
174 * value_mask = (1 << (size * 8 - 1)) - 1.
175 * Directly set value_mask for code readers.
176 */
177 switch (size) {
178 case 1:
179 value_mask = 0x7fULL;
180 break;
181 case 2:
182 value_mask = 0x7fffULL;
183 break;
184 case 4:
185 value_mask = 0x7fffffffULL;
186 break;
187 case 8:
188 /*
189 * For 64 bit value, return it self. There is no need
190 * to fill high bit.
191 */
192 /* Fall through */
193 default:
194 /* BUG! */
195 return value_int;
196 }
197
198 /* If it is a positive value, don't adjust. */
199 if ((value_int & (~0ULL - value_mask)) == 0)
200 return value_int;
201
202 /* Fill upper part of value_int with 1 to make it a negative long long. */
203 return (value_int & value_mask) | ~value_mask;
204}
205
156static int add_tracepoint_field_value(struct ctf_writer *cw, 206static int add_tracepoint_field_value(struct ctf_writer *cw,
157 struct bt_ctf_event_class *event_class, 207 struct bt_ctf_event_class *event_class,
158 struct bt_ctf_event *event, 208 struct bt_ctf_event *event,
@@ -164,7 +214,6 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
164 struct bt_ctf_field *field; 214 struct bt_ctf_field *field;
165 const char *name = fmtf->name; 215 const char *name = fmtf->name;
166 void *data = sample->raw_data; 216 void *data = sample->raw_data;
167 unsigned long long value_int;
168 unsigned long flags = fmtf->flags; 217 unsigned long flags = fmtf->flags;
169 unsigned int n_items; 218 unsigned int n_items;
170 unsigned int i; 219 unsigned int i;
@@ -172,6 +221,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
172 unsigned int len; 221 unsigned int len;
173 int ret; 222 int ret;
174 223
224 name = fmtf->alias;
175 offset = fmtf->offset; 225 offset = fmtf->offset;
176 len = fmtf->size; 226 len = fmtf->size;
177 if (flags & FIELD_IS_STRING) 227 if (flags & FIELD_IS_STRING)
@@ -208,11 +258,6 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
208 type = get_tracepoint_field_type(cw, fmtf); 258 type = get_tracepoint_field_type(cw, fmtf);
209 259
210 for (i = 0; i < n_items; i++) { 260 for (i = 0; i < n_items; i++) {
211 if (!(flags & FIELD_IS_STRING))
212 value_int = pevent_read_number(
213 fmtf->event->pevent,
214 data + offset + i * len, len);
215
216 if (flags & FIELD_IS_ARRAY) 261 if (flags & FIELD_IS_ARRAY)
217 field = bt_ctf_field_array_get_field(array_field, i); 262 field = bt_ctf_field_array_get_field(array_field, i);
218 else 263 else
@@ -226,12 +271,21 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
226 if (flags & FIELD_IS_STRING) 271 if (flags & FIELD_IS_STRING)
227 ret = bt_ctf_field_string_set_value(field, 272 ret = bt_ctf_field_string_set_value(field,
228 data + offset + i * len); 273 data + offset + i * len);
229 else if (!(flags & FIELD_IS_SIGNED)) 274 else {
230 ret = bt_ctf_field_unsigned_integer_set_value( 275 unsigned long long value_int;
231 field, value_int); 276
232 else 277 value_int = pevent_read_number(
233 ret = bt_ctf_field_signed_integer_set_value( 278 fmtf->event->pevent,
234 field, value_int); 279 data + offset + i * len, len);
280
281 if (!(flags & FIELD_IS_SIGNED))
282 ret = bt_ctf_field_unsigned_integer_set_value(
283 field, value_int);
284 else
285 ret = bt_ctf_field_signed_integer_set_value(
286 field, adjust_signedness(value_int, len));
287 }
288
235 if (ret) { 289 if (ret) {
236 pr_err("failed to set file value %s\n", name); 290 pr_err("failed to set file value %s\n", name);
237 goto err_put_field; 291 goto err_put_field;
@@ -346,12 +400,6 @@ static int add_generic_values(struct ctf_writer *cw,
346 return -1; 400 return -1;
347 } 401 }
348 402
349 if (type & PERF_SAMPLE_CPU) {
350 ret = value_set_u32(cw, event, "perf_cpu", sample->cpu);
351 if (ret)
352 return -1;
353 }
354
355 if (type & PERF_SAMPLE_PERIOD) { 403 if (type & PERF_SAMPLE_PERIOD) {
356 ret = value_set_u64(cw, event, "perf_period", sample->period); 404 ret = value_set_u64(cw, event, "perf_period", sample->period);
357 if (ret) 405 if (ret)
@@ -381,6 +429,129 @@ static int add_generic_values(struct ctf_writer *cw,
381 return 0; 429 return 0;
382} 430}
383 431
432static int ctf_stream__flush(struct ctf_stream *cs)
433{
434 int err = 0;
435
436 if (cs) {
437 err = bt_ctf_stream_flush(cs->stream);
438 if (err)
439 pr_err("CTF stream %d flush failed\n", cs->cpu);
440
441 pr("Flush stream for cpu %d (%u samples)\n",
442 cs->cpu, cs->count);
443
444 cs->count = 0;
445 }
446
447 return err;
448}
449
450static struct ctf_stream *ctf_stream__create(struct ctf_writer *cw, int cpu)
451{
452 struct ctf_stream *cs;
453 struct bt_ctf_field *pkt_ctx = NULL;
454 struct bt_ctf_field *cpu_field = NULL;
455 struct bt_ctf_stream *stream = NULL;
456 int ret;
457
458 cs = zalloc(sizeof(*cs));
459 if (!cs) {
460 pr_err("Failed to allocate ctf stream\n");
461 return NULL;
462 }
463
464 stream = bt_ctf_writer_create_stream(cw->writer, cw->stream_class);
465 if (!stream) {
466 pr_err("Failed to create CTF stream\n");
467 goto out;
468 }
469
470 pkt_ctx = bt_ctf_stream_get_packet_context(stream);
471 if (!pkt_ctx) {
472 pr_err("Failed to obtain packet context\n");
473 goto out;
474 }
475
476 cpu_field = bt_ctf_field_structure_get_field(pkt_ctx, "cpu_id");
477 bt_ctf_field_put(pkt_ctx);
478 if (!cpu_field) {
479 pr_err("Failed to obtain cpu field\n");
480 goto out;
481 }
482
483 ret = bt_ctf_field_unsigned_integer_set_value(cpu_field, (u32) cpu);
484 if (ret) {
485 pr_err("Failed to update CPU number\n");
486 goto out;
487 }
488
489 bt_ctf_field_put(cpu_field);
490
491 cs->cpu = cpu;
492 cs->stream = stream;
493 return cs;
494
495out:
496 if (cpu_field)
497 bt_ctf_field_put(cpu_field);
498 if (stream)
499 bt_ctf_stream_put(stream);
500
501 free(cs);
502 return NULL;
503}
504
505static void ctf_stream__delete(struct ctf_stream *cs)
506{
507 if (cs) {
508 bt_ctf_stream_put(cs->stream);
509 free(cs);
510 }
511}
512
513static struct ctf_stream *ctf_stream(struct ctf_writer *cw, int cpu)
514{
515 struct ctf_stream *cs = cw->stream[cpu];
516
517 if (!cs) {
518 cs = ctf_stream__create(cw, cpu);
519 cw->stream[cpu] = cs;
520 }
521
522 return cs;
523}
524
525static int get_sample_cpu(struct ctf_writer *cw, struct perf_sample *sample,
526 struct perf_evsel *evsel)
527{
528 int cpu = 0;
529
530 if (evsel->attr.sample_type & PERF_SAMPLE_CPU)
531 cpu = sample->cpu;
532
533 if (cpu > cw->stream_cnt) {
534 pr_err("Event was recorded for CPU %d, limit is at %d.\n",
535 cpu, cw->stream_cnt);
536 cpu = 0;
537 }
538
539 return cpu;
540}
541
542#define STREAM_FLUSH_COUNT 100000
543
544/*
545 * Currently we have no other way to determine the
546 * time for the stream flush other than keep track
547 * of the number of events and check it against
548 * threshold.
549 */
550static bool is_flush_needed(struct ctf_stream *cs)
551{
552 return cs->count >= STREAM_FLUSH_COUNT;
553}
554
384static int process_sample_event(struct perf_tool *tool, 555static int process_sample_event(struct perf_tool *tool,
385 union perf_event *_event __maybe_unused, 556 union perf_event *_event __maybe_unused,
386 struct perf_sample *sample, 557 struct perf_sample *sample,
@@ -390,6 +561,7 @@ static int process_sample_event(struct perf_tool *tool,
390 struct convert *c = container_of(tool, struct convert, tool); 561 struct convert *c = container_of(tool, struct convert, tool);
391 struct evsel_priv *priv = evsel->priv; 562 struct evsel_priv *priv = evsel->priv;
392 struct ctf_writer *cw = &c->writer; 563 struct ctf_writer *cw = &c->writer;
564 struct ctf_stream *cs;
393 struct bt_ctf_event_class *event_class; 565 struct bt_ctf_event_class *event_class;
394 struct bt_ctf_event *event; 566 struct bt_ctf_event *event;
395 int ret; 567 int ret;
@@ -424,9 +596,93 @@ static int process_sample_event(struct perf_tool *tool,
424 return -1; 596 return -1;
425 } 597 }
426 598
427 bt_ctf_stream_append_event(cw->stream, event); 599 cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel));
600 if (cs) {
601 if (is_flush_needed(cs))
602 ctf_stream__flush(cs);
603
604 cs->count++;
605 bt_ctf_stream_append_event(cs->stream, event);
606 }
607
428 bt_ctf_event_put(event); 608 bt_ctf_event_put(event);
429 return 0; 609 return cs ? 0 : -1;
610}
611
612/* If dup < 0, add a prefix. Else, add _dupl_X suffix. */
613static char *change_name(char *name, char *orig_name, int dup)
614{
615 char *new_name = NULL;
616 size_t len;
617
618 if (!name)
619 name = orig_name;
620
621 if (dup >= 10)
622 goto out;
623 /*
624 * Add '_' prefix to potential keywork. According to
625 * Mathieu Desnoyers (https://lkml.org/lkml/2015/1/23/652),
626 * futher CTF spec updating may require us to use '$'.
627 */
628 if (dup < 0)
629 len = strlen(name) + sizeof("_");
630 else
631 len = strlen(orig_name) + sizeof("_dupl_X");
632
633 new_name = malloc(len);
634 if (!new_name)
635 goto out;
636
637 if (dup < 0)
638 snprintf(new_name, len, "_%s", name);
639 else
640 snprintf(new_name, len, "%s_dupl_%d", orig_name, dup);
641
642out:
643 if (name != orig_name)
644 free(name);
645 return new_name;
646}
647
648static int event_class_add_field(struct bt_ctf_event_class *event_class,
649 struct bt_ctf_field_type *type,
650 struct format_field *field)
651{
652 struct bt_ctf_field_type *t = NULL;
653 char *name;
654 int dup = 1;
655 int ret;
656
657 /* alias was already assigned */
658 if (field->alias != field->name)
659 return bt_ctf_event_class_add_field(event_class, type,
660 (char *)field->alias);
661
662 name = field->name;
663
664 /* If 'name' is a keywork, add prefix. */
665 if (bt_ctf_validate_identifier(name))
666 name = change_name(name, field->name, -1);
667
668 if (!name) {
669 pr_err("Failed to fix invalid identifier.");
670 return -1;
671 }
672 while ((t = bt_ctf_event_class_get_field_by_name(event_class, name))) {
673 bt_ctf_field_type_put(t);
674 name = change_name(name, field->name, dup++);
675 if (!name) {
676 pr_err("Failed to create dup name for '%s'\n", field->name);
677 return -1;
678 }
679 }
680
681 ret = bt_ctf_event_class_add_field(event_class, type, name);
682 if (!ret)
683 field->alias = name;
684
685 return ret;
430} 686}
431 687
432static int add_tracepoint_fields_types(struct ctf_writer *cw, 688static int add_tracepoint_fields_types(struct ctf_writer *cw,
@@ -457,14 +713,14 @@ static int add_tracepoint_fields_types(struct ctf_writer *cw,
457 if (flags & FIELD_IS_ARRAY) 713 if (flags & FIELD_IS_ARRAY)
458 type = bt_ctf_field_type_array_create(type, field->arraylen); 714 type = bt_ctf_field_type_array_create(type, field->arraylen);
459 715
460 ret = bt_ctf_event_class_add_field(event_class, type, 716 ret = event_class_add_field(event_class, type, field);
461 field->name);
462 717
463 if (flags & FIELD_IS_ARRAY) 718 if (flags & FIELD_IS_ARRAY)
464 bt_ctf_field_type_put(type); 719 bt_ctf_field_type_put(type);
465 720
466 if (ret) { 721 if (ret) {
467 pr_err("Failed to add field '%s\n", field->name); 722 pr_err("Failed to add field '%s': %d\n",
723 field->name, ret);
468 return -1; 724 return -1;
469 } 725 }
470 } 726 }
@@ -508,7 +764,7 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
508 do { \ 764 do { \
509 pr2(" field '%s'\n", n); \ 765 pr2(" field '%s'\n", n); \
510 if (bt_ctf_event_class_add_field(cl, t, n)) { \ 766 if (bt_ctf_event_class_add_field(cl, t, n)) { \
511 pr_err("Failed to add field '%s;\n", n); \ 767 pr_err("Failed to add field '%s';\n", n); \
512 return -1; \ 768 return -1; \
513 } \ 769 } \
514 } while (0) 770 } while (0)
@@ -528,9 +784,6 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
528 if (type & PERF_SAMPLE_STREAM_ID) 784 if (type & PERF_SAMPLE_STREAM_ID)
529 ADD_FIELD(event_class, cw->data.u64, "perf_stream_id"); 785 ADD_FIELD(event_class, cw->data.u64, "perf_stream_id");
530 786
531 if (type & PERF_SAMPLE_CPU)
532 ADD_FIELD(event_class, cw->data.u32, "perf_cpu");
533
534 if (type & PERF_SAMPLE_PERIOD) 787 if (type & PERF_SAMPLE_PERIOD)
535 ADD_FIELD(event_class, cw->data.u64, "perf_period"); 788 ADD_FIELD(event_class, cw->data.u64, "perf_period");
536 789
@@ -604,6 +857,39 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session)
604 return 0; 857 return 0;
605} 858}
606 859
860static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
861{
862 struct ctf_stream **stream;
863 struct perf_header *ph = &session->header;
864 int ncpus;
865
866 /*
867 * Try to get the number of cpus used in the data file,
868 * if not present fallback to the MAX_CPUS.
869 */
870 ncpus = ph->env.nr_cpus_avail ?: MAX_CPUS;
871
872 stream = zalloc(sizeof(*stream) * ncpus);
873 if (!stream) {
874 pr_err("Failed to allocate streams.\n");
875 return -ENOMEM;
876 }
877
878 cw->stream = stream;
879 cw->stream_cnt = ncpus;
880 return 0;
881}
882
883static void free_streams(struct ctf_writer *cw)
884{
885 int cpu;
886
887 for (cpu = 0; cpu < cw->stream_cnt; cpu++)
888 ctf_stream__delete(cw->stream[cpu]);
889
890 free(cw->stream);
891}
892
607static int ctf_writer__setup_env(struct ctf_writer *cw, 893static int ctf_writer__setup_env(struct ctf_writer *cw,
608 struct perf_session *session) 894 struct perf_session *session)
609{ 895{
@@ -713,7 +999,7 @@ static void ctf_writer__cleanup(struct ctf_writer *cw)
713 ctf_writer__cleanup_data(cw); 999 ctf_writer__cleanup_data(cw);
714 1000
715 bt_ctf_clock_put(cw->clock); 1001 bt_ctf_clock_put(cw->clock);
716 bt_ctf_stream_put(cw->stream); 1002 free_streams(cw);
717 bt_ctf_stream_class_put(cw->stream_class); 1003 bt_ctf_stream_class_put(cw->stream_class);
718 bt_ctf_writer_put(cw->writer); 1004 bt_ctf_writer_put(cw->writer);
719 1005
@@ -725,8 +1011,9 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path)
725{ 1011{
726 struct bt_ctf_writer *writer; 1012 struct bt_ctf_writer *writer;
727 struct bt_ctf_stream_class *stream_class; 1013 struct bt_ctf_stream_class *stream_class;
728 struct bt_ctf_stream *stream;
729 struct bt_ctf_clock *clock; 1014 struct bt_ctf_clock *clock;
1015 struct bt_ctf_field_type *pkt_ctx_type;
1016 int ret;
730 1017
731 /* CTF writer */ 1018 /* CTF writer */
732 writer = bt_ctf_writer_create(path); 1019 writer = bt_ctf_writer_create(path);
@@ -767,14 +1054,15 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path)
767 if (ctf_writer__init_data(cw)) 1054 if (ctf_writer__init_data(cw))
768 goto err_cleanup; 1055 goto err_cleanup;
769 1056
770 /* CTF stream instance */ 1057 /* Add cpu_id for packet context */
771 stream = bt_ctf_writer_create_stream(writer, stream_class); 1058 pkt_ctx_type = bt_ctf_stream_class_get_packet_context_type(stream_class);
772 if (!stream) { 1059 if (!pkt_ctx_type)
773 pr("Failed to create CTF stream.\n");
774 goto err_cleanup; 1060 goto err_cleanup;
775 }
776 1061
777 cw->stream = stream; 1062 ret = bt_ctf_field_type_structure_add_field(pkt_ctx_type, cw->data.u32, "cpu_id");
1063 bt_ctf_field_type_put(pkt_ctx_type);
1064 if (ret)
1065 goto err_cleanup;
778 1066
779 /* CTF clock writer setup */ 1067 /* CTF clock writer setup */
780 if (bt_ctf_writer_add_clock(writer, clock)) { 1068 if (bt_ctf_writer_add_clock(writer, clock)) {
@@ -791,6 +1079,28 @@ err:
791 return -1; 1079 return -1;
792} 1080}
793 1081
1082static int ctf_writer__flush_streams(struct ctf_writer *cw)
1083{
1084 int cpu, ret = 0;
1085
1086 for (cpu = 0; cpu < cw->stream_cnt && !ret; cpu++)
1087 ret = ctf_stream__flush(cw->stream[cpu]);
1088
1089 return ret;
1090}
1091
1092static int convert__config(const char *var, const char *value, void *cb)
1093{
1094 struct convert *c = cb;
1095
1096 if (!strcmp(var, "convert.queue-size")) {
1097 c->queue_size = perf_config_u64(var, value);
1098 return 0;
1099 }
1100
1101 return perf_default_config(var, value, cb);
1102}
1103
794int bt_convert__perf2ctf(const char *input, const char *path, bool force) 1104int bt_convert__perf2ctf(const char *input, const char *path, bool force)
795{ 1105{
796 struct perf_session *session; 1106 struct perf_session *session;
@@ -817,6 +1127,8 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
817 struct ctf_writer *cw = &c.writer; 1127 struct ctf_writer *cw = &c.writer;
818 int err = -1; 1128 int err = -1;
819 1129
1130 perf_config(convert__config, &c);
1131
820 /* CTF writer */ 1132 /* CTF writer */
821 if (ctf_writer__init(cw, path)) 1133 if (ctf_writer__init(cw, path))
822 return -1; 1134 return -1;
@@ -826,6 +1138,11 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
826 if (!session) 1138 if (!session)
827 goto free_writer; 1139 goto free_writer;
828 1140
1141 if (c.queue_size) {
1142 ordered_events__set_alloc_size(&session->ordered_events,
1143 c.queue_size);
1144 }
1145
829 /* CTF writer env/clock setup */ 1146 /* CTF writer env/clock setup */
830 if (ctf_writer__setup_env(cw, session)) 1147 if (ctf_writer__setup_env(cw, session))
831 goto free_session; 1148 goto free_session;
@@ -834,9 +1151,14 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
834 if (setup_events(cw, session)) 1151 if (setup_events(cw, session))
835 goto free_session; 1152 goto free_session;
836 1153
1154 if (setup_streams(cw, session))
1155 goto free_session;
1156
837 err = perf_session__process_events(session); 1157 err = perf_session__process_events(session);
838 if (!err) 1158 if (!err)
839 err = bt_ctf_stream_flush(cw->stream); 1159 err = ctf_writer__flush_streams(cw);
1160 else
1161 pr_err("Error during conversion.\n");
840 1162
841 fprintf(stderr, 1163 fprintf(stderr,
842 "[ perf data convert: Converted '%s' into CTF data '%s' ]\n", 1164 "[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
@@ -847,11 +1169,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
847 (double) c.events_size / 1024.0 / 1024.0, 1169 (double) c.events_size / 1024.0 / 1024.0,
848 c.events_count); 1170 c.events_count);
849 1171
850 /* its all good */
851free_session:
852 perf_session__delete(session); 1172 perf_session__delete(session);
1173 ctf_writer__cleanup(cw);
1174
1175 return err;
853 1176
1177free_session:
1178 perf_session__delete(session);
854free_writer: 1179free_writer:
855 ctf_writer__cleanup(cw); 1180 ctf_writer__cleanup(cw);
1181 pr_err("Error during conversion setup.\n");
856 return err; 1182 return err;
857} 1183}
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index fc0ddd5792a9..13d9ae0bd15c 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -4,6 +4,7 @@
4#include "symbol.h" 4#include "symbol.h"
5#include "dso.h" 5#include "dso.h"
6#include "machine.h" 6#include "machine.h"
7#include "auxtrace.h"
7#include "util.h" 8#include "util.h"
8#include "debug.h" 9#include "debug.h"
9 10
@@ -961,6 +962,7 @@ void dso__delete(struct dso *dso)
961 } 962 }
962 963
963 dso__data_close(dso); 964 dso__data_close(dso);
965 auxtrace_cache__free(dso->auxtrace_cache);
964 dso_cache__free(&dso->data.cache); 966 dso_cache__free(&dso->data.cache);
965 dso__free_a2l(dso); 967 dso__free_a2l(dso);
966 zfree(&dso->symsrc_filename); 968 zfree(&dso->symsrc_filename);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index e0901b4ed8de..3d79c749934c 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -126,6 +126,8 @@ struct dsos {
126 struct rb_root root; /* rbtree root sorted by long name */ 126 struct rb_root root; /* rbtree root sorted by long name */
127}; 127};
128 128
129struct auxtrace_cache;
130
129struct dso { 131struct dso {
130 struct list_head node; 132 struct list_head node;
131 struct rb_node rb_node; /* rbtree node sorted by long name */ 133 struct rb_node rb_node; /* rbtree node sorted by long name */
@@ -156,6 +158,7 @@ struct dso {
156 u16 long_name_len; 158 u16 long_name_len;
157 u16 short_name_len; 159 u16 short_name_len;
158 void *dwfl; /* DWARF debug info */ 160 void *dwfl; /* DWARF debug info */
161 struct auxtrace_cache *auxtrace_cache;
159 162
160 /* dso data file */ 163 /* dso data file */
161 struct { 164 struct {
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index ff866c4d2e2f..db526091f580 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -23,12 +23,17 @@ static const char *perf_event__names[] = {
23 [PERF_RECORD_FORK] = "FORK", 23 [PERF_RECORD_FORK] = "FORK",
24 [PERF_RECORD_READ] = "READ", 24 [PERF_RECORD_READ] = "READ",
25 [PERF_RECORD_SAMPLE] = "SAMPLE", 25 [PERF_RECORD_SAMPLE] = "SAMPLE",
26 [PERF_RECORD_AUX] = "AUX",
27 [PERF_RECORD_ITRACE_START] = "ITRACE_START",
26 [PERF_RECORD_HEADER_ATTR] = "ATTR", 28 [PERF_RECORD_HEADER_ATTR] = "ATTR",
27 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", 29 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
28 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", 30 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
29 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", 31 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
30 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", 32 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
31 [PERF_RECORD_ID_INDEX] = "ID_INDEX", 33 [PERF_RECORD_ID_INDEX] = "ID_INDEX",
34 [PERF_RECORD_AUXTRACE_INFO] = "AUXTRACE_INFO",
35 [PERF_RECORD_AUXTRACE] = "AUXTRACE",
36 [PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR",
32}; 37};
33 38
34const char *perf_event__name(unsigned int id) 39const char *perf_event__name(unsigned int id)
@@ -692,6 +697,22 @@ int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
692 return machine__process_lost_event(machine, event, sample); 697 return machine__process_lost_event(machine, event, sample);
693} 698}
694 699
700int perf_event__process_aux(struct perf_tool *tool __maybe_unused,
701 union perf_event *event,
702 struct perf_sample *sample __maybe_unused,
703 struct machine *machine)
704{
705 return machine__process_aux_event(machine, event);
706}
707
708int perf_event__process_itrace_start(struct perf_tool *tool __maybe_unused,
709 union perf_event *event,
710 struct perf_sample *sample __maybe_unused,
711 struct machine *machine)
712{
713 return machine__process_itrace_start_event(machine, event);
714}
715
695size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 716size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
696{ 717{
697 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", 718 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n",
@@ -755,6 +776,21 @@ int perf_event__process_exit(struct perf_tool *tool __maybe_unused,
755 return machine__process_exit_event(machine, event, sample); 776 return machine__process_exit_event(machine, event, sample);
756} 777}
757 778
779size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp)
780{
781 return fprintf(fp, " offset: %#"PRIx64" size: %#"PRIx64" flags: %#"PRIx64" [%s%s]\n",
782 event->aux.aux_offset, event->aux.aux_size,
783 event->aux.flags,
784 event->aux.flags & PERF_AUX_FLAG_TRUNCATED ? "T" : "",
785 event->aux.flags & PERF_AUX_FLAG_OVERWRITE ? "O" : "");
786}
787
788size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp)
789{
790 return fprintf(fp, " pid: %u tid: %u\n",
791 event->itrace_start.pid, event->itrace_start.tid);
792}
793
758size_t perf_event__fprintf(union perf_event *event, FILE *fp) 794size_t perf_event__fprintf(union perf_event *event, FILE *fp)
759{ 795{
760 size_t ret = fprintf(fp, "PERF_RECORD_%s", 796 size_t ret = fprintf(fp, "PERF_RECORD_%s",
@@ -774,6 +810,12 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
774 case PERF_RECORD_MMAP2: 810 case PERF_RECORD_MMAP2:
775 ret += perf_event__fprintf_mmap2(event, fp); 811 ret += perf_event__fprintf_mmap2(event, fp);
776 break; 812 break;
813 case PERF_RECORD_AUX:
814 ret += perf_event__fprintf_aux(event, fp);
815 break;
816 case PERF_RECORD_ITRACE_START:
817 ret += perf_event__fprintf_itrace_start(event, fp);
818 break;
777 default: 819 default:
778 ret += fprintf(fp, "\n"); 820 ret += fprintf(fp, "\n");
779 } 821 }
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 09b9e8d3fcf7..7eecd5e23d77 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -157,6 +157,8 @@ enum {
157 PERF_IP_FLAG_IN_TX = 1ULL << 10, 157 PERF_IP_FLAG_IN_TX = 1ULL << 10,
158}; 158};
159 159
160#define PERF_IP_FLAG_CHARS "bcrosyiABEx"
161
160#define PERF_BRANCH_MASK (\ 162#define PERF_BRANCH_MASK (\
161 PERF_IP_FLAG_BRANCH |\ 163 PERF_IP_FLAG_BRANCH |\
162 PERF_IP_FLAG_CALL |\ 164 PERF_IP_FLAG_CALL |\
@@ -215,9 +217,17 @@ enum perf_user_event_type { /* above any possible kernel type */
215 PERF_RECORD_HEADER_BUILD_ID = 67, 217 PERF_RECORD_HEADER_BUILD_ID = 67,
216 PERF_RECORD_FINISHED_ROUND = 68, 218 PERF_RECORD_FINISHED_ROUND = 68,
217 PERF_RECORD_ID_INDEX = 69, 219 PERF_RECORD_ID_INDEX = 69,
220 PERF_RECORD_AUXTRACE_INFO = 70,
221 PERF_RECORD_AUXTRACE = 71,
222 PERF_RECORD_AUXTRACE_ERROR = 72,
218 PERF_RECORD_HEADER_MAX 223 PERF_RECORD_HEADER_MAX
219}; 224};
220 225
226enum auxtrace_error_type {
227 PERF_AUXTRACE_ERROR_ITRACE = 1,
228 PERF_AUXTRACE_ERROR_MAX
229};
230
221/* 231/*
222 * The kernel collects the number of events it couldn't send in a stretch and 232 * The kernel collects the number of events it couldn't send in a stretch and
223 * when possible sends this number in a PERF_RECORD_LOST event. The number of 233 * when possible sends this number in a PERF_RECORD_LOST event. The number of
@@ -242,6 +252,7 @@ struct events_stats {
242 u32 nr_invalid_chains; 252 u32 nr_invalid_chains;
243 u32 nr_unknown_id; 253 u32 nr_unknown_id;
244 u32 nr_unprocessable_samples; 254 u32 nr_unprocessable_samples;
255 u32 nr_auxtrace_errors[PERF_AUXTRACE_ERROR_MAX];
245}; 256};
246 257
247struct attr_event { 258struct attr_event {
@@ -280,6 +291,50 @@ struct id_index_event {
280 struct id_index_entry entries[0]; 291 struct id_index_entry entries[0];
281}; 292};
282 293
294struct auxtrace_info_event {
295 struct perf_event_header header;
296 u32 type;
297 u32 reserved__; /* For alignment */
298 u64 priv[];
299};
300
301struct auxtrace_event {
302 struct perf_event_header header;
303 u64 size;
304 u64 offset;
305 u64 reference;
306 u32 idx;
307 u32 tid;
308 u32 cpu;
309 u32 reserved__; /* For alignment */
310};
311
312#define MAX_AUXTRACE_ERROR_MSG 64
313
314struct auxtrace_error_event {
315 struct perf_event_header header;
316 u32 type;
317 u32 code;
318 u32 cpu;
319 u32 pid;
320 u32 tid;
321 u32 reserved__; /* For alignment */
322 u64 ip;
323 char msg[MAX_AUXTRACE_ERROR_MSG];
324};
325
326struct aux_event {
327 struct perf_event_header header;
328 u64 aux_offset;
329 u64 aux_size;
330 u64 flags;
331};
332
333struct itrace_start_event {
334 struct perf_event_header header;
335 u32 pid, tid;
336};
337
283union perf_event { 338union perf_event {
284 struct perf_event_header header; 339 struct perf_event_header header;
285 struct mmap_event mmap; 340 struct mmap_event mmap;
@@ -295,6 +350,11 @@ union perf_event {
295 struct tracing_data_event tracing_data; 350 struct tracing_data_event tracing_data;
296 struct build_id_event build_id; 351 struct build_id_event build_id;
297 struct id_index_event id_index; 352 struct id_index_event id_index;
353 struct auxtrace_info_event auxtrace_info;
354 struct auxtrace_event auxtrace;
355 struct auxtrace_error_event auxtrace_error;
356 struct aux_event aux;
357 struct itrace_start_event itrace_start;
298}; 358};
299 359
300void perf_event__print_totals(void); 360void perf_event__print_totals(void);
@@ -330,6 +390,14 @@ int perf_event__process_lost(struct perf_tool *tool,
330 union perf_event *event, 390 union perf_event *event,
331 struct perf_sample *sample, 391 struct perf_sample *sample,
332 struct machine *machine); 392 struct machine *machine);
393int perf_event__process_aux(struct perf_tool *tool,
394 union perf_event *event,
395 struct perf_sample *sample,
396 struct machine *machine);
397int perf_event__process_itrace_start(struct perf_tool *tool,
398 union perf_event *event,
399 struct perf_sample *sample,
400 struct machine *machine);
333int perf_event__process_mmap(struct perf_tool *tool, 401int perf_event__process_mmap(struct perf_tool *tool,
334 union perf_event *event, 402 union perf_event *event,
335 struct perf_sample *sample, 403 struct perf_sample *sample,
@@ -387,6 +455,8 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
387size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); 455size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
388size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); 456size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
389size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); 457size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
458size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp);
459size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
390size_t perf_event__fprintf(union perf_event *event, FILE *fp); 460size_t perf_event__fprintf(union perf_event *event, FILE *fp);
391 461
392u64 kallsyms__get_function_start(const char *kallsyms_filename, 462u64 kallsyms__get_function_start(const char *kallsyms_filename,
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 080be93eea96..7ec1bf93ab28 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -695,7 +695,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
695 695
696static bool perf_mmap__empty(struct perf_mmap *md) 696static bool perf_mmap__empty(struct perf_mmap *md)
697{ 697{
698 return perf_mmap__read_head(md) == md->prev; 698 return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base;
699} 699}
700 700
701static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) 701static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx)
@@ -725,6 +725,34 @@ void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
725 perf_evlist__mmap_put(evlist, idx); 725 perf_evlist__mmap_put(evlist, idx);
726} 726}
727 727
728int __weak auxtrace_mmap__mmap(struct auxtrace_mmap *mm __maybe_unused,
729 struct auxtrace_mmap_params *mp __maybe_unused,
730 void *userpg __maybe_unused,
731 int fd __maybe_unused)
732{
733 return 0;
734}
735
736void __weak auxtrace_mmap__munmap(struct auxtrace_mmap *mm __maybe_unused)
737{
738}
739
740void __weak auxtrace_mmap_params__init(
741 struct auxtrace_mmap_params *mp __maybe_unused,
742 off_t auxtrace_offset __maybe_unused,
743 unsigned int auxtrace_pages __maybe_unused,
744 bool auxtrace_overwrite __maybe_unused)
745{
746}
747
748void __weak auxtrace_mmap_params__set_idx(
749 struct auxtrace_mmap_params *mp __maybe_unused,
750 struct perf_evlist *evlist __maybe_unused,
751 int idx __maybe_unused,
752 bool per_cpu __maybe_unused)
753{
754}
755
728static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) 756static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
729{ 757{
730 if (evlist->mmap[idx].base != NULL) { 758 if (evlist->mmap[idx].base != NULL) {
@@ -732,6 +760,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
732 evlist->mmap[idx].base = NULL; 760 evlist->mmap[idx].base = NULL;
733 evlist->mmap[idx].refcnt = 0; 761 evlist->mmap[idx].refcnt = 0;
734 } 762 }
763 auxtrace_mmap__munmap(&evlist->mmap[idx].auxtrace_mmap);
735} 764}
736 765
737void perf_evlist__munmap(struct perf_evlist *evlist) 766void perf_evlist__munmap(struct perf_evlist *evlist)
@@ -759,6 +788,7 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
759struct mmap_params { 788struct mmap_params {
760 int prot; 789 int prot;
761 int mask; 790 int mask;
791 struct auxtrace_mmap_params auxtrace_mp;
762}; 792};
763 793
764static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, 794static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
@@ -789,6 +819,10 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
789 return -1; 819 return -1;
790 } 820 }
791 821
822 if (auxtrace_mmap__mmap(&evlist->mmap[idx].auxtrace_mmap,
823 &mp->auxtrace_mp, evlist->mmap[idx].base, fd))
824 return -1;
825
792 return 0; 826 return 0;
793} 827}
794 828
@@ -853,6 +887,9 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
853 for (cpu = 0; cpu < nr_cpus; cpu++) { 887 for (cpu = 0; cpu < nr_cpus; cpu++) {
854 int output = -1; 888 int output = -1;
855 889
890 auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, cpu,
891 true);
892
856 for (thread = 0; thread < nr_threads; thread++) { 893 for (thread = 0; thread < nr_threads; thread++) {
857 if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu, 894 if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
858 thread, &output)) 895 thread, &output))
@@ -878,6 +915,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
878 for (thread = 0; thread < nr_threads; thread++) { 915 for (thread = 0; thread < nr_threads; thread++) {
879 int output = -1; 916 int output = -1;
880 917
918 auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, thread,
919 false);
920
881 if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, 921 if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
882 &output)) 922 &output))
883 goto out_unmap; 923 goto out_unmap;
@@ -960,10 +1000,8 @@ static long parse_pages_arg(const char *str, unsigned long min,
960 return pages; 1000 return pages;
961} 1001}
962 1002
963int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, 1003int __perf_evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str)
964 int unset __maybe_unused)
965{ 1004{
966 unsigned int *mmap_pages = opt->value;
967 unsigned long max = UINT_MAX; 1005 unsigned long max = UINT_MAX;
968 long pages; 1006 long pages;
969 1007
@@ -980,20 +1018,32 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
980 return 0; 1018 return 0;
981} 1019}
982 1020
1021int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
1022 int unset __maybe_unused)
1023{
1024 return __perf_evlist__parse_mmap_pages(opt->value, str);
1025}
1026
983/** 1027/**
984 * perf_evlist__mmap - Create mmaps to receive events. 1028 * perf_evlist__mmap_ex - Create mmaps to receive events.
985 * @evlist: list of events 1029 * @evlist: list of events
986 * @pages: map length in pages 1030 * @pages: map length in pages
987 * @overwrite: overwrite older events? 1031 * @overwrite: overwrite older events?
1032 * @auxtrace_pages - auxtrace map length in pages
1033 * @auxtrace_overwrite - overwrite older auxtrace data?
988 * 1034 *
989 * If @overwrite is %false the user needs to signal event consumption using 1035 * If @overwrite is %false the user needs to signal event consumption using
990 * perf_mmap__write_tail(). Using perf_evlist__mmap_read() does this 1036 * perf_mmap__write_tail(). Using perf_evlist__mmap_read() does this
991 * automatically. 1037 * automatically.
992 * 1038 *
1039 * Similarly, if @auxtrace_overwrite is %false the user needs to signal data
1040 * consumption using auxtrace_mmap__write_tail().
1041 *
993 * Return: %0 on success, negative error code otherwise. 1042 * Return: %0 on success, negative error code otherwise.
994 */ 1043 */
995int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 1044int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,
996 bool overwrite) 1045 bool overwrite, unsigned int auxtrace_pages,
1046 bool auxtrace_overwrite)
997{ 1047{
998 struct perf_evsel *evsel; 1048 struct perf_evsel *evsel;
999 const struct cpu_map *cpus = evlist->cpus; 1049 const struct cpu_map *cpus = evlist->cpus;
@@ -1013,6 +1063,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
1013 pr_debug("mmap size %zuB\n", evlist->mmap_len); 1063 pr_debug("mmap size %zuB\n", evlist->mmap_len);
1014 mp.mask = evlist->mmap_len - page_size - 1; 1064 mp.mask = evlist->mmap_len - page_size - 1;
1015 1065
1066 auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->mmap_len,
1067 auxtrace_pages, auxtrace_overwrite);
1068
1016 evlist__for_each(evlist, evsel) { 1069 evlist__for_each(evlist, evsel) {
1017 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 1070 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
1018 evsel->sample_id == NULL && 1071 evsel->sample_id == NULL &&
@@ -1026,6 +1079,12 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
1026 return perf_evlist__mmap_per_cpu(evlist, &mp); 1079 return perf_evlist__mmap_per_cpu(evlist, &mp);
1027} 1080}
1028 1081
1082int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
1083 bool overwrite)
1084{
1085 return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false);
1086}
1087
1029int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) 1088int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
1030{ 1089{
1031 evlist->threads = thread_map__new_str(target->pid, target->tid, 1090 evlist->threads = thread_map__new_str(target->pid, target->tid,
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index b5cce95d644e..c07b1a94a724 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -8,6 +8,7 @@
8#include "event.h" 8#include "event.h"
9#include "evsel.h" 9#include "evsel.h"
10#include "util.h" 10#include "util.h"
11#include "auxtrace.h"
11#include <unistd.h> 12#include <unistd.h>
12 13
13struct pollfd; 14struct pollfd;
@@ -28,6 +29,7 @@ struct perf_mmap {
28 int mask; 29 int mask;
29 int refcnt; 30 int refcnt;
30 u64 prev; 31 u64 prev;
32 struct auxtrace_mmap auxtrace_mmap;
31 char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); 33 char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
32}; 34};
33 35
@@ -122,10 +124,14 @@ int perf_evlist__start_workload(struct perf_evlist *evlist);
122 124
123struct option; 125struct option;
124 126
127int __perf_evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str);
125int perf_evlist__parse_mmap_pages(const struct option *opt, 128int perf_evlist__parse_mmap_pages(const struct option *opt,
126 const char *str, 129 const char *str,
127 int unset); 130 int unset);
128 131
132int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,
133 bool overwrite, unsigned int auxtrace_pages,
134 bool auxtrace_overwrite);
129int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 135int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
130 bool overwrite); 136 bool overwrite);
131void perf_evlist__munmap(struct perf_evlist *evlist); 137void perf_evlist__munmap(struct perf_evlist *evlist);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 33e3fd8c2e68..c886b9f7a48d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1121,6 +1121,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,
1121 PRINT_ATTRf(sample_stack_user, p_unsigned); 1121 PRINT_ATTRf(sample_stack_user, p_unsigned);
1122 PRINT_ATTRf(clockid, p_signed); 1122 PRINT_ATTRf(clockid, p_signed);
1123 PRINT_ATTRf(sample_regs_intr, p_hex); 1123 PRINT_ATTRf(sample_regs_intr, p_hex);
1124 PRINT_ATTRf(aux_watermark, p_unsigned);
1124 1125
1125 return ret; 1126 return ret;
1126} 1127}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 918fd8ae2d80..3f0d809d853a 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -869,6 +869,20 @@ static int write_branch_stack(int fd __maybe_unused,
869 return 0; 869 return 0;
870} 870}
871 871
872static int write_auxtrace(int fd, struct perf_header *h,
873 struct perf_evlist *evlist __maybe_unused)
874{
875 struct perf_session *session;
876 int err;
877
878 session = container_of(h, struct perf_session, header);
879
880 err = auxtrace_index__write(fd, &session->auxtrace_index);
881 if (err < 0)
882 pr_err("Failed to write auxtrace index\n");
883 return err;
884}
885
872static void print_hostname(struct perf_header *ph, int fd __maybe_unused, 886static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
873 FILE *fp) 887 FILE *fp)
874{ 888{
@@ -1151,6 +1165,12 @@ static void print_branch_stack(struct perf_header *ph __maybe_unused,
1151 fprintf(fp, "# contains samples with branch stack\n"); 1165 fprintf(fp, "# contains samples with branch stack\n");
1152} 1166}
1153 1167
1168static void print_auxtrace(struct perf_header *ph __maybe_unused,
1169 int fd __maybe_unused, FILE *fp)
1170{
1171 fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n");
1172}
1173
1154static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, 1174static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
1155 FILE *fp) 1175 FILE *fp)
1156{ 1176{
@@ -1821,6 +1841,22 @@ out_free:
1821 return ret; 1841 return ret;
1822} 1842}
1823 1843
1844static int process_auxtrace(struct perf_file_section *section,
1845 struct perf_header *ph, int fd,
1846 void *data __maybe_unused)
1847{
1848 struct perf_session *session;
1849 int err;
1850
1851 session = container_of(ph, struct perf_session, header);
1852
1853 err = auxtrace_index__process(fd, section->size, session,
1854 ph->needs_swap);
1855 if (err < 0)
1856 pr_err("Failed to process auxtrace index\n");
1857 return err;
1858}
1859
1824struct feature_ops { 1860struct feature_ops {
1825 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 1861 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1826 void (*print)(struct perf_header *h, int fd, FILE *fp); 1862 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1861,6 +1897,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1861 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), 1897 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
1862 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), 1898 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
1863 FEAT_OPP(HEADER_GROUP_DESC, group_desc), 1899 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1900 FEAT_OPP(HEADER_AUXTRACE, auxtrace),
1864}; 1901};
1865 1902
1866struct header_print_data { 1903struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 3bb90ac172a1..d4d57962c591 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -30,6 +30,7 @@ enum {
30 HEADER_BRANCH_STACK, 30 HEADER_BRANCH_STACK,
31 HEADER_PMU_MAPPINGS, 31 HEADER_PMU_MAPPINGS,
32 HEADER_GROUP_DESC, 32 HEADER_GROUP_DESC,
33 HEADER_AUXTRACE,
33 HEADER_LAST_FEATURE, 34 HEADER_LAST_FEATURE,
34 HEADER_FEAT_BITS = 256, 35 HEADER_FEAT_BITS = 256,
35}; 36};
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index cc22b9158b93..338770679863 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1163,7 +1163,7 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
1163 return; 1163 return;
1164 1164
1165 /* force fold unfiltered entry for simplicity */ 1165 /* force fold unfiltered entry for simplicity */
1166 h->ms.unfolded = false; 1166 h->unfolded = false;
1167 h->row_offset = 0; 1167 h->row_offset = 0;
1168 h->nr_rows = 0; 1168 h->nr_rows = 0;
1169 1169
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 527e032e24f6..2f471105efb1 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -486,6 +486,22 @@ machine__module_dso(struct machine *machine, struct kmod_path *m,
486 return dso; 486 return dso;
487} 487}
488 488
489int machine__process_aux_event(struct machine *machine __maybe_unused,
490 union perf_event *event)
491{
492 if (dump_trace)
493 perf_event__fprintf_aux(event, stdout);
494 return 0;
495}
496
497int machine__process_itrace_start_event(struct machine *machine __maybe_unused,
498 union perf_event *event)
499{
500 if (dump_trace)
501 perf_event__fprintf_itrace_start(event, stdout);
502 return 0;
503}
504
489struct map *machine__new_module(struct machine *machine, u64 start, 505struct map *machine__new_module(struct machine *machine, u64 start,
490 const char *filename) 506 const char *filename)
491{ 507{
@@ -1331,6 +1347,11 @@ int machine__process_event(struct machine *machine, union perf_event *event,
1331 ret = machine__process_exit_event(machine, event, sample); break; 1347 ret = machine__process_exit_event(machine, event, sample); break;
1332 case PERF_RECORD_LOST: 1348 case PERF_RECORD_LOST:
1333 ret = machine__process_lost_event(machine, event, sample); break; 1349 ret = machine__process_lost_event(machine, event, sample); break;
1350 case PERF_RECORD_AUX:
1351 ret = machine__process_aux_event(machine, event); break;
1352 case PERF_RECORD_ITRACE_START:
1353 ret = machine__process_itrace_start_event(machine, event);
1354 break;
1334 default: 1355 default:
1335 ret = -1; 1356 ret = -1;
1336 break; 1357 break;
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 6d64cedb9d1e..1d992961d5d1 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -81,6 +81,10 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
81 struct perf_sample *sample); 81 struct perf_sample *sample);
82int machine__process_lost_event(struct machine *machine, union perf_event *event, 82int machine__process_lost_event(struct machine *machine, union perf_event *event,
83 struct perf_sample *sample); 83 struct perf_sample *sample);
84int machine__process_aux_event(struct machine *machine,
85 union perf_event *event);
86int machine__process_itrace_start_event(struct machine *machine,
87 union perf_event *event);
84int machine__process_mmap_event(struct machine *machine, union perf_event *event, 88int machine__process_mmap_event(struct machine *machine, union perf_event *event,
85 struct perf_sample *sample); 89 struct perf_sample *sample);
86int machine__process_mmap2_event(struct machine *machine, union perf_event *event, 90int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index a14f08f41686..cd0e335008b4 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -292,6 +292,11 @@ int map__load(struct map *map, symbol_filter_t filter)
292 return 0; 292 return 0;
293} 293}
294 294
295int __weak arch__compare_symbol_names(const char *namea, const char *nameb)
296{
297 return strcmp(namea, nameb);
298}
299
295struct symbol *map__find_symbol(struct map *map, u64 addr, 300struct symbol *map__find_symbol(struct map *map, u64 addr,
296 symbol_filter_t filter) 301 symbol_filter_t filter)
297{ 302{
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index ec19c59ca38e..4e0c729841ab 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -124,7 +124,7 @@ struct thread;
124 */ 124 */
125#define __map__for_each_symbol_by_name(map, sym_name, pos, filter) \ 125#define __map__for_each_symbol_by_name(map, sym_name, pos, filter) \
126 for (pos = map__find_symbol_by_name(map, sym_name, filter); \ 126 for (pos = map__find_symbol_by_name(map, sym_name, filter); \
127 pos && strcmp(pos->name, sym_name) == 0; \ 127 pos && arch__compare_symbol_names(pos->name, sym_name) == 0; \
128 pos = symbol__next_by_name(pos)) 128 pos = symbol__next_by_name(pos))
129 129
130#define map__for_each_symbol_by_name(map, sym_name, pos) \ 130#define map__for_each_symbol_by_name(map, sym_name, pos) \
@@ -132,6 +132,7 @@ struct thread;
132 132
133typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 133typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
134 134
135int arch__compare_symbol_names(const char *namea, const char *nameb);
135void map__init(struct map *map, enum map_type type, 136void map__init(struct map *map, enum map_type type,
136 u64 start, u64 end, u64 pgoff, struct dso *dso); 137 u64 start, u64 end, u64 pgoff, struct dso *dso);
137struct map *map__new(struct machine *machine, u64 start, u64 len, 138struct map *map__new(struct machine *machine, u64 start, u64 len,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index be0655388b38..80a50fdb6d8a 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -17,6 +17,7 @@
17#include "parse-events-flex.h" 17#include "parse-events-flex.h"
18#include "pmu.h" 18#include "pmu.h"
19#include "thread_map.h" 19#include "thread_map.h"
20#include "asm/bug.h"
20 21
21#define MAX_NAME_LEN 100 22#define MAX_NAME_LEN 100
22 23
@@ -24,6 +25,12 @@
24extern int parse_events_debug; 25extern int parse_events_debug;
25#endif 26#endif
26int parse_events_parse(void *data, void *scanner); 27int parse_events_parse(void *data, void *scanner);
28int parse_events_term__num(struct parse_events_term **term,
29 int type_term, char *config, u64 num,
30 YYLTYPE *loc_term, YYLTYPE *loc_val);
31int parse_events_term__str(struct parse_events_term **term,
32 int type_term, char *config, char *str,
33 YYLTYPE *loc_term, YYLTYPE *loc_val);
27 34
28static struct perf_pmu_event_symbol *perf_pmu_events_list; 35static struct perf_pmu_event_symbol *perf_pmu_events_list;
29/* 36/*
@@ -538,16 +545,40 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
538 return add_event(list, idx, &attr, NULL); 545 return add_event(list, idx, &attr, NULL);
539} 546}
540 547
548static int check_type_val(struct parse_events_term *term,
549 struct parse_events_error *err,
550 int type)
551{
552 if (type == term->type_val)
553 return 0;
554
555 if (err) {
556 err->idx = term->err_val;
557 if (type == PARSE_EVENTS__TERM_TYPE_NUM)
558 err->str = strdup("expected numeric value");
559 else
560 err->str = strdup("expected string value");
561 }
562 return -EINVAL;
563}
564
541static int config_term(struct perf_event_attr *attr, 565static int config_term(struct perf_event_attr *attr,
542 struct parse_events_term *term) 566 struct parse_events_term *term,
567 struct parse_events_error *err)
543{ 568{
544#define CHECK_TYPE_VAL(type) \ 569#define CHECK_TYPE_VAL(type) \
545do { \ 570do { \
546 if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val) \ 571 if (check_type_val(term, err, PARSE_EVENTS__TERM_TYPE_ ## type)) \
547 return -EINVAL; \ 572 return -EINVAL; \
548} while (0) 573} while (0)
549 574
550 switch (term->type_term) { 575 switch (term->type_term) {
576 case PARSE_EVENTS__TERM_TYPE_USER:
577 /*
578 * Always succeed for sysfs terms, as we dont know
579 * at this point what type they need to have.
580 */
581 return 0;
551 case PARSE_EVENTS__TERM_TYPE_CONFIG: 582 case PARSE_EVENTS__TERM_TYPE_CONFIG:
552 CHECK_TYPE_VAL(NUM); 583 CHECK_TYPE_VAL(NUM);
553 attr->config = term->val.num; 584 attr->config = term->val.num;
@@ -582,18 +613,20 @@ do { \
582} 613}
583 614
584static int config_attr(struct perf_event_attr *attr, 615static int config_attr(struct perf_event_attr *attr,
585 struct list_head *head, int fail) 616 struct list_head *head,
617 struct parse_events_error *err)
586{ 618{
587 struct parse_events_term *term; 619 struct parse_events_term *term;
588 620
589 list_for_each_entry(term, head, list) 621 list_for_each_entry(term, head, list)
590 if (config_term(attr, term) && fail) 622 if (config_term(attr, term, err))
591 return -EINVAL; 623 return -EINVAL;
592 624
593 return 0; 625 return 0;
594} 626}
595 627
596int parse_events_add_numeric(struct list_head *list, int *idx, 628int parse_events_add_numeric(struct parse_events_evlist *data,
629 struct list_head *list,
597 u32 type, u64 config, 630 u32 type, u64 config,
598 struct list_head *head_config) 631 struct list_head *head_config)
599{ 632{
@@ -604,10 +637,10 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
604 attr.config = config; 637 attr.config = config;
605 638
606 if (head_config && 639 if (head_config &&
607 config_attr(&attr, head_config, 1)) 640 config_attr(&attr, head_config, data->error))
608 return -EINVAL; 641 return -EINVAL;
609 642
610 return add_event(list, idx, &attr, NULL); 643 return add_event(list, &data->idx, &attr, NULL);
611} 644}
612 645
613static int parse_events__is_name_term(struct parse_events_term *term) 646static int parse_events__is_name_term(struct parse_events_term *term)
@@ -626,8 +659,9 @@ static char *pmu_event_name(struct list_head *head_terms)
626 return NULL; 659 return NULL;
627} 660}
628 661
629int parse_events_add_pmu(struct list_head *list, int *idx, 662int parse_events_add_pmu(struct parse_events_evlist *data,
630 char *name, struct list_head *head_config) 663 struct list_head *list, char *name,
664 struct list_head *head_config)
631{ 665{
632 struct perf_event_attr attr; 666 struct perf_event_attr attr;
633 struct perf_pmu_info info; 667 struct perf_pmu_info info;
@@ -647,7 +681,7 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
647 681
648 if (!head_config) { 682 if (!head_config) {
649 attr.type = pmu->type; 683 attr.type = pmu->type;
650 evsel = __add_event(list, idx, &attr, NULL, pmu->cpus); 684 evsel = __add_event(list, &data->idx, &attr, NULL, pmu->cpus);
651 return evsel ? 0 : -ENOMEM; 685 return evsel ? 0 : -ENOMEM;
652 } 686 }
653 687
@@ -658,13 +692,14 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
658 * Configure hardcoded terms first, no need to check 692 * Configure hardcoded terms first, no need to check
659 * return value when called with fail == 0 ;) 693 * return value when called with fail == 0 ;)
660 */ 694 */
661 config_attr(&attr, head_config, 0); 695 if (config_attr(&attr, head_config, data->error))
696 return -EINVAL;
662 697
663 if (perf_pmu__config(pmu, &attr, head_config)) 698 if (perf_pmu__config(pmu, &attr, head_config, data->error))
664 return -EINVAL; 699 return -EINVAL;
665 700
666 evsel = __add_event(list, idx, &attr, pmu_event_name(head_config), 701 evsel = __add_event(list, &data->idx, &attr,
667 pmu->cpus); 702 pmu_event_name(head_config), pmu->cpus);
668 if (evsel) { 703 if (evsel) {
669 evsel->unit = info.unit; 704 evsel->unit = info.unit;
670 evsel->scale = info.scale; 705 evsel->scale = info.scale;
@@ -1019,11 +1054,13 @@ int parse_events_terms(struct list_head *terms, const char *str)
1019 return ret; 1054 return ret;
1020} 1055}
1021 1056
1022int parse_events(struct perf_evlist *evlist, const char *str) 1057int parse_events(struct perf_evlist *evlist, const char *str,
1058 struct parse_events_error *err)
1023{ 1059{
1024 struct parse_events_evlist data = { 1060 struct parse_events_evlist data = {
1025 .list = LIST_HEAD_INIT(data.list), 1061 .list = LIST_HEAD_INIT(data.list),
1026 .idx = evlist->nr_entries, 1062 .idx = evlist->nr_entries,
1063 .error = err,
1027 }; 1064 };
1028 int ret; 1065 int ret;
1029 1066
@@ -1044,16 +1081,87 @@ int parse_events(struct perf_evlist *evlist, const char *str)
1044 return ret; 1081 return ret;
1045} 1082}
1046 1083
1084#define MAX_WIDTH 1000
1085static int get_term_width(void)
1086{
1087 struct winsize ws;
1088
1089 get_term_dimensions(&ws);
1090 return ws.ws_col > MAX_WIDTH ? MAX_WIDTH : ws.ws_col;
1091}
1092
1093static void parse_events_print_error(struct parse_events_error *err,
1094 const char *event)
1095{
1096 const char *str = "invalid or unsupported event: ";
1097 char _buf[MAX_WIDTH];
1098 char *buf = (char *) event;
1099 int idx = 0;
1100
1101 if (err->str) {
1102 /* -2 for extra '' in the final fprintf */
1103 int width = get_term_width() - 2;
1104 int len_event = strlen(event);
1105 int len_str, max_len, cut = 0;
1106
1107 /*
1108 * Maximum error index indent, we will cut
1109 * the event string if it's bigger.
1110 */
1111 int max_err_idx = 10;
1112
1113 /*
1114 * Let's be specific with the message when
1115 * we have the precise error.
1116 */
1117 str = "event syntax error: ";
1118 len_str = strlen(str);
1119 max_len = width - len_str;
1120
1121 buf = _buf;
1122
1123 /* We're cutting from the beggining. */
1124 if (err->idx > max_err_idx)
1125 cut = err->idx - max_err_idx;
1126
1127 strncpy(buf, event + cut, max_len);
1128
1129 /* Mark cut parts with '..' on both sides. */
1130 if (cut)
1131 buf[0] = buf[1] = '.';
1132
1133 if ((len_event - cut) > max_len) {
1134 buf[max_len - 1] = buf[max_len - 2] = '.';
1135 buf[max_len] = 0;
1136 }
1137
1138 idx = len_str + err->idx - cut;
1139 }
1140
1141 fprintf(stderr, "%s'%s'\n", str, buf);
1142 if (idx) {
1143 fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err->str);
1144 if (err->help)
1145 fprintf(stderr, "\n%s\n", err->help);
1146 free(err->str);
1147 free(err->help);
1148 }
1149
1150 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
1151}
1152
1153#undef MAX_WIDTH
1154
1047int parse_events_option(const struct option *opt, const char *str, 1155int parse_events_option(const struct option *opt, const char *str,
1048 int unset __maybe_unused) 1156 int unset __maybe_unused)
1049{ 1157{
1050 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 1158 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
1051 int ret = parse_events(evlist, str); 1159 struct parse_events_error err = { .idx = 0, };
1160 int ret = parse_events(evlist, str, &err);
1161
1162 if (ret)
1163 parse_events_print_error(&err, str);
1052 1164
1053 if (ret) {
1054 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
1055 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
1056 }
1057 return ret; 1165 return ret;
1058} 1166}
1059 1167
@@ -1460,7 +1568,7 @@ int parse_events__is_hardcoded_term(struct parse_events_term *term)
1460 1568
1461static int new_term(struct parse_events_term **_term, int type_val, 1569static int new_term(struct parse_events_term **_term, int type_val,
1462 int type_term, char *config, 1570 int type_term, char *config,
1463 char *str, u64 num) 1571 char *str, u64 num, int err_term, int err_val)
1464{ 1572{
1465 struct parse_events_term *term; 1573 struct parse_events_term *term;
1466 1574
@@ -1472,6 +1580,8 @@ static int new_term(struct parse_events_term **_term, int type_val,
1472 term->type_val = type_val; 1580 term->type_val = type_val;
1473 term->type_term = type_term; 1581 term->type_term = type_term;
1474 term->config = config; 1582 term->config = config;
1583 term->err_term = err_term;
1584 term->err_val = err_val;
1475 1585
1476 switch (type_val) { 1586 switch (type_val) {
1477 case PARSE_EVENTS__TERM_TYPE_NUM: 1587 case PARSE_EVENTS__TERM_TYPE_NUM:
@@ -1490,17 +1600,23 @@ static int new_term(struct parse_events_term **_term, int type_val,
1490} 1600}
1491 1601
1492int parse_events_term__num(struct parse_events_term **term, 1602int parse_events_term__num(struct parse_events_term **term,
1493 int type_term, char *config, u64 num) 1603 int type_term, char *config, u64 num,
1604 YYLTYPE *loc_term, YYLTYPE *loc_val)
1494{ 1605{
1495 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, 1606 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1496 config, NULL, num); 1607 config, NULL, num,
1608 loc_term ? loc_term->first_column : 0,
1609 loc_val ? loc_val->first_column : 0);
1497} 1610}
1498 1611
1499int parse_events_term__str(struct parse_events_term **term, 1612int parse_events_term__str(struct parse_events_term **term,
1500 int type_term, char *config, char *str) 1613 int type_term, char *config, char *str,
1614 YYLTYPE *loc_term, YYLTYPE *loc_val)
1501{ 1615{
1502 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, 1616 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1503 config, str, 0); 1617 config, str, 0,
1618 loc_term ? loc_term->first_column : 0,
1619 loc_val ? loc_val->first_column : 0);
1504} 1620}
1505 1621
1506int parse_events_term__sym_hw(struct parse_events_term **term, 1622int parse_events_term__sym_hw(struct parse_events_term **term,
@@ -1514,18 +1630,20 @@ int parse_events_term__sym_hw(struct parse_events_term **term,
1514 if (config) 1630 if (config)
1515 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, 1631 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR,
1516 PARSE_EVENTS__TERM_TYPE_USER, config, 1632 PARSE_EVENTS__TERM_TYPE_USER, config,
1517 (char *) sym->symbol, 0); 1633 (char *) sym->symbol, 0, 0, 0);
1518 else 1634 else
1519 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, 1635 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR,
1520 PARSE_EVENTS__TERM_TYPE_USER, 1636 PARSE_EVENTS__TERM_TYPE_USER,
1521 (char *) "event", (char *) sym->symbol, 0); 1637 (char *) "event", (char *) sym->symbol,
1638 0, 0, 0);
1522} 1639}
1523 1640
1524int parse_events_term__clone(struct parse_events_term **new, 1641int parse_events_term__clone(struct parse_events_term **new,
1525 struct parse_events_term *term) 1642 struct parse_events_term *term)
1526{ 1643{
1527 return new_term(new, term->type_val, term->type_term, term->config, 1644 return new_term(new, term->type_val, term->type_term, term->config,
1528 term->val.str, term->val.num); 1645 term->val.str, term->val.num,
1646 term->err_term, term->err_val);
1529} 1647}
1530 1648
1531void parse_events__free_terms(struct list_head *terms) 1649void parse_events__free_terms(struct list_head *terms)
@@ -1535,3 +1653,13 @@ void parse_events__free_terms(struct list_head *terms)
1535 list_for_each_entry_safe(term, h, terms, list) 1653 list_for_each_entry_safe(term, h, terms, list)
1536 free(term); 1654 free(term);
1537} 1655}
1656
1657void parse_events_evlist_error(struct parse_events_evlist *data,
1658 int idx, const char *str)
1659{
1660 struct parse_events_error *err = data->error;
1661
1662 err->idx = idx;
1663 err->str = strdup(str);
1664 WARN_ONCE(!err->str, "WARNING: failed to allocate error string");
1665}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 52a2dda4f954..e236f1b6ac6f 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -12,6 +12,7 @@
12struct list_head; 12struct list_head;
13struct perf_evsel; 13struct perf_evsel;
14struct perf_evlist; 14struct perf_evlist;
15struct parse_events_error;
15 16
16struct option; 17struct option;
17 18
@@ -29,7 +30,8 @@ const char *event_type(int type);
29 30
30extern int parse_events_option(const struct option *opt, const char *str, 31extern int parse_events_option(const struct option *opt, const char *str,
31 int unset); 32 int unset);
32extern int parse_events(struct perf_evlist *evlist, const char *str); 33extern int parse_events(struct perf_evlist *evlist, const char *str,
34 struct parse_events_error *error);
33extern int parse_events_terms(struct list_head *terms, const char *str); 35extern int parse_events_terms(struct list_head *terms, const char *str);
34extern int parse_filter(const struct option *opt, const char *str, int unset); 36extern int parse_filter(const struct option *opt, const char *str, int unset);
35 37
@@ -72,12 +74,23 @@ struct parse_events_term {
72 int type_term; 74 int type_term;
73 struct list_head list; 75 struct list_head list;
74 bool used; 76 bool used;
77
78 /* error string indexes for within parsed string */
79 int err_term;
80 int err_val;
81};
82
83struct parse_events_error {
84 int idx; /* index in the parsed string */
85 char *str; /* string to display at the index */
86 char *help; /* optional help string */
75}; 87};
76 88
77struct parse_events_evlist { 89struct parse_events_evlist {
78 struct list_head list; 90 struct list_head list;
79 int idx; 91 int idx;
80 int nr_groups; 92 int nr_groups;
93 struct parse_events_error *error;
81}; 94};
82 95
83struct parse_events_terms { 96struct parse_events_terms {
@@ -85,10 +98,6 @@ struct parse_events_terms {
85}; 98};
86 99
87int parse_events__is_hardcoded_term(struct parse_events_term *term); 100int parse_events__is_hardcoded_term(struct parse_events_term *term);
88int parse_events_term__num(struct parse_events_term **_term,
89 int type_term, char *config, u64 num);
90int parse_events_term__str(struct parse_events_term **_term,
91 int type_term, char *config, char *str);
92int parse_events_term__sym_hw(struct parse_events_term **term, 101int parse_events_term__sym_hw(struct parse_events_term **term,
93 char *config, unsigned idx); 102 char *config, unsigned idx);
94int parse_events_term__clone(struct parse_events_term **new, 103int parse_events_term__clone(struct parse_events_term **new,
@@ -99,21 +108,24 @@ int parse_events__modifier_group(struct list_head *list, char *event_mod);
99int parse_events_name(struct list_head *list, char *name); 108int parse_events_name(struct list_head *list, char *name);
100int parse_events_add_tracepoint(struct list_head *list, int *idx, 109int parse_events_add_tracepoint(struct list_head *list, int *idx,
101 char *sys, char *event); 110 char *sys, char *event);
102int parse_events_add_numeric(struct list_head *list, int *idx, 111int parse_events_add_numeric(struct parse_events_evlist *data,
112 struct list_head *list,
103 u32 type, u64 config, 113 u32 type, u64 config,
104 struct list_head *head_config); 114 struct list_head *head_config);
105int parse_events_add_cache(struct list_head *list, int *idx, 115int parse_events_add_cache(struct list_head *list, int *idx,
106 char *type, char *op_result1, char *op_result2); 116 char *type, char *op_result1, char *op_result2);
107int parse_events_add_breakpoint(struct list_head *list, int *idx, 117int parse_events_add_breakpoint(struct list_head *list, int *idx,
108 void *ptr, char *type, u64 len); 118 void *ptr, char *type, u64 len);
109int parse_events_add_pmu(struct list_head *list, int *idx, 119int parse_events_add_pmu(struct parse_events_evlist *data,
110 char *pmu , struct list_head *head_config); 120 struct list_head *list, char *name,
121 struct list_head *head_config);
111enum perf_pmu_event_symbol_type 122enum perf_pmu_event_symbol_type
112perf_pmu__parse_check(const char *name); 123perf_pmu__parse_check(const char *name);
113void parse_events__set_leader(char *name, struct list_head *list); 124void parse_events__set_leader(char *name, struct list_head *list);
114void parse_events_update_lists(struct list_head *list_event, 125void parse_events_update_lists(struct list_head *list_event,
115 struct list_head *list_all); 126 struct list_head *list_all);
116void parse_events_error(void *data, void *scanner, char const *msg); 127void parse_events_evlist_error(struct parse_events_evlist *data,
128 int idx, const char *str);
117 129
118void print_events(const char *event_glob, bool name_only); 130void print_events(const char *event_glob, bool name_only);
119 131
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 8895cf3132ab..09e738fe9ea2 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -3,6 +3,8 @@
3%option bison-bridge 3%option bison-bridge
4%option prefix="parse_events_" 4%option prefix="parse_events_"
5%option stack 5%option stack
6%option bison-locations
7%option yylineno
6 8
7%{ 9%{
8#include <errno.h> 10#include <errno.h>
@@ -51,6 +53,18 @@ static int str(yyscan_t scanner, int token)
51 return token; 53 return token;
52} 54}
53 55
56#define REWIND(__alloc) \
57do { \
58 YYSTYPE *__yylval = parse_events_get_lval(yyscanner); \
59 char *text = parse_events_get_text(yyscanner); \
60 \
61 if (__alloc) \
62 __yylval->str = strdup(text); \
63 \
64 yycolumn -= strlen(text); \
65 yyless(0); \
66} while (0)
67
54static int pmu_str_check(yyscan_t scanner) 68static int pmu_str_check(yyscan_t scanner)
55{ 69{
56 YYSTYPE *yylval = parse_events_get_lval(scanner); 70 YYSTYPE *yylval = parse_events_get_lval(scanner);
@@ -85,6 +99,13 @@ static int term(yyscan_t scanner, int type)
85 return PE_TERM; 99 return PE_TERM;
86} 100}
87 101
102#define YY_USER_ACTION \
103do { \
104 yylloc->last_column = yylloc->first_column; \
105 yylloc->first_column = yycolumn; \
106 yycolumn += yyleng; \
107} while (0);
108
88%} 109%}
89 110
90%x mem 111%x mem
@@ -119,6 +140,12 @@ modifier_bp [rwx]{1,3}
119 140
120 if (start_token) { 141 if (start_token) {
121 parse_events_set_extra(NULL, yyscanner); 142 parse_events_set_extra(NULL, yyscanner);
143 /*
144 * The flex parser does not init locations variable
145 * via the scan_string interface, so we need do the
146 * init in here.
147 */
148 yycolumn = 0;
122 return start_token; 149 return start_token;
123 } 150 }
124 } 151 }
@@ -127,24 +154,30 @@ modifier_bp [rwx]{1,3}
127<event>{ 154<event>{
128 155
129{group} { 156{group} {
130 BEGIN(INITIAL); yyless(0); 157 BEGIN(INITIAL);
158 REWIND(0);
131 } 159 }
132 160
133{event_pmu} | 161{event_pmu} |
134{event} { 162{event} {
135 str(yyscanner, PE_EVENT_NAME); 163 BEGIN(INITIAL);
136 BEGIN(INITIAL); yyless(0); 164 REWIND(1);
137 return PE_EVENT_NAME; 165 return PE_EVENT_NAME;
138 } 166 }
139 167
140. | 168. |
141<<EOF>> { 169<<EOF>> {
142 BEGIN(INITIAL); yyless(0); 170 BEGIN(INITIAL);
171 REWIND(0);
143 } 172 }
144 173
145} 174}
146 175
147<config>{ 176<config>{
177 /*
178 * Please update formats_error_string any time
179 * new static term is added.
180 */
148config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } 181config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
149config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } 182config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
150config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } 183config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 72def077dbbf..3d11e00243e3 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -2,6 +2,7 @@
2%parse-param {void *_data} 2%parse-param {void *_data}
3%parse-param {void *scanner} 3%parse-param {void *scanner}
4%lex-param {void* scanner} 4%lex-param {void* scanner}
5%locations
5 6
6%{ 7%{
7 8
@@ -14,8 +15,6 @@
14#include "parse-events.h" 15#include "parse-events.h"
15#include "parse-events-bison.h" 16#include "parse-events-bison.h"
16 17
17extern int parse_events_lex (YYSTYPE* lvalp, void* scanner);
18
19#define ABORT_ON(val) \ 18#define ABORT_ON(val) \
20do { \ 19do { \
21 if (val) \ 20 if (val) \
@@ -208,7 +207,7 @@ PE_NAME '/' event_config '/'
208 struct list_head *list; 207 struct list_head *list;
209 208
210 ALLOC_LIST(list); 209 ALLOC_LIST(list);
211 ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, $3)); 210 ABORT_ON(parse_events_add_pmu(data, list, $1, $3));
212 parse_events__free_terms($3); 211 parse_events__free_terms($3);
213 $$ = list; 212 $$ = list;
214} 213}
@@ -219,7 +218,7 @@ PE_NAME '/' '/'
219 struct list_head *list; 218 struct list_head *list;
220 219
221 ALLOC_LIST(list); 220 ALLOC_LIST(list);
222 ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL)); 221 ABORT_ON(parse_events_add_pmu(data, list, $1, NULL));
223 $$ = list; 222 $$ = list;
224} 223}
225| 224|
@@ -232,11 +231,11 @@ PE_KERNEL_PMU_EVENT sep_dc
232 231
233 ALLOC_LIST(head); 232 ALLOC_LIST(head);
234 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, 233 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
235 $1, 1)); 234 $1, 1, &@1, NULL));
236 list_add_tail(&term->list, head); 235 list_add_tail(&term->list, head);
237 236
238 ALLOC_LIST(list); 237 ALLOC_LIST(list);
239 ABORT_ON(parse_events_add_pmu(list, &data->idx, "cpu", head)); 238 ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
240 parse_events__free_terms(head); 239 parse_events__free_terms(head);
241 $$ = list; 240 $$ = list;
242} 241}
@@ -252,7 +251,7 @@ PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
252 251
253 ALLOC_LIST(head); 252 ALLOC_LIST(head);
254 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, 253 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
255 &pmu_name, 1)); 254 &pmu_name, 1, &@1, NULL));
256 list_add_tail(&term->list, head); 255 list_add_tail(&term->list, head);
257 256
258 ALLOC_LIST(list); 257 ALLOC_LIST(list);
@@ -275,8 +274,7 @@ value_sym '/' event_config '/'
275 int config = $1 & 255; 274 int config = $1 & 255;
276 275
277 ALLOC_LIST(list); 276 ALLOC_LIST(list);
278 ABORT_ON(parse_events_add_numeric(list, &data->idx, 277 ABORT_ON(parse_events_add_numeric(data, list, type, config, $3));
279 type, config, $3));
280 parse_events__free_terms($3); 278 parse_events__free_terms($3);
281 $$ = list; 279 $$ = list;
282} 280}
@@ -289,8 +287,7 @@ value_sym sep_slash_dc
289 int config = $1 & 255; 287 int config = $1 & 255;
290 288
291 ALLOC_LIST(list); 289 ALLOC_LIST(list);
292 ABORT_ON(parse_events_add_numeric(list, &data->idx, 290 ABORT_ON(parse_events_add_numeric(data, list, type, config, NULL));
293 type, config, NULL));
294 $$ = list; 291 $$ = list;
295} 292}
296 293
@@ -389,7 +386,13 @@ PE_NAME ':' PE_NAME
389 struct list_head *list; 386 struct list_head *list;
390 387
391 ALLOC_LIST(list); 388 ALLOC_LIST(list);
392 ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3)); 389 if (parse_events_add_tracepoint(list, &data->idx, $1, $3)) {
390 struct parse_events_error *error = data->error;
391
392 error->idx = @1.first_column;
393 error->str = strdup("unknown tracepoint");
394 return -1;
395 }
393 $$ = list; 396 $$ = list;
394} 397}
395 398
@@ -400,7 +403,7 @@ PE_VALUE ':' PE_VALUE
400 struct list_head *list; 403 struct list_head *list;
401 404
402 ALLOC_LIST(list); 405 ALLOC_LIST(list);
403 ABORT_ON(parse_events_add_numeric(list, &data->idx, (u32)$1, $3, NULL)); 406 ABORT_ON(parse_events_add_numeric(data, list, (u32)$1, $3, NULL));
404 $$ = list; 407 $$ = list;
405} 408}
406 409
@@ -411,8 +414,7 @@ PE_RAW
411 struct list_head *list; 414 struct list_head *list;
412 415
413 ALLOC_LIST(list); 416 ALLOC_LIST(list);
414 ABORT_ON(parse_events_add_numeric(list, &data->idx, 417 ABORT_ON(parse_events_add_numeric(data, list, PERF_TYPE_RAW, $1, NULL));
415 PERF_TYPE_RAW, $1, NULL));
416 $$ = list; 418 $$ = list;
417} 419}
418 420
@@ -450,7 +452,7 @@ PE_NAME '=' PE_NAME
450 struct parse_events_term *term; 452 struct parse_events_term *term;
451 453
452 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, 454 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
453 $1, $3)); 455 $1, $3, &@1, &@3));
454 $$ = term; 456 $$ = term;
455} 457}
456| 458|
@@ -459,7 +461,7 @@ PE_NAME '=' PE_VALUE
459 struct parse_events_term *term; 461 struct parse_events_term *term;
460 462
461 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, 463 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
462 $1, $3)); 464 $1, $3, &@1, &@3));
463 $$ = term; 465 $$ = term;
464} 466}
465| 467|
@@ -477,7 +479,7 @@ PE_NAME
477 struct parse_events_term *term; 479 struct parse_events_term *term;
478 480
479 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, 481 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
480 $1, 1)); 482 $1, 1, &@1, NULL));
481 $$ = term; 483 $$ = term;
482} 484}
483| 485|
@@ -494,7 +496,7 @@ PE_TERM '=' PE_NAME
494{ 496{
495 struct parse_events_term *term; 497 struct parse_events_term *term;
496 498
497 ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3)); 499 ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3, &@1, &@3));
498 $$ = term; 500 $$ = term;
499} 501}
500| 502|
@@ -502,7 +504,7 @@ PE_TERM '=' PE_VALUE
502{ 504{
503 struct parse_events_term *term; 505 struct parse_events_term *term;
504 506
505 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3)); 507 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3, &@1, &@3));
506 $$ = term; 508 $$ = term;
507} 509}
508| 510|
@@ -510,7 +512,7 @@ PE_TERM
510{ 512{
511 struct parse_events_term *term; 513 struct parse_events_term *term;
512 514
513 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1)); 515 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, &@1, NULL));
514 $$ = term; 516 $$ = term;
515} 517}
516 518
@@ -520,7 +522,9 @@ sep_slash_dc: '/' | ':' |
520 522
521%% 523%%
522 524
523void parse_events_error(void *data __maybe_unused, void *scanner __maybe_unused, 525void parse_events_error(YYLTYPE *loc, void *data,
526 void *scanner __maybe_unused,
524 char const *msg __maybe_unused) 527 char const *msg __maybe_unused)
525{ 528{
529 parse_events_evlist_error(data, loc->last_column, "parser error");
526} 530}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 59561fd86278..367d8b816cc7 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -123,6 +123,10 @@ struct option {
123#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) } 123#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
124#define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) } 124#define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
125#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) } 125#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
126#define OPT_STRING_OPTARG(s, l, v, a, h, d) \
127 { .type = OPTION_STRING, .short_name = (s), .long_name = (l), \
128 .value = check_vtype(v, const char **), (a), .help = (h), \
129 .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d) }
126#define OPT_STRING_NOEMPTY(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h), .flags = PARSE_OPT_NOEMPTY} 130#define OPT_STRING_NOEMPTY(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
127#define OPT_DATE(s, l, v, h) \ 131#define OPT_DATE(s, l, v, h) \
128 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb } 132 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 48411674da0f..244c66f89891 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -579,6 +579,38 @@ static int pmu_resolve_param_term(struct parse_events_term *term,
579 return -1; 579 return -1;
580} 580}
581 581
582static char *formats_error_string(struct list_head *formats)
583{
584 struct perf_pmu_format *format;
585 char *err, *str;
586 static const char *static_terms = "config,config1,config2,name,period,branch_type\n";
587 unsigned i = 0;
588
589 if (!asprintf(&str, "valid terms:"))
590 return NULL;
591
592 /* sysfs exported terms */
593 list_for_each_entry(format, formats, list) {
594 char c = i++ ? ',' : ' ';
595
596 err = str;
597 if (!asprintf(&str, "%s%c%s", err, c, format->name))
598 goto fail;
599 free(err);
600 }
601
602 /* static terms */
603 err = str;
604 if (!asprintf(&str, "%s,%s", err, static_terms))
605 goto fail;
606
607 free(err);
608 return str;
609fail:
610 free(err);
611 return NULL;
612}
613
582/* 614/*
583 * Setup one of config[12] attr members based on the 615 * Setup one of config[12] attr members based on the
584 * user input data - term parameter. 616 * user input data - term parameter.
@@ -587,7 +619,7 @@ static int pmu_config_term(struct list_head *formats,
587 struct perf_event_attr *attr, 619 struct perf_event_attr *attr,
588 struct parse_events_term *term, 620 struct parse_events_term *term,
589 struct list_head *head_terms, 621 struct list_head *head_terms,
590 bool zero) 622 bool zero, struct parse_events_error *err)
591{ 623{
592 struct perf_pmu_format *format; 624 struct perf_pmu_format *format;
593 __u64 *vp; 625 __u64 *vp;
@@ -611,6 +643,11 @@ static int pmu_config_term(struct list_head *formats,
611 if (!format) { 643 if (!format) {
612 if (verbose) 644 if (verbose)
613 printf("Invalid event/parameter '%s'\n", term->config); 645 printf("Invalid event/parameter '%s'\n", term->config);
646 if (err) {
647 err->idx = term->err_term;
648 err->str = strdup("unknown term");
649 err->help = formats_error_string(formats);
650 }
614 return -EINVAL; 651 return -EINVAL;
615 } 652 }
616 653
@@ -636,9 +673,14 @@ static int pmu_config_term(struct list_head *formats,
636 val = term->val.num; 673 val = term->val.num;
637 else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 674 else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
638 if (strcmp(term->val.str, "?")) { 675 if (strcmp(term->val.str, "?")) {
639 if (verbose) 676 if (verbose) {
640 pr_info("Invalid sysfs entry %s=%s\n", 677 pr_info("Invalid sysfs entry %s=%s\n",
641 term->config, term->val.str); 678 term->config, term->val.str);
679 }
680 if (err) {
681 err->idx = term->err_val;
682 err->str = strdup("expected numeric value");
683 }
642 return -EINVAL; 684 return -EINVAL;
643 } 685 }
644 686
@@ -654,12 +696,13 @@ static int pmu_config_term(struct list_head *formats,
654int perf_pmu__config_terms(struct list_head *formats, 696int perf_pmu__config_terms(struct list_head *formats,
655 struct perf_event_attr *attr, 697 struct perf_event_attr *attr,
656 struct list_head *head_terms, 698 struct list_head *head_terms,
657 bool zero) 699 bool zero, struct parse_events_error *err)
658{ 700{
659 struct parse_events_term *term; 701 struct parse_events_term *term;
660 702
661 list_for_each_entry(term, head_terms, list) { 703 list_for_each_entry(term, head_terms, list) {
662 if (pmu_config_term(formats, attr, term, head_terms, zero)) 704 if (pmu_config_term(formats, attr, term, head_terms,
705 zero, err))
663 return -EINVAL; 706 return -EINVAL;
664 } 707 }
665 708
@@ -672,12 +715,14 @@ int perf_pmu__config_terms(struct list_head *formats,
672 * 2) pmu format definitions - specified by pmu parameter 715 * 2) pmu format definitions - specified by pmu parameter
673 */ 716 */
674int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 717int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
675 struct list_head *head_terms) 718 struct list_head *head_terms,
719 struct parse_events_error *err)
676{ 720{
677 bool zero = !!pmu->default_config; 721 bool zero = !!pmu->default_config;
678 722
679 attr->type = pmu->type; 723 attr->type = pmu->type;
680 return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero); 724 return perf_pmu__config_terms(&pmu->format, attr, head_terms,
725 zero, err);
681} 726}
682 727
683static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 728static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 6b1249fbdb5f..7b9c8cf8ae3e 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -4,6 +4,7 @@
4#include <linux/bitmap.h> 4#include <linux/bitmap.h>
5#include <linux/perf_event.h> 5#include <linux/perf_event.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "parse-events.h"
7 8
8enum { 9enum {
9 PERF_PMU_FORMAT_VALUE_CONFIG, 10 PERF_PMU_FORMAT_VALUE_CONFIG,
@@ -47,11 +48,12 @@ struct perf_pmu_alias {
47 48
48struct perf_pmu *perf_pmu__find(const char *name); 49struct perf_pmu *perf_pmu__find(const char *name);
49int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 50int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
50 struct list_head *head_terms); 51 struct list_head *head_terms,
52 struct parse_events_error *error);
51int perf_pmu__config_terms(struct list_head *formats, 53int perf_pmu__config_terms(struct list_head *formats,
52 struct perf_event_attr *attr, 54 struct perf_event_attr *attr,
53 struct list_head *head_terms, 55 struct list_head *head_terms,
54 bool zero); 56 bool zero, struct parse_events_error *error);
55int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 57int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
56 struct perf_pmu_info *info); 58 struct perf_pmu_info *info);
57struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 59struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index d8bb616ff57c..abf5845a2acc 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1077,6 +1077,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
1077 struct perf_probe_point *pp = &pev->point; 1077 struct perf_probe_point *pp = &pev->point;
1078 char *ptr, *tmp; 1078 char *ptr, *tmp;
1079 char c, nc = 0; 1079 char c, nc = 0;
1080 bool file_spec = false;
1080 /* 1081 /*
1081 * <Syntax> 1082 * <Syntax>
1082 * perf probe [EVENT=]SRC[:LN|;PTN] 1083 * perf probe [EVENT=]SRC[:LN|;PTN]
@@ -1105,6 +1106,23 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
1105 arg = tmp; 1106 arg = tmp;
1106 } 1107 }
1107 1108
1109 /*
1110 * Check arg is function or file name and copy it.
1111 *
1112 * We consider arg to be a file spec if and only if it satisfies
1113 * all of the below criteria::
1114 * - it does not include any of "+@%",
1115 * - it includes one of ":;", and
1116 * - it has a period '.' in the name.
1117 *
1118 * Otherwise, we consider arg to be a function specification.
1119 */
1120 if (!strpbrk(arg, "+@%") && (ptr = strpbrk(arg, ";:")) != NULL) {
1121 /* This is a file spec if it includes a '.' before ; or : */
1122 if (memchr(arg, '.', ptr - arg))
1123 file_spec = true;
1124 }
1125
1108 ptr = strpbrk(arg, ";:+@%"); 1126 ptr = strpbrk(arg, ";:+@%");
1109 if (ptr) { 1127 if (ptr) {
1110 nc = *ptr; 1128 nc = *ptr;
@@ -1115,10 +1133,9 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
1115 if (tmp == NULL) 1133 if (tmp == NULL)
1116 return -ENOMEM; 1134 return -ENOMEM;
1117 1135
1118 /* Check arg is function or file and copy it */ 1136 if (file_spec)
1119 if (strchr(tmp, '.')) /* File */
1120 pp->file = tmp; 1137 pp->file = tmp;
1121 else /* Function */ 1138 else
1122 pp->function = tmp; 1139 pp->function = tmp;
1123 1140
1124 /* Parse other options */ 1141 /* Parse other options */
@@ -2129,7 +2146,23 @@ static int show_perf_probe_event(struct perf_probe_event *pev,
2129 return ret; 2146 return ret;
2130} 2147}
2131 2148
2132static int __show_perf_probe_events(int fd, bool is_kprobe) 2149static bool filter_probe_trace_event(struct probe_trace_event *tev,
2150 struct strfilter *filter)
2151{
2152 char tmp[128];
2153
2154 /* At first, check the event name itself */
2155 if (strfilter__compare(filter, tev->event))
2156 return true;
2157
2158 /* Next, check the combination of name and group */
2159 if (e_snprintf(tmp, 128, "%s:%s", tev->group, tev->event) < 0)
2160 return false;
2161 return strfilter__compare(filter, tmp);
2162}
2163
2164static int __show_perf_probe_events(int fd, bool is_kprobe,
2165 struct strfilter *filter)
2133{ 2166{
2134 int ret = 0; 2167 int ret = 0;
2135 struct probe_trace_event tev; 2168 struct probe_trace_event tev;
@@ -2147,12 +2180,15 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
2147 strlist__for_each(ent, rawlist) { 2180 strlist__for_each(ent, rawlist) {
2148 ret = parse_probe_trace_command(ent->s, &tev); 2181 ret = parse_probe_trace_command(ent->s, &tev);
2149 if (ret >= 0) { 2182 if (ret >= 0) {
2183 if (!filter_probe_trace_event(&tev, filter))
2184 goto next;
2150 ret = convert_to_perf_probe_event(&tev, &pev, 2185 ret = convert_to_perf_probe_event(&tev, &pev,
2151 is_kprobe); 2186 is_kprobe);
2152 if (ret >= 0) 2187 if (ret >= 0)
2153 ret = show_perf_probe_event(&pev, 2188 ret = show_perf_probe_event(&pev,
2154 tev.point.module); 2189 tev.point.module);
2155 } 2190 }
2191next:
2156 clear_perf_probe_event(&pev); 2192 clear_perf_probe_event(&pev);
2157 clear_probe_trace_event(&tev); 2193 clear_probe_trace_event(&tev);
2158 if (ret < 0) 2194 if (ret < 0)
@@ -2164,7 +2200,7 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
2164} 2200}
2165 2201
2166/* List up current perf-probe events */ 2202/* List up current perf-probe events */
2167int show_perf_probe_events(void) 2203int show_perf_probe_events(struct strfilter *filter)
2168{ 2204{
2169 int kp_fd, up_fd, ret; 2205 int kp_fd, up_fd, ret;
2170 2206
@@ -2176,7 +2212,7 @@ int show_perf_probe_events(void)
2176 2212
2177 kp_fd = open_kprobe_events(false); 2213 kp_fd = open_kprobe_events(false);
2178 if (kp_fd >= 0) { 2214 if (kp_fd >= 0) {
2179 ret = __show_perf_probe_events(kp_fd, true); 2215 ret = __show_perf_probe_events(kp_fd, true, filter);
2180 close(kp_fd); 2216 close(kp_fd);
2181 if (ret < 0) 2217 if (ret < 0)
2182 goto out; 2218 goto out;
@@ -2190,7 +2226,7 @@ int show_perf_probe_events(void)
2190 } 2226 }
2191 2227
2192 if (up_fd >= 0) { 2228 if (up_fd >= 0) {
2193 ret = __show_perf_probe_events(up_fd, false); 2229 ret = __show_perf_probe_events(up_fd, false, filter);
2194 close(up_fd); 2230 close(up_fd);
2195 } 2231 }
2196out: 2232out:
@@ -2265,6 +2301,9 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
2265{ 2301{
2266 int i, ret; 2302 int i, ret;
2267 2303
2304 if (*base == '.')
2305 base++;
2306
2268 /* Try no suffix */ 2307 /* Try no suffix */
2269 ret = e_snprintf(buf, len, "%s", base); 2308 ret = e_snprintf(buf, len, "%s", base);
2270 if (ret < 0) { 2309 if (ret < 0) {
@@ -2447,6 +2486,10 @@ static int find_probe_functions(struct map *map, char *name)
2447#define strdup_or_goto(str, label) \ 2486#define strdup_or_goto(str, label) \
2448 ({ char *__p = strdup(str); if (!__p) goto label; __p; }) 2487 ({ char *__p = strdup(str); if (!__p) goto label; __p; })
2449 2488
2489void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused,
2490 struct probe_trace_event *tev __maybe_unused,
2491 struct map *map __maybe_unused) { }
2492
2450/* 2493/*
2451 * Find probe function addresses from map. 2494 * Find probe function addresses from map.
2452 * Return an error or the number of found probe_trace_event 2495 * Return an error or the number of found probe_trace_event
@@ -2553,6 +2596,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2553 strdup_or_goto(pev->args[i].type, 2596 strdup_or_goto(pev->args[i].type,
2554 nomem_out); 2597 nomem_out);
2555 } 2598 }
2599 arch__fix_tev_from_maps(pev, tev, map);
2556 } 2600 }
2557 2601
2558out: 2602out:
@@ -2567,6 +2611,8 @@ err_out:
2567 goto out; 2611 goto out;
2568} 2612}
2569 2613
2614bool __weak arch__prefers_symtab(void) { return false; }
2615
2570static int convert_to_probe_trace_events(struct perf_probe_event *pev, 2616static int convert_to_probe_trace_events(struct perf_probe_event *pev,
2571 struct probe_trace_event **tevs, 2617 struct probe_trace_event **tevs,
2572 int max_tevs, const char *target) 2618 int max_tevs, const char *target)
@@ -2582,6 +2628,12 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
2582 } 2628 }
2583 } 2629 }
2584 2630
2631 if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) {
2632 ret = find_probe_trace_events_from_map(pev, tevs, max_tevs, target);
2633 if (ret > 0)
2634 return ret; /* Found in symbol table */
2635 }
2636
2585 /* Convert perf_probe_event with debuginfo */ 2637 /* Convert perf_probe_event with debuginfo */
2586 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); 2638 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
2587 if (ret != 0) 2639 if (ret != 0)
@@ -2682,40 +2734,39 @@ error:
2682 return ret; 2734 return ret;
2683} 2735}
2684 2736
2685static int del_trace_probe_event(int fd, const char *buf, 2737static int del_trace_probe_events(int fd, struct strfilter *filter,
2686 struct strlist *namelist) 2738 struct strlist *namelist)
2687{ 2739{
2688 struct str_node *ent, *n; 2740 struct str_node *ent;
2689 int ret = -1; 2741 const char *p;
2742 int ret = -ENOENT;
2690 2743
2691 if (strpbrk(buf, "*?")) { /* Glob-exp */ 2744 if (!namelist)
2692 strlist__for_each_safe(ent, n, namelist) 2745 return -ENOENT;
2693 if (strglobmatch(ent->s, buf)) { 2746
2694 ret = __del_trace_probe_event(fd, ent); 2747 strlist__for_each(ent, namelist) {
2695 if (ret < 0) 2748 p = strchr(ent->s, ':');
2696 break; 2749 if ((p && strfilter__compare(filter, p + 1)) ||
2697 strlist__remove(namelist, ent); 2750 strfilter__compare(filter, ent->s)) {
2698 }
2699 } else {
2700 ent = strlist__find(namelist, buf);
2701 if (ent) {
2702 ret = __del_trace_probe_event(fd, ent); 2751 ret = __del_trace_probe_event(fd, ent);
2703 if (ret >= 0) 2752 if (ret < 0)
2704 strlist__remove(namelist, ent); 2753 break;
2705 } 2754 }
2706 } 2755 }
2707 2756
2708 return ret; 2757 return ret;
2709} 2758}
2710 2759
2711int del_perf_probe_events(struct strlist *dellist) 2760int del_perf_probe_events(struct strfilter *filter)
2712{ 2761{
2713 int ret = -1, ufd = -1, kfd = -1; 2762 int ret, ret2, ufd = -1, kfd = -1;
2714 char buf[128];
2715 const char *group, *event;
2716 char *p, *str;
2717 struct str_node *ent;
2718 struct strlist *namelist = NULL, *unamelist = NULL; 2763 struct strlist *namelist = NULL, *unamelist = NULL;
2764 char *str = strfilter__string(filter);
2765
2766 if (!str)
2767 return -EINVAL;
2768
2769 pr_debug("Delete filter: \'%s\'\n", str);
2719 2770
2720 /* Get current event names */ 2771 /* Get current event names */
2721 kfd = open_kprobe_events(true); 2772 kfd = open_kprobe_events(true);
@@ -2728,48 +2779,21 @@ int del_perf_probe_events(struct strlist *dellist)
2728 2779
2729 if (kfd < 0 && ufd < 0) { 2780 if (kfd < 0 && ufd < 0) {
2730 print_both_open_warning(kfd, ufd); 2781 print_both_open_warning(kfd, ufd);
2782 ret = kfd;
2731 goto error; 2783 goto error;
2732 } 2784 }
2733 2785
2734 if (namelist == NULL && unamelist == NULL) 2786 ret = del_trace_probe_events(kfd, filter, namelist);
2787 if (ret < 0 && ret != -ENOENT)
2735 goto error; 2788 goto error;
2736 2789
2737 strlist__for_each(ent, dellist) { 2790 ret2 = del_trace_probe_events(ufd, filter, unamelist);
2738 str = strdup(ent->s); 2791 if (ret2 < 0 && ret2 != -ENOENT)
2739 if (str == NULL) { 2792 ret = ret2;
2740 ret = -ENOMEM; 2793 else if (ret == -ENOENT && ret2 == -ENOENT) {
2741 goto error; 2794 pr_debug("\"%s\" does not hit any event.\n", str);
2742 } 2795 /* Note that this is silently ignored */
2743 pr_debug("Parsing: %s\n", str); 2796 ret = 0;
2744 p = strchr(str, ':');
2745 if (p) {
2746 group = str;
2747 *p = '\0';
2748 event = p + 1;
2749 } else {
2750 group = "*";
2751 event = str;
2752 }
2753
2754 ret = e_snprintf(buf, 128, "%s:%s", group, event);
2755 if (ret < 0) {
2756 pr_err("Failed to copy event.");
2757 free(str);
2758 goto error;
2759 }
2760
2761 pr_debug("Group: %s, Event: %s\n", group, event);
2762
2763 if (namelist)
2764 ret = del_trace_probe_event(kfd, buf, namelist);
2765
2766 if (unamelist && ret != 0)
2767 ret = del_trace_probe_event(ufd, buf, unamelist);
2768
2769 if (ret != 0)
2770 pr_info("Info: Event \"%s\" does not exist.\n", buf);
2771
2772 free(str);
2773 } 2797 }
2774 2798
2775error: 2799error:
@@ -2782,6 +2806,7 @@ error:
2782 strlist__delete(unamelist); 2806 strlist__delete(unamelist);
2783 close(ufd); 2807 close(ufd);
2784 } 2808 }
2809 free(str);
2785 2810
2786 return ret; 2811 return ret;
2787} 2812}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index d6b783447be9..e10aedc34570 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -126,8 +126,8 @@ extern const char *kernel_get_module_path(const char *module);
126 126
127extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 127extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
128 int max_probe_points, bool force_add); 128 int max_probe_points, bool force_add);
129extern int del_perf_probe_events(struct strlist *dellist); 129extern int del_perf_probe_events(struct strfilter *filter);
130extern int show_perf_probe_events(void); 130extern int show_perf_probe_events(struct strfilter *filter);
131extern int show_line_range(struct line_range *lr, const char *module, 131extern int show_line_range(struct line_range *lr, const char *module,
132 bool user); 132 bool user);
133extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 133extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
@@ -135,6 +135,9 @@ extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
135 struct strfilter *filter, bool externs); 135 struct strfilter *filter, bool externs);
136extern int show_available_funcs(const char *module, struct strfilter *filter, 136extern int show_available_funcs(const char *module, struct strfilter *filter,
137 bool user); 137 bool user);
138bool arch__prefers_symtab(void);
139void arch__fix_tev_from_maps(struct perf_probe_event *pev,
140 struct probe_trace_event *tev, struct map *map);
138 141
139/* Maximum index number of event-name postfix */ 142/* Maximum index number of event-name postfix */
140#define MAX_EVENT_INDEX 1024 143#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c
index a126e6cc6e73..b234a6e3d0d4 100644
--- a/tools/perf/util/pstack.c
+++ b/tools/perf/util/pstack.c
@@ -74,3 +74,10 @@ void *pstack__pop(struct pstack *pstack)
74 pstack->entries[pstack->top] = NULL; 74 pstack->entries[pstack->top] = NULL;
75 return ret; 75 return ret;
76} 76}
77
78void *pstack__peek(struct pstack *pstack)
79{
80 if (pstack->top == 0)
81 return NULL;
82 return pstack->entries[pstack->top - 1];
83}
diff --git a/tools/perf/util/pstack.h b/tools/perf/util/pstack.h
index c3cb6584d527..ded7f2e36624 100644
--- a/tools/perf/util/pstack.h
+++ b/tools/perf/util/pstack.h
@@ -10,5 +10,6 @@ bool pstack__empty(const struct pstack *pstack);
10void pstack__remove(struct pstack *pstack, void *key); 10void pstack__remove(struct pstack *pstack, void *key);
11void pstack__push(struct pstack *pstack, void *key); 11void pstack__push(struct pstack *pstack, void *key);
12void *pstack__pop(struct pstack *pstack); 12void *pstack__pop(struct pstack *pstack);
13void *pstack__peek(struct pstack *pstack);
13 14
14#endif /* _PERF_PSTACK_ */ 15#endif /* _PERF_PSTACK_ */
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 8acd0df88b5c..d457c523a33d 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -20,7 +20,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
20 if (!evlist) 20 if (!evlist)
21 return -ENOMEM; 21 return -ENOMEM;
22 22
23 if (parse_events(evlist, str)) 23 if (parse_events(evlist, str, NULL))
24 goto out_delete; 24 goto out_delete;
25 25
26 evsel = perf_evlist__first(evlist); 26 evsel = perf_evlist__first(evlist);
@@ -119,7 +119,16 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
119 evsel->attr.comm_exec = 1; 119 evsel->attr.comm_exec = 1;
120 } 120 }
121 121
122 if (evlist->nr_entries > 1) { 122 if (opts->full_auxtrace) {
123 /*
124 * Need to be able to synthesize and parse selected events with
125 * arbitrary sample types, which requires always being able to
126 * match the id.
127 */
128 use_sample_identifier = perf_can_sample_identifier();
129 evlist__for_each(evlist, evsel)
130 perf_evsel__set_sample_id(evsel, use_sample_identifier);
131 } else if (evlist->nr_entries > 1) {
123 struct perf_evsel *first = perf_evlist__first(evlist); 132 struct perf_evsel *first = perf_evlist__first(evlist);
124 133
125 evlist__for_each(evlist, evsel) { 134 evlist__for_each(evlist, evsel) {
@@ -207,7 +216,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
207 if (!temp_evlist) 216 if (!temp_evlist)
208 return false; 217 return false;
209 218
210 err = parse_events(temp_evlist, str); 219 err = parse_events(temp_evlist, str, NULL);
211 if (err) 220 if (err)
212 goto out_delete; 221 goto out_delete;
213 222
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0c74012575ac..e722107f932a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -15,12 +15,13 @@
15#include "cpumap.h" 15#include "cpumap.h"
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "asm/bug.h" 17#include "asm/bug.h"
18#include "auxtrace.h"
18 19
19static int machines__deliver_event(struct machines *machines, 20static int perf_session__deliver_event(struct perf_session *session,
20 struct perf_evlist *evlist, 21 union perf_event *event,
21 union perf_event *event, 22 struct perf_sample *sample,
22 struct perf_sample *sample, 23 struct perf_tool *tool,
23 struct perf_tool *tool, u64 file_offset); 24 u64 file_offset);
24 25
25static int perf_session__open(struct perf_session *session) 26static int perf_session__open(struct perf_session *session)
26{ 27{
@@ -105,8 +106,8 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
105 return ret; 106 return ret;
106 } 107 }
107 108
108 return machines__deliver_event(&session->machines, session->evlist, event->event, 109 return perf_session__deliver_event(session, event->event, &sample,
109 &sample, session->tool, event->file_offset); 110 session->tool, event->file_offset);
110} 111}
111 112
112struct perf_session *perf_session__new(struct perf_data_file *file, 113struct perf_session *perf_session__new(struct perf_data_file *file,
@@ -119,6 +120,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
119 120
120 session->repipe = repipe; 121 session->repipe = repipe;
121 session->tool = tool; 122 session->tool = tool;
123 INIT_LIST_HEAD(&session->auxtrace_index);
122 machines__init(&session->machines); 124 machines__init(&session->machines);
123 ordered_events__init(&session->ordered_events, ordered_events__deliver_event); 125 ordered_events__init(&session->ordered_events, ordered_events__deliver_event);
124 126
@@ -185,6 +187,8 @@ static void perf_session_env__delete(struct perf_session_env *env)
185 187
186void perf_session__delete(struct perf_session *session) 188void perf_session__delete(struct perf_session *session)
187{ 189{
190 auxtrace__free(session);
191 auxtrace_index__free(&session->auxtrace_index);
188 perf_session__destroy_kernel_maps(session); 192 perf_session__destroy_kernel_maps(session);
189 perf_session__delete_threads(session); 193 perf_session__delete_threads(session);
190 perf_session_env__delete(&session->header.env); 194 perf_session_env__delete(&session->header.env);
@@ -262,6 +266,49 @@ static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
262 return 0; 266 return 0;
263} 267}
264 268
269static int process_event_auxtrace_info_stub(struct perf_tool *tool __maybe_unused,
270 union perf_event *event __maybe_unused,
271 struct perf_session *session __maybe_unused)
272{
273 dump_printf(": unhandled!\n");
274 return 0;
275}
276
277static int skipn(int fd, off_t n)
278{
279 char buf[4096];
280 ssize_t ret;
281
282 while (n > 0) {
283 ret = read(fd, buf, min(n, (off_t)sizeof(buf)));
284 if (ret <= 0)
285 return ret;
286 n -= ret;
287 }
288
289 return 0;
290}
291
292static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
293 union perf_event *event,
294 struct perf_session *session
295 __maybe_unused)
296{
297 dump_printf(": unhandled!\n");
298 if (perf_data_file__is_pipe(session->file))
299 skipn(perf_data_file__fd(session->file), event->auxtrace.size);
300 return event->auxtrace.size;
301}
302
303static
304int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused,
305 union perf_event *event __maybe_unused,
306 struct perf_session *session __maybe_unused)
307{
308 dump_printf(": unhandled!\n");
309 return 0;
310}
311
265void perf_tool__fill_defaults(struct perf_tool *tool) 312void perf_tool__fill_defaults(struct perf_tool *tool)
266{ 313{
267 if (tool->sample == NULL) 314 if (tool->sample == NULL)
@@ -278,6 +325,10 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
278 tool->exit = process_event_stub; 325 tool->exit = process_event_stub;
279 if (tool->lost == NULL) 326 if (tool->lost == NULL)
280 tool->lost = perf_event__process_lost; 327 tool->lost = perf_event__process_lost;
328 if (tool->aux == NULL)
329 tool->aux = perf_event__process_aux;
330 if (tool->itrace_start == NULL)
331 tool->itrace_start = perf_event__process_itrace_start;
281 if (tool->read == NULL) 332 if (tool->read == NULL)
282 tool->read = process_event_sample_stub; 333 tool->read = process_event_sample_stub;
283 if (tool->throttle == NULL) 334 if (tool->throttle == NULL)
@@ -298,6 +349,12 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
298 } 349 }
299 if (tool->id_index == NULL) 350 if (tool->id_index == NULL)
300 tool->id_index = process_id_index_stub; 351 tool->id_index = process_id_index_stub;
352 if (tool->auxtrace_info == NULL)
353 tool->auxtrace_info = process_event_auxtrace_info_stub;
354 if (tool->auxtrace == NULL)
355 tool->auxtrace = process_event_auxtrace_stub;
356 if (tool->auxtrace_error == NULL)
357 tool->auxtrace_error = process_event_auxtrace_error_stub;
301} 358}
302 359
303static void swap_sample_id_all(union perf_event *event, void *data) 360static void swap_sample_id_all(union perf_event *event, void *data)
@@ -390,6 +447,26 @@ static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
390 swap_sample_id_all(event, &event->read + 1); 447 swap_sample_id_all(event, &event->read + 1);
391} 448}
392 449
450static void perf_event__aux_swap(union perf_event *event, bool sample_id_all)
451{
452 event->aux.aux_offset = bswap_64(event->aux.aux_offset);
453 event->aux.aux_size = bswap_64(event->aux.aux_size);
454 event->aux.flags = bswap_64(event->aux.flags);
455
456 if (sample_id_all)
457 swap_sample_id_all(event, &event->aux + 1);
458}
459
460static void perf_event__itrace_start_swap(union perf_event *event,
461 bool sample_id_all)
462{
463 event->itrace_start.pid = bswap_32(event->itrace_start.pid);
464 event->itrace_start.tid = bswap_32(event->itrace_start.tid);
465
466 if (sample_id_all)
467 swap_sample_id_all(event, &event->itrace_start + 1);
468}
469
393static void perf_event__throttle_swap(union perf_event *event, 470static void perf_event__throttle_swap(union perf_event *event,
394 bool sample_id_all) 471 bool sample_id_all)
395{ 472{
@@ -449,6 +526,7 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
449 attr->branch_sample_type = bswap_64(attr->branch_sample_type); 526 attr->branch_sample_type = bswap_64(attr->branch_sample_type);
450 attr->sample_regs_user = bswap_64(attr->sample_regs_user); 527 attr->sample_regs_user = bswap_64(attr->sample_regs_user);
451 attr->sample_stack_user = bswap_32(attr->sample_stack_user); 528 attr->sample_stack_user = bswap_32(attr->sample_stack_user);
529 attr->aux_watermark = bswap_32(attr->aux_watermark);
452 530
453 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); 531 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
454} 532}
@@ -478,6 +556,40 @@ static void perf_event__tracing_data_swap(union perf_event *event,
478 event->tracing_data.size = bswap_32(event->tracing_data.size); 556 event->tracing_data.size = bswap_32(event->tracing_data.size);
479} 557}
480 558
559static void perf_event__auxtrace_info_swap(union perf_event *event,
560 bool sample_id_all __maybe_unused)
561{
562 size_t size;
563
564 event->auxtrace_info.type = bswap_32(event->auxtrace_info.type);
565
566 size = event->header.size;
567 size -= (void *)&event->auxtrace_info.priv - (void *)event;
568 mem_bswap_64(event->auxtrace_info.priv, size);
569}
570
571static void perf_event__auxtrace_swap(union perf_event *event,
572 bool sample_id_all __maybe_unused)
573{
574 event->auxtrace.size = bswap_64(event->auxtrace.size);
575 event->auxtrace.offset = bswap_64(event->auxtrace.offset);
576 event->auxtrace.reference = bswap_64(event->auxtrace.reference);
577 event->auxtrace.idx = bswap_32(event->auxtrace.idx);
578 event->auxtrace.tid = bswap_32(event->auxtrace.tid);
579 event->auxtrace.cpu = bswap_32(event->auxtrace.cpu);
580}
581
582static void perf_event__auxtrace_error_swap(union perf_event *event,
583 bool sample_id_all __maybe_unused)
584{
585 event->auxtrace_error.type = bswap_32(event->auxtrace_error.type);
586 event->auxtrace_error.code = bswap_32(event->auxtrace_error.code);
587 event->auxtrace_error.cpu = bswap_32(event->auxtrace_error.cpu);
588 event->auxtrace_error.pid = bswap_32(event->auxtrace_error.pid);
589 event->auxtrace_error.tid = bswap_32(event->auxtrace_error.tid);
590 event->auxtrace_error.ip = bswap_64(event->auxtrace_error.ip);
591}
592
481typedef void (*perf_event__swap_op)(union perf_event *event, 593typedef void (*perf_event__swap_op)(union perf_event *event,
482 bool sample_id_all); 594 bool sample_id_all);
483 595
@@ -492,11 +604,16 @@ static perf_event__swap_op perf_event__swap_ops[] = {
492 [PERF_RECORD_THROTTLE] = perf_event__throttle_swap, 604 [PERF_RECORD_THROTTLE] = perf_event__throttle_swap,
493 [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap, 605 [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap,
494 [PERF_RECORD_SAMPLE] = perf_event__all64_swap, 606 [PERF_RECORD_SAMPLE] = perf_event__all64_swap,
607 [PERF_RECORD_AUX] = perf_event__aux_swap,
608 [PERF_RECORD_ITRACE_START] = perf_event__itrace_start_swap,
495 [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, 609 [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,
496 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, 610 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
497 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, 611 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
498 [PERF_RECORD_HEADER_BUILD_ID] = NULL, 612 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
499 [PERF_RECORD_ID_INDEX] = perf_event__all64_swap, 613 [PERF_RECORD_ID_INDEX] = perf_event__all64_swap,
614 [PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap,
615 [PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap,
616 [PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap,
500 [PERF_RECORD_HEADER_MAX] = NULL, 617 [PERF_RECORD_HEADER_MAX] = NULL,
501}; 618};
502 619
@@ -938,12 +1055,34 @@ static int machines__deliver_event(struct machines *machines,
938 return tool->throttle(tool, event, sample, machine); 1055 return tool->throttle(tool, event, sample, machine);
939 case PERF_RECORD_UNTHROTTLE: 1056 case PERF_RECORD_UNTHROTTLE:
940 return tool->unthrottle(tool, event, sample, machine); 1057 return tool->unthrottle(tool, event, sample, machine);
1058 case PERF_RECORD_AUX:
1059 return tool->aux(tool, event, sample, machine);
1060 case PERF_RECORD_ITRACE_START:
1061 return tool->itrace_start(tool, event, sample, machine);
941 default: 1062 default:
942 ++evlist->stats.nr_unknown_events; 1063 ++evlist->stats.nr_unknown_events;
943 return -1; 1064 return -1;
944 } 1065 }
945} 1066}
946 1067
1068static int perf_session__deliver_event(struct perf_session *session,
1069 union perf_event *event,
1070 struct perf_sample *sample,
1071 struct perf_tool *tool,
1072 u64 file_offset)
1073{
1074 int ret;
1075
1076 ret = auxtrace__process_event(session, event, sample, tool);
1077 if (ret < 0)
1078 return ret;
1079 if (ret > 0)
1080 return 0;
1081
1082 return machines__deliver_event(&session->machines, session->evlist,
1083 event, sample, tool, file_offset);
1084}
1085
947static s64 perf_session__process_user_event(struct perf_session *session, 1086static s64 perf_session__process_user_event(struct perf_session *session,
948 union perf_event *event, 1087 union perf_event *event,
949 u64 file_offset) 1088 u64 file_offset)
@@ -980,6 +1119,15 @@ static s64 perf_session__process_user_event(struct perf_session *session,
980 return tool->finished_round(tool, event, oe); 1119 return tool->finished_round(tool, event, oe);
981 case PERF_RECORD_ID_INDEX: 1120 case PERF_RECORD_ID_INDEX:
982 return tool->id_index(tool, event, session); 1121 return tool->id_index(tool, event, session);
1122 case PERF_RECORD_AUXTRACE_INFO:
1123 return tool->auxtrace_info(tool, event, session);
1124 case PERF_RECORD_AUXTRACE:
1125 /* setup for reading amidst mmap */
1126 lseek(fd, file_offset + event->header.size, SEEK_SET);
1127 return tool->auxtrace(tool, event, session);
1128 case PERF_RECORD_AUXTRACE_ERROR:
1129 perf_session__auxtrace_error_inc(session, event);
1130 return tool->auxtrace_error(tool, event, session);
983 default: 1131 default:
984 return -EINVAL; 1132 return -EINVAL;
985 } 1133 }
@@ -1096,8 +1244,8 @@ static s64 perf_session__process_event(struct perf_session *session,
1096 return ret; 1244 return ret;
1097 } 1245 }
1098 1246
1099 return machines__deliver_event(&session->machines, evlist, event, 1247 return perf_session__deliver_event(session, event, &sample, tool,
1100 &sample, tool, file_offset); 1248 file_offset);
1101} 1249}
1102 1250
1103void perf_event_header__bswap(struct perf_event_header *hdr) 1251void perf_event_header__bswap(struct perf_event_header *hdr)
@@ -1168,6 +1316,8 @@ static void perf_session__warn_about_errors(const struct perf_session *session)
1168 1316
1169 if (oe->nr_unordered_events != 0) 1317 if (oe->nr_unordered_events != 0)
1170 ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events); 1318 ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events);
1319
1320 events_stats__auxtrace_error_warn(stats);
1171} 1321}
1172 1322
1173volatile int session_done; 1323volatile int session_done;
@@ -1256,10 +1406,14 @@ more:
1256done: 1406done:
1257 /* do the final flush for ordered samples */ 1407 /* do the final flush for ordered samples */
1258 err = ordered_events__flush(oe, OE_FLUSH__FINAL); 1408 err = ordered_events__flush(oe, OE_FLUSH__FINAL);
1409 if (err)
1410 goto out_err;
1411 err = auxtrace__flush_events(session, tool);
1259out_err: 1412out_err:
1260 free(buf); 1413 free(buf);
1261 perf_session__warn_about_errors(session); 1414 perf_session__warn_about_errors(session);
1262 ordered_events__free(&session->ordered_events); 1415 ordered_events__free(&session->ordered_events);
1416 auxtrace__free_events(session);
1263 return err; 1417 return err;
1264} 1418}
1265 1419
@@ -1402,10 +1556,14 @@ more:
1402out: 1556out:
1403 /* do the final flush for ordered samples */ 1557 /* do the final flush for ordered samples */
1404 err = ordered_events__flush(oe, OE_FLUSH__FINAL); 1558 err = ordered_events__flush(oe, OE_FLUSH__FINAL);
1559 if (err)
1560 goto out_err;
1561 err = auxtrace__flush_events(session, tool);
1405out_err: 1562out_err:
1406 ui_progress__finish(); 1563 ui_progress__finish();
1407 perf_session__warn_about_errors(session); 1564 perf_session__warn_about_errors(session);
1408 ordered_events__free(&session->ordered_events); 1565 ordered_events__free(&session->ordered_events);
1566 auxtrace__free_events(session);
1409 session->one_mmap = false; 1567 session->one_mmap = false;
1410 return err; 1568 return err;
1411} 1569}
@@ -1488,7 +1646,13 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp
1488 1646
1489size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) 1647size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1490{ 1648{
1491 size_t ret = fprintf(fp, "Aggregated stats:\n"); 1649 size_t ret;
1650 const char *msg = "";
1651
1652 if (perf_header__has_feat(&session->header, HEADER_AUXTRACE))
1653 msg = " (excludes AUX area (e.g. instruction trace) decoded / synthesized events)";
1654
1655 ret = fprintf(fp, "Aggregated stats:%s\n", msg);
1492 1656
1493 ret += events_stats__fprintf(&session->evlist->stats, fp); 1657 ret += events_stats__fprintf(&session->evlist->stats, fp);
1494 return ret; 1658 return ret;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index d5fa7b7916ef..b44afc75d1cc 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -15,10 +15,16 @@
15struct ip_callchain; 15struct ip_callchain;
16struct thread; 16struct thread;
17 17
18struct auxtrace;
19struct itrace_synth_opts;
20
18struct perf_session { 21struct perf_session {
19 struct perf_header header; 22 struct perf_header header;
20 struct machines machines; 23 struct machines machines;
21 struct perf_evlist *evlist; 24 struct perf_evlist *evlist;
25 struct auxtrace *auxtrace;
26 struct itrace_synth_opts *itrace_synth_opts;
27 struct list_head auxtrace_index;
22 struct trace_event tevent; 28 struct trace_event tevent;
23 bool repipe; 29 bool repipe;
24 bool one_mmap; 30 bool one_mmap;
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 846036a921dc..e97cd476d336 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -58,15 +58,16 @@ struct he_stat {
58 58
59struct hist_entry_diff { 59struct hist_entry_diff {
60 bool computed; 60 bool computed;
61 union {
62 /* PERF_HPP__DELTA */
63 double period_ratio_delta;
61 64
62 /* PERF_HPP__DELTA */ 65 /* PERF_HPP__RATIO */
63 double period_ratio_delta; 66 double period_ratio;
64
65 /* PERF_HPP__RATIO */
66 double period_ratio;
67 67
68 /* HISTC_WEIGHTED_DIFF */ 68 /* HISTC_WEIGHTED_DIFF */
69 s64 wdiff; 69 s64 wdiff;
70 };
70}; 71};
71 72
72/** 73/**
@@ -92,21 +93,28 @@ struct hist_entry {
92 s32 cpu; 93 s32 cpu;
93 u8 cpumode; 94 u8 cpumode;
94 95
95 struct hist_entry_diff diff;
96
97 /* We are added by hists__add_dummy_entry. */ 96 /* We are added by hists__add_dummy_entry. */
98 bool dummy; 97 bool dummy;
99 98
100 /* XXX These two should move to some tree widget lib */
101 u16 row_offset;
102 u16 nr_rows;
103
104 bool init_have_children;
105 char level; 99 char level;
106 u8 filtered; 100 u8 filtered;
101 union {
102 /*
103 * Since perf diff only supports the stdio output, TUI
104 * fields are only accessed from perf report (or perf
105 * top). So make it an union to reduce memory usage.
106 */
107 struct hist_entry_diff diff;
108 struct /* for TUI */ {
109 u16 row_offset;
110 u16 nr_rows;
111 bool init_have_children;
112 bool unfolded;
113 bool has_children;
114 };
115 };
107 char *srcline; 116 char *srcline;
108 struct symbol *parent; 117 struct symbol *parent;
109 unsigned long position;
110 struct rb_root sorted_chain; 118 struct rb_root sorted_chain;
111 struct branch_info *branch_info; 119 struct branch_info *branch_info;
112 struct hists *hists; 120 struct hists *hists;
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
index 79a757a2a15c..bcae659b6546 100644
--- a/tools/perf/util/strfilter.c
+++ b/tools/perf/util/strfilter.c
@@ -170,6 +170,46 @@ struct strfilter *strfilter__new(const char *rules, const char **err)
170 return filter; 170 return filter;
171} 171}
172 172
173static int strfilter__append(struct strfilter *filter, bool _or,
174 const char *rules, const char **err)
175{
176 struct strfilter_node *right, *root;
177 const char *ep = NULL;
178
179 if (!filter || !rules)
180 return -EINVAL;
181
182 right = strfilter_node__new(rules, &ep);
183 if (!right || *ep != '\0') {
184 if (err)
185 *err = ep;
186 goto error;
187 }
188 root = strfilter_node__alloc(_or ? OP_or : OP_and, filter->root, right);
189 if (!root) {
190 ep = NULL;
191 goto error;
192 }
193
194 filter->root = root;
195 return 0;
196
197error:
198 strfilter_node__delete(right);
199 return ep ? -EINVAL : -ENOMEM;
200}
201
202int strfilter__or(struct strfilter *filter, const char *rules, const char **err)
203{
204 return strfilter__append(filter, true, rules, err);
205}
206
207int strfilter__and(struct strfilter *filter, const char *rules,
208 const char **err)
209{
210 return strfilter__append(filter, false, rules, err);
211}
212
173static bool strfilter_node__compare(struct strfilter_node *node, 213static bool strfilter_node__compare(struct strfilter_node *node,
174 const char *str) 214 const char *str)
175{ 215{
@@ -197,3 +237,70 @@ bool strfilter__compare(struct strfilter *filter, const char *str)
197 return false; 237 return false;
198 return strfilter_node__compare(filter->root, str); 238 return strfilter_node__compare(filter->root, str);
199} 239}
240
241static int strfilter_node__sprint(struct strfilter_node *node, char *buf);
242
243/* sprint node in parenthesis if needed */
244static int strfilter_node__sprint_pt(struct strfilter_node *node, char *buf)
245{
246 int len;
247 int pt = node->r ? 2 : 0; /* don't need to check node->l */
248
249 if (buf && pt)
250 *buf++ = '(';
251 len = strfilter_node__sprint(node, buf);
252 if (len < 0)
253 return len;
254 if (buf && pt)
255 *(buf + len) = ')';
256 return len + pt;
257}
258
259static int strfilter_node__sprint(struct strfilter_node *node, char *buf)
260{
261 int len = 0, rlen;
262
263 if (!node || !node->p)
264 return -EINVAL;
265
266 switch (*node->p) {
267 case '|':
268 case '&':
269 len = strfilter_node__sprint_pt(node->l, buf);
270 if (len < 0)
271 return len;
272 case '!':
273 if (buf) {
274 *(buf + len++) = *node->p;
275 buf += len;
276 } else
277 len++;
278 rlen = strfilter_node__sprint_pt(node->r, buf);
279 if (rlen < 0)
280 return rlen;
281 len += rlen;
282 break;
283 default:
284 len = strlen(node->p);
285 if (buf)
286 strcpy(buf, node->p);
287 }
288
289 return len;
290}
291
292char *strfilter__string(struct strfilter *filter)
293{
294 int len;
295 char *ret = NULL;
296
297 len = strfilter_node__sprint(filter->root, NULL);
298 if (len < 0)
299 return NULL;
300
301 ret = malloc(len + 1);
302 if (ret)
303 strfilter_node__sprint(filter->root, ret);
304
305 return ret;
306}
diff --git a/tools/perf/util/strfilter.h b/tools/perf/util/strfilter.h
index fe611f3c9e39..cff5eda88728 100644
--- a/tools/perf/util/strfilter.h
+++ b/tools/perf/util/strfilter.h
@@ -29,6 +29,32 @@ struct strfilter {
29struct strfilter *strfilter__new(const char *rules, const char **err); 29struct strfilter *strfilter__new(const char *rules, const char **err);
30 30
31/** 31/**
32 * strfilter__or - Append an additional rule by logical-or
33 * @filter: Original string filter
34 * @rules: Filter rule to be appended at left of the root of
35 * @filter by using logical-or.
36 * @err: Pointer which points an error detected on @rules
37 *
38 * Parse @rules and join it to the @filter by using logical-or.
39 * Return 0 if success, or return the error code.
40 */
41int strfilter__or(struct strfilter *filter,
42 const char *rules, const char **err);
43
44/**
45 * strfilter__add - Append an additional rule by logical-and
46 * @filter: Original string filter
47 * @rules: Filter rule to be appended at left of the root of
48 * @filter by using logical-and.
49 * @err: Pointer which points an error detected on @rules
50 *
51 * Parse @rules and join it to the @filter by using logical-and.
52 * Return 0 if success, or return the error code.
53 */
54int strfilter__and(struct strfilter *filter,
55 const char *rules, const char **err);
56
57/**
32 * strfilter__compare - compare given string and a string filter 58 * strfilter__compare - compare given string and a string filter
33 * @filter: String filter 59 * @filter: String filter
34 * @str: target string 60 * @str: target string
@@ -45,4 +71,13 @@ bool strfilter__compare(struct strfilter *filter, const char *str);
45 */ 71 */
46void strfilter__delete(struct strfilter *filter); 72void strfilter__delete(struct strfilter *filter);
47 73
74/**
75 * strfilter__string - Reconstruct a rule string from filter
76 * @filter: String filter to reconstruct
77 *
78 * Reconstruct a rule string from @filter. This will be good for
79 * debug messages. Note that returning string must be freed afterward.
80 */
81char *strfilter__string(struct strfilter *filter);
82
48#endif 83#endif
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index a7ab6063e038..9d526a5312b1 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -630,6 +630,11 @@ void symsrc__destroy(struct symsrc *ss)
630 close(ss->fd); 630 close(ss->fd);
631} 631}
632 632
633bool __weak elf__needs_adjust_symbols(GElf_Ehdr ehdr)
634{
635 return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL;
636}
637
633int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, 638int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
634 enum dso_binary_type type) 639 enum dso_binary_type type)
635{ 640{
@@ -678,6 +683,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
678 } 683 }
679 684
680 if (!dso__build_id_equal(dso, build_id)) { 685 if (!dso__build_id_equal(dso, build_id)) {
686 pr_debug("%s: build id mismatch for %s.\n", __func__, name);
681 dso->load_errno = DSO_LOAD_ERRNO__MISMATCHING_BUILDID; 687 dso->load_errno = DSO_LOAD_ERRNO__MISMATCHING_BUILDID;
682 goto out_elf_end; 688 goto out_elf_end;
683 } 689 }
@@ -711,8 +717,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
711 ".gnu.prelink_undo", 717 ".gnu.prelink_undo",
712 NULL) != NULL); 718 NULL) != NULL);
713 } else { 719 } else {
714 ss->adjust_symbols = ehdr.e_type == ET_EXEC || 720 ss->adjust_symbols = elf__needs_adjust_symbols(ehdr);
715 ehdr.e_type == ET_REL;
716 } 721 }
717 722
718 ss->name = strdup(name); 723 ss->name = strdup(name);
@@ -771,6 +776,8 @@ static bool want_demangle(bool is_kernel_sym)
771 return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; 776 return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
772} 777}
773 778
779void __weak arch__elf_sym_adjust(GElf_Sym *sym __maybe_unused) { }
780
774int dso__load_sym(struct dso *dso, struct map *map, 781int dso__load_sym(struct dso *dso, struct map *map,
775 struct symsrc *syms_ss, struct symsrc *runtime_ss, 782 struct symsrc *syms_ss, struct symsrc *runtime_ss,
776 symbol_filter_t filter, int kmodule) 783 symbol_filter_t filter, int kmodule)
@@ -935,6 +942,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
935 (sym.st_value & 1)) 942 (sym.st_value & 1))
936 --sym.st_value; 943 --sym.st_value;
937 944
945 arch__elf_sym_adjust(&sym);
946
938 if (dso->kernel || kmodule) { 947 if (dso->kernel || kmodule) {
939 char dso_name[PATH_MAX]; 948 char dso_name[PATH_MAX];
940 949
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 201f6c4ca738..45ba48a7acb3 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -85,8 +85,17 @@ static int prefix_underscores_count(const char *str)
85 return tail - str; 85 return tail - str;
86} 86}
87 87
88#define SYMBOL_A 0 88int __weak arch__choose_best_symbol(struct symbol *syma,
89#define SYMBOL_B 1 89 struct symbol *symb __maybe_unused)
90{
91 /* Avoid "SyS" kernel syscall aliases */
92 if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3))
93 return SYMBOL_B;
94 if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10))
95 return SYMBOL_B;
96
97 return SYMBOL_A;
98}
90 99
91static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 100static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
92{ 101{
@@ -134,13 +143,7 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
134 else if (na < nb) 143 else if (na < nb)
135 return SYMBOL_B; 144 return SYMBOL_B;
136 145
137 /* Avoid "SyS" kernel syscall aliases */ 146 return arch__choose_best_symbol(syma, symb);
138 if (na >= 3 && !strncmp(syma->name, "SyS", 3))
139 return SYMBOL_B;
140 if (na >= 10 && !strncmp(syma->name, "compat_SyS", 10))
141 return SYMBOL_B;
142
143 return SYMBOL_A;
144} 147}
145 148
146void symbols__fixup_duplicate(struct rb_root *symbols) 149void symbols__fixup_duplicate(struct rb_root *symbols)
@@ -408,7 +411,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
408 int cmp; 411 int cmp;
409 412
410 s = rb_entry(n, struct symbol_name_rb_node, rb_node); 413 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
411 cmp = strcmp(name, s->sym.name); 414 cmp = arch__compare_symbol_names(name, s->sym.name);
412 415
413 if (cmp < 0) 416 if (cmp < 0)
414 n = n->rb_left; 417 n = n->rb_left;
@@ -426,7 +429,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
426 struct symbol_name_rb_node *tmp; 429 struct symbol_name_rb_node *tmp;
427 430
428 tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 431 tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
429 if (strcmp(tmp->sym.name, s->sym.name)) 432 if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
430 break; 433 break;
431 434
432 s = tmp; 435 s = tmp;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 09561500164a..bef47ead1d9b 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -158,8 +158,6 @@ struct ref_reloc_sym {
158struct map_symbol { 158struct map_symbol {
159 struct map *map; 159 struct map *map;
160 struct symbol *sym; 160 struct symbol *sym;
161 bool unfolded;
162 bool has_children;
163}; 161};
164 162
165struct addr_map_symbol { 163struct addr_map_symbol {
@@ -303,4 +301,14 @@ int setup_list(struct strlist **list, const char *list_str,
303int setup_intlist(struct intlist **list, const char *list_str, 301int setup_intlist(struct intlist **list, const char *list_str,
304 const char *list_name); 302 const char *list_name);
305 303
304#ifdef HAVE_LIBELF_SUPPORT
305bool elf__needs_adjust_symbols(GElf_Ehdr ehdr);
306void arch__elf_sym_adjust(GElf_Sym *sym);
307#endif
308
309#define SYMBOL_A 0
310#define SYMBOL_B 1
311
312int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb);
313
306#endif /* __PERF_SYMBOL */ 314#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index 51d9e56c0f84..7f282ad1d2bd 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -3,6 +3,8 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5 5
6#include <linux/types.h>
7
6struct perf_session; 8struct perf_session;
7union perf_event; 9union perf_event;
8struct perf_evlist; 10struct perf_evlist;
@@ -29,6 +31,9 @@ typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
29typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event, 31typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event,
30 struct ordered_events *oe); 32 struct ordered_events *oe);
31 33
34typedef s64 (*event_op3)(struct perf_tool *tool, union perf_event *event,
35 struct perf_session *session);
36
32struct perf_tool { 37struct perf_tool {
33 event_sample sample, 38 event_sample sample,
34 read; 39 read;
@@ -38,13 +43,18 @@ struct perf_tool {
38 fork, 43 fork,
39 exit, 44 exit,
40 lost, 45 lost,
46 aux,
47 itrace_start,
41 throttle, 48 throttle,
42 unthrottle; 49 unthrottle;
43 event_attr_op attr; 50 event_attr_op attr;
44 event_op2 tracing_data; 51 event_op2 tracing_data;
45 event_oe finished_round; 52 event_oe finished_round;
46 event_op2 build_id, 53 event_op2 build_id,
47 id_index; 54 id_index,
55 auxtrace_info,
56 auxtrace_error;
57 event_op3 auxtrace;
48 bool ordered_events; 58 bool ordered_events;
49 bool ordering_requires_timestamps; 59 bool ordering_requires_timestamps;
50}; 60};