aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/Makefile4
-rw-r--r--tools/perf/Documentation/perf-annotate.txt10
-rw-r--r--tools/perf/Documentation/perf-archive.txt2
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt7
-rw-r--r--tools/perf/Documentation/perf-diff.txt4
-rw-r--r--tools/perf/Documentation/perf-evlist.txt4
-rw-r--r--tools/perf/Documentation/perf-mem.txt48
-rw-r--r--tools/perf/Documentation/perf-record.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt49
-rw-r--r--tools/perf/Documentation/perf-script-python.txt2
-rw-r--r--tools/perf/Documentation/perf-stat.txt19
-rw-r--r--tools/perf/Documentation/perf-test.txt4
-rw-r--r--tools/perf/Documentation/perf-top.txt8
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile681
-rw-r--r--tools/perf/arch/arm/util/dwarf-regs.c5
-rw-r--r--tools/perf/arch/common.c1
-rw-r--r--tools/perf/arch/powerpc/util/dwarf-regs.c5
-rw-r--r--tools/perf/arch/s390/util/dwarf-regs.c2
-rw-r--r--tools/perf/arch/sh/util/dwarf-regs.c2
-rw-r--r--tools/perf/arch/sparc/util/dwarf-regs.c2
-rw-r--r--tools/perf/arch/x86/util/dwarf-regs.c2
-rw-r--r--tools/perf/bench/bench.h25
-rw-r--r--tools/perf/bench/numa.c1731
-rw-r--r--tools/perf/builtin-annotate.c53
-rw-r--r--tools/perf/builtin-bench.c19
-rw-r--r--tools/perf/builtin-buildid-cache.c96
-rw-r--r--tools/perf/builtin-buildid-list.c21
-rw-r--r--tools/perf/builtin-diff.c231
-rw-r--r--tools/perf/builtin-evlist.c88
-rw-r--r--tools/perf/builtin-kmem.c16
-rw-r--r--tools/perf/builtin-kvm.c8
-rw-r--r--tools/perf/builtin-mem.c242
-rw-r--r--tools/perf/builtin-probe.c2
-rw-r--r--tools/perf/builtin-record.c191
-rw-r--r--tools/perf/builtin-report.c305
-rw-r--r--tools/perf/builtin-sched.c7
-rw-r--r--tools/perf/builtin-script.c17
-rw-r--r--tools/perf/builtin-stat.c568
-rw-r--r--tools/perf/builtin-top.c449
-rw-r--r--tools/perf/builtin-trace.c30
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt15
-rw-r--r--tools/perf/config/Makefile477
-rw-r--r--tools/perf/config/feature-tests.mak21
-rw-r--r--tools/perf/config/utilities.mak6
-rw-r--r--tools/perf/perf.c44
-rw-r--r--tools/perf/perf.h45
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report3
-rw-r--r--tools/perf/scripts/perl/rwtop.pl6
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl129
-rwxr-xr-xtools/perf/scripts/python/net_dropmonitor.py39
-rw-r--r--tools/perf/tests/attr.c18
-rw-r--r--tools/perf/tests/attr.py26
-rw-r--r--tools/perf/tests/attr/base-record7
-rw-r--r--tools/perf/tests/attr/base-stat5
-rw-r--r--tools/perf/tests/attr/test-record-C013
-rw-r--r--tools/perf/tests/attr/test-record-data5
-rw-r--r--tools/perf/tests/attr/test-record-group2
-rw-r--r--tools/perf/tests/attr/test-record-group14
-rw-r--r--tools/perf/tests/attr/test-stat-C09
-rw-r--r--tools/perf/tests/bp_signal.c192
-rw-r--r--tools/perf/tests/bp_signal_overflow.c132
-rw-r--r--tools/perf/tests/builtin-test.c56
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c8
-rw-r--r--tools/perf/tests/hists_link.c500
-rw-r--r--tools/perf/tests/make138
-rw-r--r--tools/perf/tests/mmap-basic.c42
-rw-r--r--tools/perf/tests/open-syscall-all-cpus.c19
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c10
-rw-r--r--tools/perf/tests/open-syscall.c17
-rw-r--r--tools/perf/tests/parse-events.c328
-rw-r--r--tools/perf/tests/perf-record.c27
-rw-r--r--tools/perf/tests/pmu.c11
-rw-r--r--tools/perf/tests/python-use.c23
-rw-r--r--tools/perf/tests/sw-clock.c119
-rw-r--r--tools/perf/tests/task-exit.c123
-rw-r--r--tools/perf/tests/tests.h15
-rw-r--r--tools/perf/tests/util.c30
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c7
-rw-r--r--tools/perf/ui/browser.c15
-rw-r--r--tools/perf/ui/browser.h1
-rw-r--r--tools/perf/ui/browsers/annotate.c191
-rw-r--r--tools/perf/ui/browsers/hists.c448
-rw-r--r--tools/perf/ui/browsers/map.c60
-rw-r--r--tools/perf/ui/browsers/scripts.c1
-rw-r--r--tools/perf/ui/gtk/annotate.c245
-rw-r--r--tools/perf/ui/gtk/browser.c235
-rw-r--r--tools/perf/ui/gtk/gtk.h10
-rw-r--r--tools/perf/ui/gtk/helpline.c23
-rw-r--r--tools/perf/ui/gtk/hists.c316
-rw-r--r--tools/perf/ui/helpline.c12
-rw-r--r--tools/perf/ui/helpline.h22
-rw-r--r--tools/perf/ui/hist.c480
-rw-r--r--tools/perf/ui/keysyms.h1
-rw-r--r--tools/perf/ui/setup.c3
-rw-r--r--tools/perf/ui/stdio/hist.c32
-rw-r--r--tools/perf/ui/tui/helpline.c29
-rw-r--r--tools/perf/ui/tui/setup.c21
-rw-r--r--tools/perf/ui/ui.h2
-rw-r--r--tools/perf/ui/util.c1
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN4
-rw-r--r--tools/perf/util/annotate.c264
-rw-r--r--tools/perf/util/annotate.h63
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h5
-rw-r--r--tools/perf/util/cpumap.c116
-rw-r--r--tools/perf/util/cpumap.h21
-rw-r--r--tools/perf/util/debug.c28
-rw-r--r--tools/perf/util/debug.h34
-rw-r--r--tools/perf/util/debugfs.c114
-rw-r--r--tools/perf/util/debugfs.h12
-rw-r--r--tools/perf/util/dso.c6
-rw-r--r--tools/perf/util/dso.h2
-rw-r--r--tools/perf/util/event.c4
-rw-r--r--tools/perf/util/event.h9
-rw-r--r--tools/perf/util/evlist.c109
-rw-r--r--tools/perf/util/evlist.h43
-rw-r--r--tools/perf/util/evsel.c402
-rw-r--r--tools/perf/util/evsel.h75
-rw-r--r--tools/perf/util/header.c283
-rw-r--r--tools/perf/util/header.h3
-rw-r--r--tools/perf/util/hist.c334
-rw-r--r--tools/perf/util/hist.h75
-rw-r--r--tools/perf/util/include/linux/bitops.h1
-rw-r--r--tools/perf/util/intlist.c36
-rw-r--r--tools/perf/util/intlist.h2
-rw-r--r--tools/perf/util/machine.c826
-rw-r--r--tools/perf/util/machine.h45
-rw-r--r--tools/perf/util/map.c122
-rw-r--r--tools/perf/util/map.h24
-rw-r--r--tools/perf/util/parse-events.c98
-rw-r--r--tools/perf/util/parse-events.h22
-rw-r--r--tools/perf/util/parse-events.y75
-rw-r--r--tools/perf/util/pmu.c46
-rw-r--r--tools/perf/util/pmu.h15
-rw-r--r--tools/perf/util/pmu.y1
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/probe-finder.c10
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/python.c9
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c341
-rw-r--r--tools/perf/util/session.h37
-rw-r--r--tools/perf/util/setup.py8
-rw-r--r--tools/perf/util/sort.c735
-rw-r--r--tools/perf/util/sort.h45
-rw-r--r--tools/perf/util/stat.c2
-rw-r--r--tools/perf/util/string.c18
-rw-r--r--tools/perf/util/strlist.c54
-rw-r--r--tools/perf/util/strlist.h42
-rw-r--r--tools/perf/util/symbol-elf.c23
-rw-r--r--tools/perf/util/symbol-minimal.c1
-rw-r--r--tools/perf/util/symbol.c537
-rw-r--r--tools/perf/util/symbol.h16
-rw-r--r--tools/perf/util/sysfs.c2
-rw-r--r--tools/perf/util/thread.c22
-rw-r--r--tools/perf/util/thread.h2
-rw-r--r--tools/perf/util/thread_map.h5
-rw-r--r--tools/perf/util/top.c45
-rw-r--r--tools/perf/util/top.h12
-rw-r--r--tools/perf/util/trace-event-info.c380
-rw-r--r--tools/perf/util/trace-event-parse.c37
-rw-r--r--tools/perf/util/trace-event-read.c473
-rw-r--r--tools/perf/util/trace-event.h6
-rw-r--r--tools/perf/util/util.c51
-rw-r--r--tools/perf/util/util.h15
169 files changed, 11173 insertions, 4871 deletions
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index ef6d22e879eb..eb30044a922a 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -222,10 +222,14 @@ install-pdf: pdf
222#install-html: html 222#install-html: html
223# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) 223# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
224 224
225ifneq ($(MAKECMDGOALS),clean)
226ifneq ($(MAKECMDGOALS),tags)
225$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 227$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
226 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE 228 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE
227 229
228-include $(OUTPUT)PERF-VERSION-FILE 230-include $(OUTPUT)PERF-VERSION-FILE
231endif
232endif
229 233
230# 234#
231# Determine "include::" file references in asciidoc files. 235# Determine "include::" file references in asciidoc files.
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index c8ffd9fd5c6a..e9cd39a92dc2 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -61,11 +61,13 @@ OPTIONS
61 61
62--stdio:: Use the stdio interface. 62--stdio:: Use the stdio interface.
63 63
64--tui:: Use the TUI interface Use of --tui requires a tty, if one is not 64--tui:: Use the TUI interface. Use of --tui requires a tty, if one is not
65 present, as when piping to other commands, the stdio interface is 65 present, as when piping to other commands, the stdio interface is
66 used. This interfaces starts by centering on the line with more 66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples. 67 samples, TAB/UNTAB cycles through the lines with more samples.
68 68
69--gtk:: Use the GTK interface.
70
69-C:: 71-C::
70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 72--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
71 be provided as a comma-separated list with no space: 0,1. Ranges of 73 be provided as a comma-separated list with no space: 0,1. Ranges of
@@ -88,6 +90,12 @@ OPTIONS
88--objdump=<path>:: 90--objdump=<path>::
89 Path to objdump binary. 91 Path to objdump binary.
90 92
93--skip-missing::
94 Skip symbols that cannot be annotated.
95
96--group::
97 Show event group information together
98
91SEE ALSO 99SEE ALSO
92-------- 100--------
93linkperf:perf-record[1], linkperf:perf-report[1] 101linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt
index fae174dc7d01..5032a142853e 100644
--- a/tools/perf/Documentation/perf-archive.txt
+++ b/tools/perf/Documentation/perf-archive.txt
@@ -13,7 +13,7 @@ SYNOPSIS
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command runs runs perf-buildid-list --with-hits, and collects the files 15This command runs runs perf-buildid-list --with-hits, and collects the files
16with the buildids found so that analisys of perf.data contents can be possible 16with the buildids found so that analysis of perf.data contents can be possible
17on another machine. 17on another machine.
18 18
19 19
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index c1057701a7dc..e9a8349a7172 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -24,6 +24,13 @@ OPTIONS
24-r:: 24-r::
25--remove=:: 25--remove=::
26 Remove specified file from the cache. 26 Remove specified file from the cache.
27-M::
28--missing=::
29 List missing build ids in the cache for the specified file.
30-u::
31--update::
32 Update specified file of the cache. It can be used to update kallsyms
33 kernel dso to vmlinux in order to support annotation.
27-v:: 34-v::
28--verbose:: 35--verbose::
29 Be more verbose. 36 Be more verbose.
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 194f37d635df..5b3123d5721f 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -22,10 +22,6 @@ specified perf.data files.
22 22
23OPTIONS 23OPTIONS
24------- 24-------
25-M::
26--displacement::
27 Show position displacement relative to baseline.
28
29-D:: 25-D::
30--dump-raw-trace:: 26--dump-raw-trace::
31 Dump raw trace in ASCII. 27 Dump raw trace in ASCII.
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 15217345c2fa..1ceb3700ffbb 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -28,6 +28,10 @@ OPTIONS
28--verbose=:: 28--verbose=::
29 Show all fields. 29 Show all fields.
30 30
31-g::
32--group::
33 Show event group information.
34
31SEE ALSO 35SEE ALSO
32-------- 36--------
33linkperf:perf-record[1], linkperf:perf-list[1], 37linkperf:perf-record[1], linkperf:perf-list[1],
diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt
new file mode 100644
index 000000000000..888d51137fbe
--- /dev/null
+++ b/tools/perf/Documentation/perf-mem.txt
@@ -0,0 +1,48 @@
1perf-mem(1)
2===========
3
4NAME
5----
6perf-mem - Profile memory accesses
7
8SYNOPSIS
9--------
10[verse]
11'perf mem' [<options>] (record [<command>] | report)
12
13DESCRIPTION
14-----------
15"perf mem -t <TYPE> record" runs a command and gathers memory operation data
16from it, into perf.data. Perf record options are accepted and are passed through.
17
18"perf mem -t <TYPE> report" displays the result. It invokes perf report with the
19right set of options to display a memory access profile.
20
21OPTIONS
22-------
23<command>...::
24 Any command you can specify in a shell.
25
26-t::
27--type=::
28 Select the memory operation type: load or store (default: load)
29
30-D::
31--dump-raw-samples=::
32 Dump the raw decoded samples on the screen in a format that is easy to parse with
33 one sample per line.
34
35-x::
36--field-separator::
37 Specify the field separator used when dump raw samples (-D option). By default,
38 The separator is the space character.
39
40-C::
41--cpu-list::
42 Restrict dump of raw samples to those provided via this option. Note that the same
43 option can be passed in record mode. It will be interpreted the same way as perf
44 record.
45
46SEE ALSO
47--------
48linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 938e8904f64d..d4da111ef53d 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -182,6 +182,12 @@ is enabled for all the sampling events. The sampled branch type is the same for
182The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k 182The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
183Note that this feature may not be available on all processors. 183Note that this feature may not be available on all processors.
184 184
185-W::
186--weight::
187Enable weightened sampling. An additional weight is recorded per sample and can be
188displayed with the weight and local_weight sort keys. This currently works for TSX
189abort events and some memory events in precise mode on modern Intel CPUs.
190
185SEE ALSO 191SEE ALSO
186-------- 192--------
187linkperf:perf-stat[1], linkperf:perf-list[1] 193linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index f4d91bebd59d..66dab7410c1d 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -57,11 +57,44 @@ OPTIONS
57 57
58-s:: 58-s::
59--sort=:: 59--sort=::
60 Sort by key(s): pid, comm, dso, symbol, parent, srcline. 60 Sort histogram entries by given key(s) - multiple keys can be specified
61 in CSV format. Following sort keys are available:
62 pid, comm, dso, symbol, parent, cpu, srcline, weight, local_weight.
63
64 Each key has following meaning:
65
66 - comm: command (name) of the task which can be read via /proc/<pid>/comm
67 - pid: command and tid of the task
68 - dso: name of library or module executed at the time of sample
69 - symbol: name of function executed at the time of sample
70 - parent: name of function matched to the parent regex filter. Unmatched
71 entries are displayed as "[other]".
72 - cpu: cpu number the task ran at the time of sample
73 - srcline: filename and line number executed at the time of sample. The
74 DWARF debuggin info must be provided.
75
76 By default, comm, dso and symbol keys are used.
77 (i.e. --sort comm,dso,symbol)
78
79 If --branch-stack option is used, following sort keys are also
80 available:
81 dso_from, dso_to, symbol_from, symbol_to, mispredict.
82
83 - dso_from: name of library or module branched from
84 - dso_to: name of library or module branched to
85 - symbol_from: name of function branched from
86 - symbol_to: name of function branched to
87 - mispredict: "N" for predicted branch, "Y" for mispredicted branch
88
89 And default sort keys are changed to comm, dso_from, symbol_from, dso_to
90 and symbol_to, see '--branch-stack'.
61 91
62-p:: 92-p::
63--parent=<regex>:: 93--parent=<regex>::
64 regex filter to identify parent, see: '--sort parent' 94 A regex filter to identify parent. The parent is a caller of this
95 function and searched through the callchain, thus it requires callchain
96 information recorded. The pattern is in the exteneded regex format and
97 defaults to "\^sys_|^do_page_fault", see '--sort parent'.
65 98
66-x:: 99-x::
67--exclude-other:: 100--exclude-other::
@@ -74,7 +107,6 @@ OPTIONS
74 107
75-t:: 108-t::
76--field-separator=:: 109--field-separator=::
77
78 Use a special separator character and don't pad with spaces, replacing 110 Use a special separator character and don't pad with spaces, replacing
79 all occurrences of this separator in symbol names (and other output) 111 all occurrences of this separator in symbol names (and other output)
80 with a '.' character, that thus it's the only non valid separator. 112 with a '.' character, that thus it's the only non valid separator.
@@ -171,6 +203,17 @@ OPTIONS
171--objdump=<path>:: 203--objdump=<path>::
172 Path to objdump binary. 204 Path to objdump binary.
173 205
206--group::
207 Show event group information together.
208
209--demangle::
210 Demangle symbol names to human readable form. It's enabled by default,
211 disable with --no-demangle.
212
213--percent-limit::
214 Do not show entries which have an overhead under that percent.
215 (Default: 0).
216
174SEE ALSO 217SEE ALSO
175-------- 218--------
176linkperf:perf-stat[1], linkperf:perf-annotate[1] 219linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
index a4027f221a53..9f1f054b8432 100644
--- a/tools/perf/Documentation/perf-script-python.txt
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -336,7 +336,6 @@ scripts listed by the 'perf script -l' command e.g.:
336---- 336----
337root@tropicana:~# perf script -l 337root@tropicana:~# perf script -l
338List of available trace scripts: 338List of available trace scripts:
339 workqueue-stats workqueue stats (ins/exe/create/destroy)
340 wakeup-latency system-wide min/max/avg wakeup latency 339 wakeup-latency system-wide min/max/avg wakeup latency
341 rw-by-file <comm> r/w activity for a program, by file 340 rw-by-file <comm> r/w activity for a program, by file
342 rw-by-pid system-wide r/w activity 341 rw-by-pid system-wide r/w activity
@@ -402,7 +401,6 @@ should show a new entry for your script:
402---- 401----
403root@tropicana:~# perf script -l 402root@tropicana:~# perf script -l
404List of available trace scripts: 403List of available trace scripts:
405 workqueue-stats workqueue stats (ins/exe/create/destroy)
406 wakeup-latency system-wide min/max/avg wakeup latency 404 wakeup-latency system-wide min/max/avg wakeup latency
407 rw-by-file <comm> r/w activity for a program, by file 405 rw-by-file <comm> r/w activity for a program, by file
408 rw-by-pid system-wide r/w activity 406 rw-by-pid system-wide r/w activity
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index cf0c3107e06e..2fe87fb558f0 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -52,7 +52,7 @@ OPTIONS
52 52
53-r:: 53-r::
54--repeat=<n>:: 54--repeat=<n>::
55 repeat command and print average + stddev (max: 100) 55 repeat command and print average + stddev (max: 100). 0 means forever.
56 56
57-B:: 57-B::
58--big-num:: 58--big-num::
@@ -114,6 +114,23 @@ with it. --append may be used here. Examples:
114 114
115perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage 115perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage
116 116
117-I msecs::
118--interval-print msecs::
119 Print count deltas every N milliseconds (minimum: 100ms)
120 example: perf stat -I 1000 -e cycles -a sleep 5
121
122--per-socket::
123Aggregate counts per processor socket for system-wide mode measurements. This
124is a useful mode to detect imbalance between sockets. To enable this mode,
125use --per-socket in addition to -a. (system-wide). The output includes the
126socket number and the number of online processors on that socket. This is
127useful to gauge the amount of aggregation.
128
129--per-core::
130Aggregate counts per physical processor for system-wide mode measurements. This
131is a useful mode to detect imbalance between physical cores. To enable this mode,
132use --per-core in addition to -a. (system-wide). The output includes the
133core number and the number of online logical processors on that physical processor.
117 134
118EXAMPLES 135EXAMPLES
119-------- 136--------
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index b24ac40fcd58..d1d3e5121f89 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -23,6 +23,10 @@ from 'perf test list'.
23 23
24OPTIONS 24OPTIONS
25------- 25-------
26-s::
27--skip::
28 Tests to skip (comma separater numeric list).
29
26-v:: 30-v::
27--verbose:: 31--verbose::
28 Be more verbose. 32 Be more verbose.
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 5b80d84d6b4a..7fdd1909e376 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -60,7 +60,7 @@ Default is to monitor all CPUS.
60 60
61-i:: 61-i::
62--inherit:: 62--inherit::
63 Child tasks inherit counters, only makes sens with -p option. 63 Child tasks do not inherit counters.
64 64
65-k <path>:: 65-k <path>::
66--vmlinux=<path>:: 66--vmlinux=<path>::
@@ -112,7 +112,7 @@ Default is to monitor all CPUS.
112 112
113-s:: 113-s::
114--sort:: 114--sort::
115 Sort by key(s): pid, comm, dso, symbol, parent, srcline. 115 Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, local_weight.
116 116
117-n:: 117-n::
118--show-nr-samples:: 118--show-nr-samples::
@@ -155,6 +155,10 @@ Default is to monitor all CPUS.
155 155
156 Default: fractal,0.5,callee. 156 Default: fractal,0.5,callee.
157 157
158--percent-limit::
159 Do not show entries which have an overhead under that percent.
160 (Default: 0).
161
158INTERACTIVE PROMPTING KEYS 162INTERACTIVE PROMPTING KEYS
159-------------------------- 163--------------------------
160 164
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 39d41068484f..025de796067c 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,6 +1,7 @@
1tools/perf 1tools/perf
2tools/scripts 2tools/scripts
3tools/lib/traceevent 3tools/lib/traceevent
4tools/lib/lk
4include/linux/const.h 5include/linux/const.h
5include/linux/perf_event.h 6include/linux/perf_event.h
6include/linux/rbtree.h 7include/linux/rbtree.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 8ab05e543ef4..203cb0eecff2 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -35,7 +35,9 @@ include config/utilities.mak
35# 35#
36# Define WERROR=0 to disable treating any warnings as errors. 36# Define WERROR=0 to disable treating any warnings as errors.
37# 37#
38# Define NO_NEWT if you do not want TUI support. 38# Define NO_NEWT if you do not want TUI support. (deprecated)
39#
40# Define NO_SLANG if you do not want TUI support.
39# 41#
40# Define NO_GTK2 if you do not want GTK+ GUI support. 42# Define NO_GTK2 if you do not want GTK+ GUI support.
41# 43#
@@ -47,165 +49,65 @@ include config/utilities.mak
47# backtrace post unwind. 49# backtrace post unwind.
48# 50#
49# Define NO_BACKTRACE if you do not want stack backtrace debug feature 51# Define NO_BACKTRACE if you do not want stack backtrace debug feature
52#
53# Define NO_LIBNUMA if you do not want numa perf benchmark
54#
55# Define NO_LIBAUDIT if you do not want libaudit support
56#
57# Define NO_LIBBIONIC if you do not want bionic support
50 58
51$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 59ifeq ($(srctree),)
52 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 60srctree := $(patsubst %/,%,$(dir $(shell pwd)))
53-include $(OUTPUT)PERF-VERSION-FILE 61srctree := $(patsubst %/,%,$(dir $(srctree)))
54 62#$(info Determined 'srctree' to be $(srctree))
55uname_M := $(shell uname -m 2>/dev/null || echo not)
56
57ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
58 -e s/arm.*/arm/ -e s/sa110/arm/ \
59 -e s/s390x/s390/ -e s/parisc64/parisc/ \
60 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
61 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
62NO_PERF_REGS := 1
63
64CC = $(CROSS_COMPILE)gcc
65AR = $(CROSS_COMPILE)ar
66
67# Additional ARCH settings for x86
68ifeq ($(ARCH),i386)
69 override ARCH := x86
70 NO_PERF_REGS := 0
71 LIBUNWIND_LIBS = -lunwind -lunwind-x86
72endif
73ifeq ($(ARCH),x86_64)
74 override ARCH := x86
75 IS_X86_64 := 0
76 ifeq (, $(findstring m32,$(EXTRA_CFLAGS)))
77 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
78 endif
79 ifeq (${IS_X86_64}, 1)
80 RAW_ARCH := x86_64
81 ARCH_CFLAGS := -DARCH_X86_64
82 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
83 endif
84 NO_PERF_REGS := 0
85 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
86endif
87
88# Treat warnings as errors unless directed not to
89ifneq ($(WERROR),0)
90 CFLAGS_WERROR := -Werror
91endif 63endif
92 64
93ifeq ("$(origin DEBUG)", "command line") 65ifneq ($(objtree),)
94 PERF_DEBUG = $(DEBUG) 66#$(info Determined 'objtree' to be $(objtree))
95endif
96ifndef PERF_DEBUG
97 CFLAGS_OPTIMIZE = -O6 -D_FORTIFY_SOURCE=2
98endif 67endif
99 68
100ifdef PARSER_DEBUG 69ifneq ($(OUTPUT),)
101 PARSER_DEBUG_BISON := -t 70#$(info Determined 'OUTPUT' to be $(OUTPUT))
102 PARSER_DEBUG_FLEX := -d
103 PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
104endif 71endif
105 72
106CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS) 73$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
107EXTLIBS = -lpthread -lrt -lelf -lm 74 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
108ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
109ALL_LDFLAGS = $(LDFLAGS)
110STRIP ?= strip
111
112# Among the variables below, these:
113# perfexecdir
114# template_dir
115# mandir
116# infodir
117# htmldir
118# ETC_PERFCONFIG (but not sysconfdir)
119# can be specified as a relative path some/where/else;
120# this is interpreted as relative to $(prefix) and "perf" at
121# runtime figures out where they are based on the path to the executable.
122# This can help installing the suite in a relocatable way.
123
124# Make the path relative to DESTDIR, not to prefix
125ifndef DESTDIR
126prefix = $(HOME)
127endif
128bindir_relative = bin
129bindir = $(prefix)/$(bindir_relative)
130mandir = share/man
131infodir = share/info
132perfexecdir = libexec/perf-core
133sharedir = $(prefix)/share
134template_dir = share/perf-core/templates
135htmldir = share/doc/perf-doc
136ifeq ($(prefix),/usr)
137sysconfdir = /etc
138ETC_PERFCONFIG = $(sysconfdir)/perfconfig
139else
140sysconfdir = $(prefix)/etc
141ETC_PERFCONFIG = etc/perfconfig
142endif
143lib = lib
144 75
145export prefix bindir sharedir sysconfdir 76CC = $(CROSS_COMPILE)gcc
77AR = $(CROSS_COMPILE)ar
146 78
147RM = rm -f 79RM = rm -f
148MKDIR = mkdir 80MKDIR = mkdir
149FIND = find 81FIND = find
150INSTALL = install 82INSTALL = install
83FLEX = flex
84BISON = bison
85STRIP = strip
151 86
152# sparse is architecture-neutral, which means that we need to tell it 87LK_DIR = $(srctree)/tools/lib/lk/
153# explicitly what architecture to check for. Fix this up for yours.. 88TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
154SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
155
156-include config/feature-tests.mak
157 89
158ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) 90# include config/Makefile by default and rule out
159 CFLAGS := $(CFLAGS) -fstack-protector-all 91# non-config cases
160endif 92config := 1
161 93
162ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y) 94NON_CONFIG_TARGETS := clean TAGS tags cscope help
163 CFLAGS := $(CFLAGS) -Wstack-protector
164endif
165 95
166ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y) 96ifdef MAKECMDGOALS
167 CFLAGS := $(CFLAGS) -Wvolatile-register-var 97ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
98 config := 0
168endif 99endif
169
170### --- END CONFIGURATION SECTION ---
171
172ifeq ($(srctree),)
173srctree := $(patsubst %/,%,$(dir $(shell pwd)))
174srctree := $(patsubst %/,%,$(dir $(srctree)))
175#$(info Determined 'srctree' to be $(srctree))
176endif 100endif
177 101
178ifneq ($(objtree),) 102ifeq ($(config),1)
179#$(info Determined 'objtree' to be $(objtree)) 103include config/Makefile
180endif 104endif
181 105
182ifneq ($(OUTPUT),) 106export prefix bindir sharedir sysconfdir
183#$(info Determined 'OUTPUT' to be $(OUTPUT))
184endif
185 107
186BASIC_CFLAGS = \ 108# sparse is architecture-neutral, which means that we need to tell it
187 -Iutil/include \ 109# explicitly what architecture to check for. Fix this up for yours..
188 -Iarch/$(ARCH)/include \ 110SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
189 $(if $(objtree),-I$(objtree)/arch/$(ARCH)/include/generated/uapi) \
190 -I$(srctree)/arch/$(ARCH)/include/uapi \
191 -I$(srctree)/arch/$(ARCH)/include \
192 $(if $(objtree),-I$(objtree)/include/generated/uapi) \
193 -I$(srctree)/include/uapi \
194 -I$(srctree)/include \
195 -I$(OUTPUT)util \
196 -Iutil \
197 -I. \
198 -I$(TRACE_EVENT_DIR) \
199 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
200
201BASIC_LDFLAGS =
202
203ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
204 BIONIC := 1
205 EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
206 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
207 BASIC_CFLAGS += -I.
208endif
209 111
210# Guard against environment variables 112# Guard against environment variables
211BUILTIN_OBJS = 113BUILTIN_OBJS =
@@ -219,24 +121,38 @@ SCRIPT_SH += perf-archive.sh
219grep-libs = $(filter -l%,$(1)) 121grep-libs = $(filter -l%,$(1))
220strip-libs = $(filter-out -l%,$(1)) 122strip-libs = $(filter-out -l%,$(1))
221 123
222TRACE_EVENT_DIR = ../lib/traceevent/ 124LK_PATH=$(LK_DIR)
223 125
224ifneq ($(OUTPUT),) 126ifneq ($(OUTPUT),)
225 TE_PATH=$(OUTPUT) 127 TE_PATH=$(OUTPUT)
128ifneq ($(subdir),)
129 LK_PATH=$(OUTPUT)$(LK_DIR)
226else 130else
227 TE_PATH=$(TRACE_EVENT_DIR) 131 LK_PATH=$(OUTPUT)
132endif
133else
134 TE_PATH=$(TRACE_EVENT_DIR)
228endif 135endif
229 136
230LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 137LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
231TE_LIB := -L$(TE_PATH) -ltraceevent 138export LIBTRACEEVENT
232 139
233PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) 140LIBLK = $(LK_PATH)liblk.a
234PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py 141export LIBLK
235 142
236export LIBTRACEEVENT 143# python extension build directories
144PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
145PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
146PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
147export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
148
149python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
150
151PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
152PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
237 153
238$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) 154$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
239 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ 155 $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
240 --quiet build_ext; \ 156 --quiet build_ext; \
241 mkdir -p $(OUTPUT)python && \ 157 mkdir -p $(OUTPUT)python && \
242 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ 158 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
@@ -251,8 +167,6 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
251# 167#
252PROGRAMS += $(OUTPUT)perf 168PROGRAMS += $(OUTPUT)perf
253 169
254LANG_BINDINGS =
255
256# what 'all' will build and 'install' will install, in perfexecdir 170# what 'all' will build and 'install' will install, in perfexecdir
257ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 171ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
258 172
@@ -261,28 +175,25 @@ OTHER_PROGRAMS = $(OUTPUT)perf
261 175
262# Set paths to tools early so that they can be used for version tests. 176# Set paths to tools early so that they can be used for version tests.
263ifndef SHELL_PATH 177ifndef SHELL_PATH
264 SHELL_PATH = /bin/sh 178 SHELL_PATH = /bin/sh
265endif 179endif
266ifndef PERL_PATH 180ifndef PERL_PATH
267 PERL_PATH = /usr/bin/perl 181 PERL_PATH = /usr/bin/perl
268endif 182endif
269 183
270export PERL_PATH 184export PERL_PATH
271 185
272FLEX = flex
273BISON= bison
274
275$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c 186$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
276 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c 187 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
277 188
278$(OUTPUT)util/parse-events-bison.c: util/parse-events.y 189$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
279 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c 190 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
280 191
281$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c 192$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
282 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c 193 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
283 194
284$(OUTPUT)util/pmu-bison.c: util/pmu.y 195$(OUTPUT)util/pmu-bison.c: util/pmu.y
285 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c 196 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
286 197
287$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c 198$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
288$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c 199$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
@@ -329,7 +240,6 @@ LIB_H += util/cache.h
329LIB_H += util/callchain.h 240LIB_H += util/callchain.h
330LIB_H += util/build-id.h 241LIB_H += util/build-id.h
331LIB_H += util/debug.h 242LIB_H += util/debug.h
332LIB_H += util/debugfs.h
333LIB_H += util/sysfs.h 243LIB_H += util/sysfs.h
334LIB_H += util/pmu.h 244LIB_H += util/pmu.h
335LIB_H += util/event.h 245LIB_H += util/event.h
@@ -378,8 +288,11 @@ LIB_H += util/rblist.h
378LIB_H += util/intlist.h 288LIB_H += util/intlist.h
379LIB_H += util/perf_regs.h 289LIB_H += util/perf_regs.h
380LIB_H += util/unwind.h 290LIB_H += util/unwind.h
381LIB_H += ui/helpline.h
382LIB_H += util/vdso.h 291LIB_H += util/vdso.h
292LIB_H += ui/helpline.h
293LIB_H += ui/progress.h
294LIB_H += ui/util.h
295LIB_H += ui/ui.h
383 296
384LIB_OBJS += $(OUTPUT)util/abspath.o 297LIB_OBJS += $(OUTPUT)util/abspath.o
385LIB_OBJS += $(OUTPUT)util/alias.o 298LIB_OBJS += $(OUTPUT)util/alias.o
@@ -387,7 +300,6 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
387LIB_OBJS += $(OUTPUT)util/build-id.o 300LIB_OBJS += $(OUTPUT)util/build-id.o
388LIB_OBJS += $(OUTPUT)util/config.o 301LIB_OBJS += $(OUTPUT)util/config.o
389LIB_OBJS += $(OUTPUT)util/ctype.o 302LIB_OBJS += $(OUTPUT)util/ctype.o
390LIB_OBJS += $(OUTPUT)util/debugfs.o
391LIB_OBJS += $(OUTPUT)util/sysfs.o 303LIB_OBJS += $(OUTPUT)util/sysfs.o
392LIB_OBJS += $(OUTPUT)util/pmu.o 304LIB_OBJS += $(OUTPUT)util/pmu.o
393LIB_OBJS += $(OUTPUT)util/environment.o 305LIB_OBJS += $(OUTPUT)util/environment.o
@@ -453,6 +365,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
453LIB_OBJS += $(OUTPUT)ui/setup.o 365LIB_OBJS += $(OUTPUT)ui/setup.o
454LIB_OBJS += $(OUTPUT)ui/helpline.o 366LIB_OBJS += $(OUTPUT)ui/helpline.o
455LIB_OBJS += $(OUTPUT)ui/progress.o 367LIB_OBJS += $(OUTPUT)ui/progress.o
368LIB_OBJS += $(OUTPUT)ui/util.o
456LIB_OBJS += $(OUTPUT)ui/hist.o 369LIB_OBJS += $(OUTPUT)ui/hist.o
457LIB_OBJS += $(OUTPUT)ui/stdio/hist.o 370LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
458 371
@@ -471,7 +384,12 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o
471LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o 384LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
472LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o 385LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
473LIB_OBJS += $(OUTPUT)tests/pmu.o 386LIB_OBJS += $(OUTPUT)tests/pmu.o
474LIB_OBJS += $(OUTPUT)tests/util.o 387LIB_OBJS += $(OUTPUT)tests/hists_link.o
388LIB_OBJS += $(OUTPUT)tests/python-use.o
389LIB_OBJS += $(OUTPUT)tests/bp_signal.o
390LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
391LIB_OBJS += $(OUTPUT)tests/task-exit.o
392LIB_OBJS += $(OUTPUT)tests/sw-clock.o
475 393
476BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 394BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
477BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 395BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -504,78 +422,18 @@ BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
504BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o 422BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
505BUILTIN_OBJS += $(OUTPUT)builtin-inject.o 423BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
506BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o 424BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
425BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
507 426
508PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) 427PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
509
510#
511# Platform specific tweaks
512#
513 428
514# We choose to avoid "if .. else if .. else .. endif endif" 429# We choose to avoid "if .. else if .. else .. endif endif"
515# because maintaining the nesting to match is a pain. If 430# because maintaining the nesting to match is a pain. If
516# we had "elif" things would have been much nicer... 431# we had "elif" things would have been much nicer...
517 432
518-include config.mak.autogen
519-include config.mak
520
521ifdef NO_LIBELF
522 NO_DWARF := 1
523 NO_DEMANGLE := 1
524 NO_LIBUNWIND := 1
525else
526FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
527ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
528 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
529 ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
530 LIBC_SUPPORT := 1
531 endif
532 ifeq ($(BIONIC),1)
533 LIBC_SUPPORT := 1
534 endif
535 ifeq ($(LIBC_SUPPORT),1)
536 msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
537
538 NO_LIBELF := 1
539 NO_DWARF := 1
540 NO_DEMANGLE := 1
541 else
542 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
543 endif
544else
545 # for linking with debug library, run like:
546 # make DEBUG=1 LIBDW_DIR=/opt/libdw/
547 ifdef LIBDW_DIR
548 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
549 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
550 endif
551
552 FLAGS_DWARF=$(ALL_CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
553 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
554 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
555 NO_DWARF := 1
556 endif # Dwarf support
557endif # SOURCE_LIBELF
558endif # NO_LIBELF
559
560ifndef NO_LIBUNWIND
561# for linking with debug library, run like:
562# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
563ifdef LIBUNWIND_DIR
564 LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
565 LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
566endif
567
568FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
569ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
570 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
571 NO_LIBUNWIND := 1
572endif # Libunwind support
573endif # NO_LIBUNWIND
574
575-include arch/$(ARCH)/Makefile 433-include arch/$(ARCH)/Makefile
576 434
577ifneq ($(OUTPUT),) 435ifneq ($(OUTPUT),)
578 BASIC_CFLAGS += -I$(OUTPUT) 436 CFLAGS += -I$(OUTPUT)
579endif 437endif
580 438
581ifdef NO_LIBELF 439ifdef NO_LIBELF
@@ -593,282 +451,74 @@ BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
593LIB_OBJS += $(OUTPUT)util/symbol-minimal.o 451LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
594 452
595else # NO_LIBELF 453else # NO_LIBELF
596BASIC_CFLAGS += -DLIBELF_SUPPORT
597
598FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
599ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
600 BASIC_CFLAGS += -DLIBELF_MMAP
601endif
602
603ifndef NO_DWARF 454ifndef NO_DWARF
604ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) 455 LIB_OBJS += $(OUTPUT)util/probe-finder.o
605 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); 456 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
606else
607 BASIC_CFLAGS := -DDWARF_SUPPORT $(LIBDW_CFLAGS) $(BASIC_CFLAGS)
608 BASIC_LDFLAGS := $(LIBDW_LDFLAGS) $(BASIC_LDFLAGS)
609 EXTLIBS += -lelf -ldw
610 LIB_OBJS += $(OUTPUT)util/probe-finder.o
611 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
612endif # PERF_HAVE_DWARF_REGS
613endif # NO_DWARF 457endif # NO_DWARF
614endif # NO_LIBELF 458endif # NO_LIBELF
615 459
616ifndef NO_LIBUNWIND 460ifndef NO_LIBUNWIND
617 BASIC_CFLAGS += -DLIBUNWIND_SUPPORT 461 LIB_OBJS += $(OUTPUT)util/unwind.o
618 EXTLIBS += $(LIBUNWIND_LIBS)
619 BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS)
620 BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS)
621 LIB_OBJS += $(OUTPUT)util/unwind.o
622endif 462endif
623 463
624ifndef NO_LIBAUDIT 464ifndef NO_LIBAUDIT
625 FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit 465 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
626 ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
627 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
628 else
629 BASIC_CFLAGS += -DLIBAUDIT_SUPPORT
630 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
631 EXTLIBS += -laudit
632 endif
633endif 466endif
634 467
635ifndef NO_NEWT 468ifndef NO_SLANG
636 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt 469 LIB_OBJS += $(OUTPUT)ui/browser.o
637 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT),libnewt),y) 470 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
638 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); 471 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
639 else 472 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
640 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 473 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
641 BASIC_CFLAGS += -I/usr/include/slang 474 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
642 BASIC_CFLAGS += -DNEWT_SUPPORT 475 LIB_OBJS += $(OUTPUT)ui/tui/util.o
643 EXTLIBS += -lnewt -lslang 476 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
644 LIB_OBJS += $(OUTPUT)ui/browser.o 477 LIB_OBJS += $(OUTPUT)ui/tui/progress.o
645 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o 478 LIB_H += ui/browser.h
646 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o 479 LIB_H += ui/browsers/map.h
647 LIB_OBJS += $(OUTPUT)ui/browsers/map.o 480 LIB_H += ui/keysyms.h
648 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o 481 LIB_H += ui/libslang.h
649 LIB_OBJS += $(OUTPUT)ui/util.o
650 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
651 LIB_OBJS += $(OUTPUT)ui/tui/util.o
652 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
653 LIB_OBJS += $(OUTPUT)ui/tui/progress.o
654 LIB_H += ui/browser.h
655 LIB_H += ui/browsers/map.h
656 LIB_H += ui/keysyms.h
657 LIB_H += ui/libslang.h
658 LIB_H += ui/progress.h
659 LIB_H += ui/util.h
660 LIB_H += ui/ui.h
661 endif
662endif 482endif
663 483
664ifndef NO_GTK2 484ifndef NO_GTK2
665 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 485 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
666 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y) 486 LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
667 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); 487 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
668 else 488 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
669 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y) 489 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
670 BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR 490 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
671 endif 491 LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
672 BASIC_CFLAGS += -DGTK2_SUPPORT
673 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
674 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
675 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
676 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
677 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
678 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
679 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
680 # Make sure that it'd be included only once.
681 ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),)
682 LIB_OBJS += $(OUTPUT)ui/util.o
683 endif
684 endif
685endif
686
687ifdef NO_LIBPERL
688 BASIC_CFLAGS += -DNO_LIBPERL
689else
690 PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
691 PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
692 PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
693 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
694 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
695
696 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
697 BASIC_CFLAGS += -DNO_LIBPERL
698 else
699 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
700 EXTLIBS += $(PERL_EMBED_LIBADD)
701 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
702 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
703 endif
704endif 492endif
705 493
706disable-python = $(eval $(disable-python_code)) 494ifndef NO_LIBPERL
707define disable-python_code 495 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
708 BASIC_CFLAGS += -DNO_LIBPYTHON 496 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
709 $(if $(1),$(warning No $(1) was found))
710 $(warning Python support won't be built)
711endef
712
713override PYTHON := \
714 $(call get-executable-or-default,PYTHON,python)
715
716ifndef PYTHON
717 $(call disable-python,python interpreter)
718 python-clean :=
719else
720
721 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
722
723 # python extension build directories
724 PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
725 PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
726 PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
727 export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
728
729 python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
730
731 ifdef NO_LIBPYTHON
732 $(call disable-python)
733 else
734
735 override PYTHON_CONFIG := \
736 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
737
738 ifndef PYTHON_CONFIG
739 $(call disable-python,python-config tool)
740 else
741
742 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
743
744 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
745 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
746 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
747 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
748 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
749
750 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
751 $(call disable-python,Python.h (for Python 2.x))
752 else
753
754 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
755 $(warning Python 3 is not yet supported; please set)
756 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
757 $(warning If you also have Python 2 installed, then)
758 $(warning try something like:)
759 $(warning $(and ,))
760 $(warning $(and ,) make PYTHON=python2)
761 $(warning $(and ,))
762 $(warning Otherwise, disable Python support entirely:)
763 $(warning $(and ,))
764 $(warning $(and ,) make NO_LIBPYTHON=1)
765 $(warning $(and ,))
766 $(error $(and ,))
767 else
768 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
769 EXTLIBS += $(PYTHON_EMBED_LIBADD)
770 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
771 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
772 LANG_BINDINGS += $(OUTPUT)python/perf.so
773 endif
774
775 endif
776 endif
777 endif
778endif 497endif
779 498
780ifdef NO_DEMANGLE 499ifndef NO_LIBPYTHON
781 BASIC_CFLAGS += -DNO_DEMANGLE 500 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
782else 501 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
783 ifdef HAVE_CPLUS_DEMANGLE
784 EXTLIBS += -liberty
785 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
786 else
787 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
788 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
789 ifeq ($(has_bfd),y)
790 EXTLIBS += -lbfd
791 else
792 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
793 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
794 ifeq ($(has_bfd_iberty),y)
795 EXTLIBS += -lbfd -liberty
796 else
797 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
798 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
799 ifeq ($(has_bfd_iberty_z),y)
800 EXTLIBS += -lbfd -liberty -lz
801 else
802 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
803 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
804 ifeq ($(has_cplus_demangle),y)
805 EXTLIBS += -liberty
806 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
807 else
808 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
809 BASIC_CFLAGS += -DNO_DEMANGLE
810 endif
811 endif
812 endif
813 endif
814 endif
815endif 502endif
816 503
817ifeq ($(NO_PERF_REGS),0) 504ifeq ($(NO_PERF_REGS),0)
818 ifeq ($(ARCH),x86) 505 ifeq ($(ARCH),x86)
819 LIB_H += arch/x86/include/perf_regs.h 506 LIB_H += arch/x86/include/perf_regs.h
820 endif 507 endif
821 BASIC_CFLAGS += -DHAVE_PERF_REGS
822endif
823
824ifndef NO_STRLCPY
825 ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
826 BASIC_CFLAGS += -DHAVE_STRLCPY
827 endif
828endif
829
830ifndef NO_ON_EXIT
831 ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
832 BASIC_CFLAGS += -DHAVE_ON_EXIT
833 endif
834endif 508endif
835 509
836ifndef NO_BACKTRACE 510ifndef NO_LIBNUMA
837 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y) 511 BUILTIN_OBJS += $(OUTPUT)bench/numa.o
838 BASIC_CFLAGS += -DBACKTRACE_SUPPORT
839 endif
840endif 512endif
841 513
842ifdef ASCIIDOC8 514ifdef ASCIIDOC8
843 export ASCIIDOC8 515 export ASCIIDOC8
844endif 516endif
845 517
846# Shell quote (do not use $(call) to accommodate ancient setups);
847
848ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
849
850DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
851bindir_SQ = $(subst ','\'',$(bindir))
852bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
853mandir_SQ = $(subst ','\'',$(mandir))
854infodir_SQ = $(subst ','\'',$(infodir))
855perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
856template_dir_SQ = $(subst ','\'',$(template_dir))
857htmldir_SQ = $(subst ','\'',$(htmldir))
858prefix_SQ = $(subst ','\'',$(prefix))
859sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
860
861SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
862
863LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group 518LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
864 519
865ALL_CFLAGS += $(BASIC_CFLAGS)
866ALL_CFLAGS += $(ARCH_CFLAGS)
867ALL_LDFLAGS += $(BASIC_LDFLAGS)
868
869export INSTALL SHELL_PATH 520export INSTALL SHELL_PATH
870 521
871
872### Build rules 522### Build rules
873 523
874SHELL = $(SHELL_PATH) 524SHELL = $(SHELL_PATH)
@@ -884,22 +534,22 @@ strip: $(PROGRAMS) $(OUTPUT)perf
884 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf 534 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
885 535
886$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 536$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
887 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 537 $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
888 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 538 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
889 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 539 $(CFLAGS) -c $(filter %.c,$^) -o $@
890 540
891$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) 541$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
892 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ 542 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
893 $(BUILTIN_OBJS) $(LIBS) -o $@ 543 $(BUILTIN_OBJS) $(LIBS) -o $@
894 544
895$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 545$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
896 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 546 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
897 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 547 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
898 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 548 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
899 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 549 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
900 550
901$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 551$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
902 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 552 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
903 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 553 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
904 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 554 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
905 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 555 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
@@ -924,71 +574,77 @@ $(OUTPUT)perf.o perf.spec \
924# over the general rule for .o 574# over the general rule for .o
925 575
926$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS 576$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
927 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -w $< 577 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
928 578
929$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS 579$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
930 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $< 580 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
931 581
932$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 582$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
933 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 583 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
934$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS 584$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
935 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $< 585 $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
936$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS 586$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
937 $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $< 587 $(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
938$(OUTPUT)%.o: %.S 588$(OUTPUT)%.o: %.S
939 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 589 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
940$(OUTPUT)%.s: %.S 590$(OUTPUT)%.s: %.S
941 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $< 591 $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
942 592
943$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS 593$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
944 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 594 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
945 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ 595 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
946 '-DPREFIX="$(prefix_SQ)"' \ 596 '-DPREFIX="$(prefix_SQ)"' \
947 $< 597 $<
948 598
949$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS 599$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
950 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 600 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
951 '-DBINDIR="$(bindir_SQ)"' \ 601 '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
602 $<
603
604$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
605 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
606 -DPYTHONPATH='"$(OUTPUT)python"' \
607 -DPYTHON='"$(PYTHON_WORD)"' \
952 $< 608 $<
953 609
954$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 610$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
955 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 611 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
956 612
957$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS 613$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
958 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 614 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
959 615
960$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 616$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
961 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 617 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
962 618
963$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 619$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
964 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 620 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
965 621
966$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS 622$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
967 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 623 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
968 624
969$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS 625$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
970 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 626 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
971 627
972$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 628$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
973 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 629 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
974 630
975$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS 631$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
976 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $< 632 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
977 633
978$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS 634$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
979 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 635 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
980 636
981$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 637$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
982 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 638 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
983 639
984$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS 640$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
985 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 641 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
986 642
987$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS 643$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
988 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 644 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
989 645
990$(OUTPUT)perf-%: %.o $(PERFLIBS) 646$(OUTPUT)perf-%: %.o $(PERFLIBS)
991 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 647 $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
992 648
993$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 649$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
994$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 650$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
@@ -1011,6 +667,18 @@ $(LIBTRACEEVENT):
1011$(LIBTRACEEVENT)-clean: 667$(LIBTRACEEVENT)-clean:
1012 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean 668 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
1013 669
670# if subdir is set, we've been called from above so target has been built
671# already
672$(LIBLK):
673ifeq ($(subdir),)
674 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
675endif
676
677$(LIBLK)-clean:
678ifeq ($(subdir),)
679 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
680endif
681
1014help: 682help:
1015 @echo 'Perf make targets:' 683 @echo 'Perf make targets:'
1016 @echo ' doc - make *all* documentation (see below)' 684 @echo ' doc - make *all* documentation (see below)'
@@ -1063,7 +731,7 @@ cscope:
1063 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b 731 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
1064 732
1065### Detect prefix changes 733### Detect prefix changes
1066TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ 734TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
1067 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) 735 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
1068 736
1069$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS 737$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
@@ -1084,7 +752,7 @@ check: $(OUTPUT)common-cmds.h
1084 then \ 752 then \
1085 for i in *.c */*.c; \ 753 for i in *.c */*.c; \
1086 do \ 754 do \
1087 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ 755 sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
1088 done; \ 756 done; \
1089 else \ 757 else \
1090 exit 1; \ 758 exit 1; \
@@ -1092,14 +760,7 @@ check: $(OUTPUT)common-cmds.h
1092 760
1093### Installation rules 761### Installation rules
1094 762
1095ifneq ($(filter /%,$(firstword $(perfexecdir))),) 763install-bin: all
1096perfexec_instdir = $(perfexecdir)
1097else
1098perfexec_instdir = $(prefix)/$(perfexecdir)
1099endif
1100perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1101
1102install: all try-install-man
1103 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 764 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1104 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' 765 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1105 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 766 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
@@ -1120,6 +781,8 @@ install: all try-install-man
1120 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' 781 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1121 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' 782 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1122 783
784install: install-bin try-install-man
785
1123install-python_ext: 786install-python_ext:
1124 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' 787 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
1125 788
@@ -1129,7 +792,7 @@ $(INSTALL_DOC_TARGETS):
1129 792
1130### Cleaning rules 793### Cleaning rules
1131 794
1132clean: $(LIBTRACEEVENT)-clean 795clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean
1133 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) 796 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
1134 $(RM) $(ALL_PROGRAMS) perf 797 $(RM) $(ALL_PROGRAMS) perf
1135 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 798 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
@@ -1139,6 +802,6 @@ clean: $(LIBTRACEEVENT)-clean
1139 $(RM) $(OUTPUT)util/*-flex* 802 $(RM) $(OUTPUT)util/*-flex*
1140 $(python-clean) 803 $(python-clean)
1141 804
1142.PHONY: all install clean strip $(LIBTRACEEVENT) 805.PHONY: all install clean strip $(LIBTRACEEVENT) $(LIBLK)
1143.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 806.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
1144.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 807.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
index e8d5c551c69c..33ec5b339da8 100644
--- a/tools/perf/arch/arm/util/dwarf-regs.c
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -8,10 +8,7 @@
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11#include <stdlib.h> 11#include <stddef.h>
12#ifndef __UCLIBC__
13#include <libio.h>
14#endif
15#include <dwarf-regs.h> 12#include <dwarf-regs.h>
16 13
17struct pt_regs_dwarfnum { 14struct pt_regs_dwarfnum {
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
index 3e975cb6232e..aacef07ebf31 100644
--- a/tools/perf/arch/common.c
+++ b/tools/perf/arch/common.c
@@ -155,6 +155,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
155 if (lookup_path(buf)) 155 if (lookup_path(buf))
156 goto out; 156 goto out;
157 free(buf); 157 free(buf);
158 buf = NULL;
158 } 159 }
159 160
160 if (!strcmp(arch, "arm")) 161 if (!strcmp(arch, "arm"))
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c
index 7cdd61d0e27c..733151cdf46e 100644
--- a/tools/perf/arch/powerpc/util/dwarf-regs.c
+++ b/tools/perf/arch/powerpc/util/dwarf-regs.c
@@ -9,10 +9,7 @@
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 */ 10 */
11 11
12#include <stdlib.h> 12#include <stddef.h>
13#ifndef __UCLIBC__
14#include <libio.h>
15#endif
16#include <dwarf-regs.h> 13#include <dwarf-regs.h>
17 14
18 15
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c
index e19653e025fa..0469df02ee62 100644
--- a/tools/perf/arch/s390/util/dwarf-regs.c
+++ b/tools/perf/arch/s390/util/dwarf-regs.c
@@ -6,7 +6,7 @@
6 * 6 *
7 */ 7 */
8 8
9#include <libio.h> 9#include <stddef.h>
10#include <dwarf-regs.h> 10#include <dwarf-regs.h>
11 11
12#define NUM_GPRS 16 12#define NUM_GPRS 16
diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c
index a11edb007a6c..0d0897f57a10 100644
--- a/tools/perf/arch/sh/util/dwarf-regs.c
+++ b/tools/perf/arch/sh/util/dwarf-regs.c
@@ -19,7 +19,7 @@
19 * 19 *
20 */ 20 */
21 21
22#include <libio.h> 22#include <stddef.h>
23#include <dwarf-regs.h> 23#include <dwarf-regs.h>
24 24
25/* 25/*
diff --git a/tools/perf/arch/sparc/util/dwarf-regs.c b/tools/perf/arch/sparc/util/dwarf-regs.c
index 0ab88483720c..92eda412fed3 100644
--- a/tools/perf/arch/sparc/util/dwarf-regs.c
+++ b/tools/perf/arch/sparc/util/dwarf-regs.c
@@ -9,7 +9,7 @@
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 */ 10 */
11 11
12#include <libio.h> 12#include <stddef.h>
13#include <dwarf-regs.h> 13#include <dwarf-regs.h>
14 14
15#define SPARC_MAX_REGS 96 15#define SPARC_MAX_REGS 96
diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c
index a794d3081928..be22dd463232 100644
--- a/tools/perf/arch/x86/util/dwarf-regs.c
+++ b/tools/perf/arch/x86/util/dwarf-regs.c
@@ -20,7 +20,7 @@
20 * 20 *
21 */ 21 */
22 22
23#include <libio.h> 23#include <stddef.h>
24#include <dwarf-regs.h> 24#include <dwarf-regs.h>
25 25
26/* 26/*
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index 8f89998eeaf4..0fdc85269c4d 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -1,6 +1,31 @@
1#ifndef BENCH_H 1#ifndef BENCH_H
2#define BENCH_H 2#define BENCH_H
3 3
4/*
5 * The madvise transparent hugepage constants were added in glibc
6 * 2.13. For compatibility with older versions of glibc, define these
7 * tokens if they are not already defined.
8 *
9 * PA-RISC uses different madvise values from other architectures and
10 * needs to be special-cased.
11 */
12#ifdef __hppa__
13# ifndef MADV_HUGEPAGE
14# define MADV_HUGEPAGE 67
15# endif
16# ifndef MADV_NOHUGEPAGE
17# define MADV_NOHUGEPAGE 68
18# endif
19#else
20# ifndef MADV_HUGEPAGE
21# define MADV_HUGEPAGE 14
22# endif
23# ifndef MADV_NOHUGEPAGE
24# define MADV_NOHUGEPAGE 15
25# endif
26#endif
27
28extern int bench_numa(int argc, const char **argv, const char *prefix);
4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); 29extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); 30extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
6extern int bench_mem_memcpy(int argc, const char **argv, 31extern int bench_mem_memcpy(int argc, const char **argv,
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
new file mode 100644
index 000000000000..30d1c3225b46
--- /dev/null
+++ b/tools/perf/bench/numa.c
@@ -0,0 +1,1731 @@
1/*
2 * numa.c
3 *
4 * numa: Simulate NUMA-sensitive workload and measure their NUMA performance
5 */
6
7#include "../perf.h"
8#include "../builtin.h"
9#include "../util/util.h"
10#include "../util/parse-options.h"
11
12#include "bench.h"
13
14#include <errno.h>
15#include <sched.h>
16#include <stdio.h>
17#include <assert.h>
18#include <malloc.h>
19#include <signal.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23#include <pthread.h>
24#include <sys/mman.h>
25#include <sys/time.h>
26#include <sys/wait.h>
27#include <sys/prctl.h>
28#include <sys/types.h>
29
30#include <numa.h>
31#include <numaif.h>
32
33/*
34 * Regular printout to the terminal, supressed if -q is specified:
35 */
36#define tprintf(x...) do { if (g && g->p.show_details >= 0) printf(x); } while (0)
37
38/*
39 * Debug printf:
40 */
41#define dprintf(x...) do { if (g && g->p.show_details >= 1) printf(x); } while (0)
42
43struct thread_data {
44 int curr_cpu;
45 cpu_set_t bind_cpumask;
46 int bind_node;
47 u8 *process_data;
48 int process_nr;
49 int thread_nr;
50 int task_nr;
51 unsigned int loops_done;
52 u64 val;
53 u64 runtime_ns;
54 pthread_mutex_t *process_lock;
55};
56
57/* Parameters set by options: */
58
59struct params {
60 /* Startup synchronization: */
61 bool serialize_startup;
62
63 /* Task hierarchy: */
64 int nr_proc;
65 int nr_threads;
66
67 /* Working set sizes: */
68 const char *mb_global_str;
69 const char *mb_proc_str;
70 const char *mb_proc_locked_str;
71 const char *mb_thread_str;
72
73 double mb_global;
74 double mb_proc;
75 double mb_proc_locked;
76 double mb_thread;
77
78 /* Access patterns to the working set: */
79 bool data_reads;
80 bool data_writes;
81 bool data_backwards;
82 bool data_zero_memset;
83 bool data_rand_walk;
84 u32 nr_loops;
85 u32 nr_secs;
86 u32 sleep_usecs;
87
88 /* Working set initialization: */
89 bool init_zero;
90 bool init_random;
91 bool init_cpu0;
92
93 /* Misc options: */
94 int show_details;
95 int run_all;
96 int thp;
97
98 long bytes_global;
99 long bytes_process;
100 long bytes_process_locked;
101 long bytes_thread;
102
103 int nr_tasks;
104 bool show_quiet;
105
106 bool show_convergence;
107 bool measure_convergence;
108
109 int perturb_secs;
110 int nr_cpus;
111 int nr_nodes;
112
113 /* Affinity options -C and -N: */
114 char *cpu_list_str;
115 char *node_list_str;
116};
117
118
119/* Global, read-writable area, accessible to all processes and threads: */
120
121struct global_info {
122 u8 *data;
123
124 pthread_mutex_t startup_mutex;
125 int nr_tasks_started;
126
127 pthread_mutex_t startup_done_mutex;
128
129 pthread_mutex_t start_work_mutex;
130 int nr_tasks_working;
131
132 pthread_mutex_t stop_work_mutex;
133 u64 bytes_done;
134
135 struct thread_data *threads;
136
137 /* Convergence latency measurement: */
138 bool all_converged;
139 bool stop_work;
140
141 int print_once;
142
143 struct params p;
144};
145
146static struct global_info *g = NULL;
147
148static int parse_cpus_opt(const struct option *opt, const char *arg, int unset);
149static int parse_nodes_opt(const struct option *opt, const char *arg, int unset);
150
151struct params p0;
152
153static const struct option options[] = {
154 OPT_INTEGER('p', "nr_proc" , &p0.nr_proc, "number of processes"),
155 OPT_INTEGER('t', "nr_threads" , &p0.nr_threads, "number of threads per process"),
156
157 OPT_STRING('G', "mb_global" , &p0.mb_global_str, "MB", "global memory (MBs)"),
158 OPT_STRING('P', "mb_proc" , &p0.mb_proc_str, "MB", "process memory (MBs)"),
159 OPT_STRING('L', "mb_proc_locked", &p0.mb_proc_locked_str,"MB", "process serialized/locked memory access (MBs), <= process_memory"),
160 OPT_STRING('T', "mb_thread" , &p0.mb_thread_str, "MB", "thread memory (MBs)"),
161
162 OPT_UINTEGER('l', "nr_loops" , &p0.nr_loops, "max number of loops to run"),
163 OPT_UINTEGER('s', "nr_secs" , &p0.nr_secs, "max number of seconds to run"),
164 OPT_UINTEGER('u', "usleep" , &p0.sleep_usecs, "usecs to sleep per loop iteration"),
165
166 OPT_BOOLEAN('R', "data_reads" , &p0.data_reads, "access the data via writes (can be mixed with -W)"),
167 OPT_BOOLEAN('W', "data_writes" , &p0.data_writes, "access the data via writes (can be mixed with -R)"),
168 OPT_BOOLEAN('B', "data_backwards", &p0.data_backwards, "access the data backwards as well"),
169 OPT_BOOLEAN('Z', "data_zero_memset", &p0.data_zero_memset,"access the data via glibc bzero only"),
170 OPT_BOOLEAN('r', "data_rand_walk", &p0.data_rand_walk, "access the data with random (32bit LFSR) walk"),
171
172
173 OPT_BOOLEAN('z', "init_zero" , &p0.init_zero, "bzero the initial allocations"),
174 OPT_BOOLEAN('I', "init_random" , &p0.init_random, "randomize the contents of the initial allocations"),
175 OPT_BOOLEAN('0', "init_cpu0" , &p0.init_cpu0, "do the initial allocations on CPU#0"),
176 OPT_INTEGER('x', "perturb_secs", &p0.perturb_secs, "perturb thread 0/0 every X secs, to test convergence stability"),
177
178 OPT_INCR ('d', "show_details" , &p0.show_details, "Show details"),
179 OPT_INCR ('a', "all" , &p0.run_all, "Run all tests in the suite"),
180 OPT_INTEGER('H', "thp" , &p0.thp, "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"),
181 OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"),
182 OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"),
183 OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "bzero the initial allocations"),
184 OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"),
185
186 /* Special option string parsing callbacks: */
187 OPT_CALLBACK('C', "cpus", NULL, "cpu[,cpu2,...cpuN]",
188 "bind the first N tasks to these specific cpus (the rest is unbound)",
189 parse_cpus_opt),
190 OPT_CALLBACK('M', "memnodes", NULL, "node[,node2,...nodeN]",
191 "bind the first N tasks to these specific memory nodes (the rest is unbound)",
192 parse_nodes_opt),
193 OPT_END()
194};
195
196static const char * const bench_numa_usage[] = {
197 "perf bench numa <options>",
198 NULL
199};
200
201static const char * const numa_usage[] = {
202 "perf bench numa mem [<options>]",
203 NULL
204};
205
206static cpu_set_t bind_to_cpu(int target_cpu)
207{
208 cpu_set_t orig_mask, mask;
209 int ret;
210
211 ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
212 BUG_ON(ret);
213
214 CPU_ZERO(&mask);
215
216 if (target_cpu == -1) {
217 int cpu;
218
219 for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
220 CPU_SET(cpu, &mask);
221 } else {
222 BUG_ON(target_cpu < 0 || target_cpu >= g->p.nr_cpus);
223 CPU_SET(target_cpu, &mask);
224 }
225
226 ret = sched_setaffinity(0, sizeof(mask), &mask);
227 BUG_ON(ret);
228
229 return orig_mask;
230}
231
232static cpu_set_t bind_to_node(int target_node)
233{
234 int cpus_per_node = g->p.nr_cpus/g->p.nr_nodes;
235 cpu_set_t orig_mask, mask;
236 int cpu;
237 int ret;
238
239 BUG_ON(cpus_per_node*g->p.nr_nodes != g->p.nr_cpus);
240 BUG_ON(!cpus_per_node);
241
242 ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
243 BUG_ON(ret);
244
245 CPU_ZERO(&mask);
246
247 if (target_node == -1) {
248 for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
249 CPU_SET(cpu, &mask);
250 } else {
251 int cpu_start = (target_node + 0) * cpus_per_node;
252 int cpu_stop = (target_node + 1) * cpus_per_node;
253
254 BUG_ON(cpu_stop > g->p.nr_cpus);
255
256 for (cpu = cpu_start; cpu < cpu_stop; cpu++)
257 CPU_SET(cpu, &mask);
258 }
259
260 ret = sched_setaffinity(0, sizeof(mask), &mask);
261 BUG_ON(ret);
262
263 return orig_mask;
264}
265
266static void bind_to_cpumask(cpu_set_t mask)
267{
268 int ret;
269
270 ret = sched_setaffinity(0, sizeof(mask), &mask);
271 BUG_ON(ret);
272}
273
274static void mempol_restore(void)
275{
276 int ret;
277
278 ret = set_mempolicy(MPOL_DEFAULT, NULL, g->p.nr_nodes-1);
279
280 BUG_ON(ret);
281}
282
283static void bind_to_memnode(int node)
284{
285 unsigned long nodemask;
286 int ret;
287
288 if (node == -1)
289 return;
290
291 BUG_ON(g->p.nr_nodes > (int)sizeof(nodemask));
292 nodemask = 1L << node;
293
294 ret = set_mempolicy(MPOL_BIND, &nodemask, sizeof(nodemask)*8);
295 dprintf("binding to node %d, mask: %016lx => %d\n", node, nodemask, ret);
296
297 BUG_ON(ret);
298}
299
300#define HPSIZE (2*1024*1024)
301
302#define set_taskname(fmt...) \
303do { \
304 char name[20]; \
305 \
306 snprintf(name, 20, fmt); \
307 prctl(PR_SET_NAME, name); \
308} while (0)
309
310static u8 *alloc_data(ssize_t bytes0, int map_flags,
311 int init_zero, int init_cpu0, int thp, int init_random)
312{
313 cpu_set_t orig_mask;
314 ssize_t bytes;
315 u8 *buf;
316 int ret;
317
318 if (!bytes0)
319 return NULL;
320
321 /* Allocate and initialize all memory on CPU#0: */
322 if (init_cpu0) {
323 orig_mask = bind_to_node(0);
324 bind_to_memnode(0);
325 }
326
327 bytes = bytes0 + HPSIZE;
328
329 buf = (void *)mmap(0, bytes, PROT_READ|PROT_WRITE, MAP_ANON|map_flags, -1, 0);
330 BUG_ON(buf == (void *)-1);
331
332 if (map_flags == MAP_PRIVATE) {
333 if (thp > 0) {
334 ret = madvise(buf, bytes, MADV_HUGEPAGE);
335 if (ret && !g->print_once) {
336 g->print_once = 1;
337 printf("WARNING: Could not enable THP - do: 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled'\n");
338 }
339 }
340 if (thp < 0) {
341 ret = madvise(buf, bytes, MADV_NOHUGEPAGE);
342 if (ret && !g->print_once) {
343 g->print_once = 1;
344 printf("WARNING: Could not disable THP: run a CONFIG_TRANSPARENT_HUGEPAGE kernel?\n");
345 }
346 }
347 }
348
349 if (init_zero) {
350 bzero(buf, bytes);
351 } else {
352 /* Initialize random contents, different in each word: */
353 if (init_random) {
354 u64 *wbuf = (void *)buf;
355 long off = rand();
356 long i;
357
358 for (i = 0; i < bytes/8; i++)
359 wbuf[i] = i + off;
360 }
361 }
362
363 /* Align to 2MB boundary: */
364 buf = (void *)(((unsigned long)buf + HPSIZE-1) & ~(HPSIZE-1));
365
366 /* Restore affinity: */
367 if (init_cpu0) {
368 bind_to_cpumask(orig_mask);
369 mempol_restore();
370 }
371
372 return buf;
373}
374
375static void free_data(void *data, ssize_t bytes)
376{
377 int ret;
378
379 if (!data)
380 return;
381
382 ret = munmap(data, bytes);
383 BUG_ON(ret);
384}
385
386/*
387 * Create a shared memory buffer that can be shared between processes, zeroed:
388 */
389static void * zalloc_shared_data(ssize_t bytes)
390{
391 return alloc_data(bytes, MAP_SHARED, 1, g->p.init_cpu0, g->p.thp, g->p.init_random);
392}
393
394/*
395 * Create a shared memory buffer that can be shared between processes:
396 */
397static void * setup_shared_data(ssize_t bytes)
398{
399 return alloc_data(bytes, MAP_SHARED, 0, g->p.init_cpu0, g->p.thp, g->p.init_random);
400}
401
402/*
403 * Allocate process-local memory - this will either be shared between
404 * threads of this process, or only be accessed by this thread:
405 */
406static void * setup_private_data(ssize_t bytes)
407{
408 return alloc_data(bytes, MAP_PRIVATE, 0, g->p.init_cpu0, g->p.thp, g->p.init_random);
409}
410
411/*
412 * Return a process-shared (global) mutex:
413 */
414static void init_global_mutex(pthread_mutex_t *mutex)
415{
416 pthread_mutexattr_t attr;
417
418 pthread_mutexattr_init(&attr);
419 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
420 pthread_mutex_init(mutex, &attr);
421}
422
423static int parse_cpu_list(const char *arg)
424{
425 p0.cpu_list_str = strdup(arg);
426
427 dprintf("got CPU list: {%s}\n", p0.cpu_list_str);
428
429 return 0;
430}
431
432static void parse_setup_cpu_list(void)
433{
434 struct thread_data *td;
435 char *str0, *str;
436 int t;
437
438 if (!g->p.cpu_list_str)
439 return;
440
441 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
442
443 str0 = str = strdup(g->p.cpu_list_str);
444 t = 0;
445
446 BUG_ON(!str);
447
448 tprintf("# binding tasks to CPUs:\n");
449 tprintf("# ");
450
451 while (true) {
452 int bind_cpu, bind_cpu_0, bind_cpu_1;
453 char *tok, *tok_end, *tok_step, *tok_len, *tok_mul;
454 int bind_len;
455 int step;
456 int mul;
457
458 tok = strsep(&str, ",");
459 if (!tok)
460 break;
461
462 tok_end = strstr(tok, "-");
463
464 dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end);
465 if (!tok_end) {
466 /* Single CPU specified: */
467 bind_cpu_0 = bind_cpu_1 = atol(tok);
468 } else {
469 /* CPU range specified (for example: "5-11"): */
470 bind_cpu_0 = atol(tok);
471 bind_cpu_1 = atol(tok_end + 1);
472 }
473
474 step = 1;
475 tok_step = strstr(tok, "#");
476 if (tok_step) {
477 step = atol(tok_step + 1);
478 BUG_ON(step <= 0 || step >= g->p.nr_cpus);
479 }
480
481 /*
482 * Mask length.
483 * Eg: "--cpus 8_4-16#4" means: '--cpus 8_4,12_4,16_4',
484 * where the _4 means the next 4 CPUs are allowed.
485 */
486 bind_len = 1;
487 tok_len = strstr(tok, "_");
488 if (tok_len) {
489 bind_len = atol(tok_len + 1);
490 BUG_ON(bind_len <= 0 || bind_len > g->p.nr_cpus);
491 }
492
493 /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */
494 mul = 1;
495 tok_mul = strstr(tok, "x");
496 if (tok_mul) {
497 mul = atol(tok_mul + 1);
498 BUG_ON(mul <= 0);
499 }
500
501 dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul);
502
503 BUG_ON(bind_cpu_0 < 0 || bind_cpu_0 >= g->p.nr_cpus);
504 BUG_ON(bind_cpu_1 < 0 || bind_cpu_1 >= g->p.nr_cpus);
505 BUG_ON(bind_cpu_0 > bind_cpu_1);
506
507 for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) {
508 int i;
509
510 for (i = 0; i < mul; i++) {
511 int cpu;
512
513 if (t >= g->p.nr_tasks) {
514 printf("\n# NOTE: ignoring bind CPUs starting at CPU#%d\n #", bind_cpu);
515 goto out;
516 }
517 td = g->threads + t;
518
519 if (t)
520 tprintf(",");
521 if (bind_len > 1) {
522 tprintf("%2d/%d", bind_cpu, bind_len);
523 } else {
524 tprintf("%2d", bind_cpu);
525 }
526
527 CPU_ZERO(&td->bind_cpumask);
528 for (cpu = bind_cpu; cpu < bind_cpu+bind_len; cpu++) {
529 BUG_ON(cpu < 0 || cpu >= g->p.nr_cpus);
530 CPU_SET(cpu, &td->bind_cpumask);
531 }
532 t++;
533 }
534 }
535 }
536out:
537
538 tprintf("\n");
539
540 if (t < g->p.nr_tasks)
541 printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
542
543 free(str0);
544}
545
546static int parse_cpus_opt(const struct option *opt __maybe_unused,
547 const char *arg, int unset __maybe_unused)
548{
549 if (!arg)
550 return -1;
551
552 return parse_cpu_list(arg);
553}
554
555static int parse_node_list(const char *arg)
556{
557 p0.node_list_str = strdup(arg);
558
559 dprintf("got NODE list: {%s}\n", p0.node_list_str);
560
561 return 0;
562}
563
564static void parse_setup_node_list(void)
565{
566 struct thread_data *td;
567 char *str0, *str;
568 int t;
569
570 if (!g->p.node_list_str)
571 return;
572
573 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
574
575 str0 = str = strdup(g->p.node_list_str);
576 t = 0;
577
578 BUG_ON(!str);
579
580 tprintf("# binding tasks to NODEs:\n");
581 tprintf("# ");
582
583 while (true) {
584 int bind_node, bind_node_0, bind_node_1;
585 char *tok, *tok_end, *tok_step, *tok_mul;
586 int step;
587 int mul;
588
589 tok = strsep(&str, ",");
590 if (!tok)
591 break;
592
593 tok_end = strstr(tok, "-");
594
595 dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end);
596 if (!tok_end) {
597 /* Single NODE specified: */
598 bind_node_0 = bind_node_1 = atol(tok);
599 } else {
600 /* NODE range specified (for example: "5-11"): */
601 bind_node_0 = atol(tok);
602 bind_node_1 = atol(tok_end + 1);
603 }
604
605 step = 1;
606 tok_step = strstr(tok, "#");
607 if (tok_step) {
608 step = atol(tok_step + 1);
609 BUG_ON(step <= 0 || step >= g->p.nr_nodes);
610 }
611
612 /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */
613 mul = 1;
614 tok_mul = strstr(tok, "x");
615 if (tok_mul) {
616 mul = atol(tok_mul + 1);
617 BUG_ON(mul <= 0);
618 }
619
620 dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step);
621
622 BUG_ON(bind_node_0 < 0 || bind_node_0 >= g->p.nr_nodes);
623 BUG_ON(bind_node_1 < 0 || bind_node_1 >= g->p.nr_nodes);
624 BUG_ON(bind_node_0 > bind_node_1);
625
626 for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) {
627 int i;
628
629 for (i = 0; i < mul; i++) {
630 if (t >= g->p.nr_tasks) {
631 printf("\n# NOTE: ignoring bind NODEs starting at NODE#%d\n", bind_node);
632 goto out;
633 }
634 td = g->threads + t;
635
636 if (!t)
637 tprintf(" %2d", bind_node);
638 else
639 tprintf(",%2d", bind_node);
640
641 td->bind_node = bind_node;
642 t++;
643 }
644 }
645 }
646out:
647
648 tprintf("\n");
649
650 if (t < g->p.nr_tasks)
651 printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
652
653 free(str0);
654}
655
656static int parse_nodes_opt(const struct option *opt __maybe_unused,
657 const char *arg, int unset __maybe_unused)
658{
659 if (!arg)
660 return -1;
661
662 return parse_node_list(arg);
663
664 return 0;
665}
666
667#define BIT(x) (1ul << x)
668
669static inline uint32_t lfsr_32(uint32_t lfsr)
670{
671 const uint32_t taps = BIT(1) | BIT(5) | BIT(6) | BIT(31);
672 return (lfsr>>1) ^ ((0x0u - (lfsr & 0x1u)) & taps);
673}
674
675/*
676 * Make sure there's real data dependency to RAM (when read
677 * accesses are enabled), so the compiler, the CPU and the
678 * kernel (KSM, zero page, etc.) cannot optimize away RAM
679 * accesses:
680 */
681static inline u64 access_data(u64 *data __attribute__((unused)), u64 val)
682{
683 if (g->p.data_reads)
684 val += *data;
685 if (g->p.data_writes)
686 *data = val + 1;
687 return val;
688}
689
690/*
691 * The worker process does two types of work, a forwards going
692 * loop and a backwards going loop.
693 *
694 * We do this so that on multiprocessor systems we do not create
695 * a 'train' of processing, with highly synchronized processes,
696 * skewing the whole benchmark.
697 */
698static u64 do_work(u8 *__data, long bytes, int nr, int nr_max, int loop, u64 val)
699{
700 long words = bytes/sizeof(u64);
701 u64 *data = (void *)__data;
702 long chunk_0, chunk_1;
703 u64 *d0, *d, *d1;
704 long off;
705 long i;
706
707 BUG_ON(!data && words);
708 BUG_ON(data && !words);
709
710 if (!data)
711 return val;
712
713 /* Very simple memset() work variant: */
714 if (g->p.data_zero_memset && !g->p.data_rand_walk) {
715 bzero(data, bytes);
716 return val;
717 }
718
719 /* Spread out by PID/TID nr and by loop nr: */
720 chunk_0 = words/nr_max;
721 chunk_1 = words/g->p.nr_loops;
722 off = nr*chunk_0 + loop*chunk_1;
723
724 while (off >= words)
725 off -= words;
726
727 if (g->p.data_rand_walk) {
728 u32 lfsr = nr + loop + val;
729 int j;
730
731 for (i = 0; i < words/1024; i++) {
732 long start, end;
733
734 lfsr = lfsr_32(lfsr);
735
736 start = lfsr % words;
737 end = min(start + 1024, words-1);
738
739 if (g->p.data_zero_memset) {
740 bzero(data + start, (end-start) * sizeof(u64));
741 } else {
742 for (j = start; j < end; j++)
743 val = access_data(data + j, val);
744 }
745 }
746 } else if (!g->p.data_backwards || (nr + loop) & 1) {
747
748 d0 = data + off;
749 d = data + off + 1;
750 d1 = data + words;
751
752 /* Process data forwards: */
753 for (;;) {
754 if (unlikely(d >= d1))
755 d = data;
756 if (unlikely(d == d0))
757 break;
758
759 val = access_data(d, val);
760
761 d++;
762 }
763 } else {
764 /* Process data backwards: */
765
766 d0 = data + off;
767 d = data + off - 1;
768 d1 = data + words;
769
770 /* Process data forwards: */
771 for (;;) {
772 if (unlikely(d < data))
773 d = data + words-1;
774 if (unlikely(d == d0))
775 break;
776
777 val = access_data(d, val);
778
779 d--;
780 }
781 }
782
783 return val;
784}
785
786static void update_curr_cpu(int task_nr, unsigned long bytes_worked)
787{
788 unsigned int cpu;
789
790 cpu = sched_getcpu();
791
792 g->threads[task_nr].curr_cpu = cpu;
793 prctl(0, bytes_worked);
794}
795
796#define MAX_NR_NODES 64
797
798/*
799 * Count the number of nodes a process's threads
800 * are spread out on.
801 *
802 * A count of 1 means that the process is compressed
803 * to a single node. A count of g->p.nr_nodes means it's
804 * spread out on the whole system.
805 */
806static int count_process_nodes(int process_nr)
807{
808 char node_present[MAX_NR_NODES] = { 0, };
809 int nodes;
810 int n, t;
811
812 for (t = 0; t < g->p.nr_threads; t++) {
813 struct thread_data *td;
814 int task_nr;
815 int node;
816
817 task_nr = process_nr*g->p.nr_threads + t;
818 td = g->threads + task_nr;
819
820 node = numa_node_of_cpu(td->curr_cpu);
821 node_present[node] = 1;
822 }
823
824 nodes = 0;
825
826 for (n = 0; n < MAX_NR_NODES; n++)
827 nodes += node_present[n];
828
829 return nodes;
830}
831
832/*
833 * Count the number of distinct process-threads a node contains.
834 *
835 * A count of 1 means that the node contains only a single
836 * process. If all nodes on the system contain at most one
837 * process then we are well-converged.
838 */
839static int count_node_processes(int node)
840{
841 int processes = 0;
842 int t, p;
843
844 for (p = 0; p < g->p.nr_proc; p++) {
845 for (t = 0; t < g->p.nr_threads; t++) {
846 struct thread_data *td;
847 int task_nr;
848 int n;
849
850 task_nr = p*g->p.nr_threads + t;
851 td = g->threads + task_nr;
852
853 n = numa_node_of_cpu(td->curr_cpu);
854 if (n == node) {
855 processes++;
856 break;
857 }
858 }
859 }
860
861 return processes;
862}
863
864static void calc_convergence_compression(int *strong)
865{
866 unsigned int nodes_min, nodes_max;
867 int p;
868
869 nodes_min = -1;
870 nodes_max = 0;
871
872 for (p = 0; p < g->p.nr_proc; p++) {
873 unsigned int nodes = count_process_nodes(p);
874
875 nodes_min = min(nodes, nodes_min);
876 nodes_max = max(nodes, nodes_max);
877 }
878
879 /* Strong convergence: all threads compress on a single node: */
880 if (nodes_min == 1 && nodes_max == 1) {
881 *strong = 1;
882 } else {
883 *strong = 0;
884 tprintf(" {%d-%d}", nodes_min, nodes_max);
885 }
886}
887
888static void calc_convergence(double runtime_ns_max, double *convergence)
889{
890 unsigned int loops_done_min, loops_done_max;
891 int process_groups;
892 int nodes[MAX_NR_NODES];
893 int distance;
894 int nr_min;
895 int nr_max;
896 int strong;
897 int sum;
898 int nr;
899 int node;
900 int cpu;
901 int t;
902
903 if (!g->p.show_convergence && !g->p.measure_convergence)
904 return;
905
906 for (node = 0; node < g->p.nr_nodes; node++)
907 nodes[node] = 0;
908
909 loops_done_min = -1;
910 loops_done_max = 0;
911
912 for (t = 0; t < g->p.nr_tasks; t++) {
913 struct thread_data *td = g->threads + t;
914 unsigned int loops_done;
915
916 cpu = td->curr_cpu;
917
918 /* Not all threads have written it yet: */
919 if (cpu < 0)
920 continue;
921
922 node = numa_node_of_cpu(cpu);
923
924 nodes[node]++;
925
926 loops_done = td->loops_done;
927 loops_done_min = min(loops_done, loops_done_min);
928 loops_done_max = max(loops_done, loops_done_max);
929 }
930
931 nr_max = 0;
932 nr_min = g->p.nr_tasks;
933 sum = 0;
934
935 for (node = 0; node < g->p.nr_nodes; node++) {
936 nr = nodes[node];
937 nr_min = min(nr, nr_min);
938 nr_max = max(nr, nr_max);
939 sum += nr;
940 }
941 BUG_ON(nr_min > nr_max);
942
943 BUG_ON(sum > g->p.nr_tasks);
944
945 if (0 && (sum < g->p.nr_tasks))
946 return;
947
948 /*
949 * Count the number of distinct process groups present
950 * on nodes - when we are converged this will decrease
951 * to g->p.nr_proc:
952 */
953 process_groups = 0;
954
955 for (node = 0; node < g->p.nr_nodes; node++) {
956 int processes = count_node_processes(node);
957
958 nr = nodes[node];
959 tprintf(" %2d/%-2d", nr, processes);
960
961 process_groups += processes;
962 }
963
964 distance = nr_max - nr_min;
965
966 tprintf(" [%2d/%-2d]", distance, process_groups);
967
968 tprintf(" l:%3d-%-3d (%3d)",
969 loops_done_min, loops_done_max, loops_done_max-loops_done_min);
970
971 if (loops_done_min && loops_done_max) {
972 double skew = 1.0 - (double)loops_done_min/loops_done_max;
973
974 tprintf(" [%4.1f%%]", skew * 100.0);
975 }
976
977 calc_convergence_compression(&strong);
978
979 if (strong && process_groups == g->p.nr_proc) {
980 if (!*convergence) {
981 *convergence = runtime_ns_max;
982 tprintf(" (%6.1fs converged)\n", *convergence/1e9);
983 if (g->p.measure_convergence) {
984 g->all_converged = true;
985 g->stop_work = true;
986 }
987 }
988 } else {
989 if (*convergence) {
990 tprintf(" (%6.1fs de-converged)", runtime_ns_max/1e9);
991 *convergence = 0;
992 }
993 tprintf("\n");
994 }
995}
996
997static void show_summary(double runtime_ns_max, int l, double *convergence)
998{
999 tprintf("\r # %5.1f%% [%.1f mins]",
1000 (double)(l+1)/g->p.nr_loops*100.0, runtime_ns_max/1e9 / 60.0);
1001
1002 calc_convergence(runtime_ns_max, convergence);
1003
1004 if (g->p.show_details >= 0)
1005 fflush(stdout);
1006}
1007
1008static void *worker_thread(void *__tdata)
1009{
1010 struct thread_data *td = __tdata;
1011 struct timeval start0, start, stop, diff;
1012 int process_nr = td->process_nr;
1013 int thread_nr = td->thread_nr;
1014 unsigned long last_perturbance;
1015 int task_nr = td->task_nr;
1016 int details = g->p.show_details;
1017 int first_task, last_task;
1018 double convergence = 0;
1019 u64 val = td->val;
1020 double runtime_ns_max;
1021 u8 *global_data;
1022 u8 *process_data;
1023 u8 *thread_data;
1024 u64 bytes_done;
1025 long work_done;
1026 u32 l;
1027
1028 bind_to_cpumask(td->bind_cpumask);
1029 bind_to_memnode(td->bind_node);
1030
1031 set_taskname("thread %d/%d", process_nr, thread_nr);
1032
1033 global_data = g->data;
1034 process_data = td->process_data;
1035 thread_data = setup_private_data(g->p.bytes_thread);
1036
1037 bytes_done = 0;
1038
1039 last_task = 0;
1040 if (process_nr == g->p.nr_proc-1 && thread_nr == g->p.nr_threads-1)
1041 last_task = 1;
1042
1043 first_task = 0;
1044 if (process_nr == 0 && thread_nr == 0)
1045 first_task = 1;
1046
1047 if (details >= 2) {
1048 printf("# thread %2d / %2d global mem: %p, process mem: %p, thread mem: %p\n",
1049 process_nr, thread_nr, global_data, process_data, thread_data);
1050 }
1051
1052 if (g->p.serialize_startup) {
1053 pthread_mutex_lock(&g->startup_mutex);
1054 g->nr_tasks_started++;
1055 pthread_mutex_unlock(&g->startup_mutex);
1056
1057 /* Here we will wait for the main process to start us all at once: */
1058 pthread_mutex_lock(&g->start_work_mutex);
1059 g->nr_tasks_working++;
1060
1061 /* Last one wake the main process: */
1062 if (g->nr_tasks_working == g->p.nr_tasks)
1063 pthread_mutex_unlock(&g->startup_done_mutex);
1064
1065 pthread_mutex_unlock(&g->start_work_mutex);
1066 }
1067
1068 gettimeofday(&start0, NULL);
1069
1070 start = stop = start0;
1071 last_perturbance = start.tv_sec;
1072
1073 for (l = 0; l < g->p.nr_loops; l++) {
1074 start = stop;
1075
1076 if (g->stop_work)
1077 break;
1078
1079 val += do_work(global_data, g->p.bytes_global, process_nr, g->p.nr_proc, l, val);
1080 val += do_work(process_data, g->p.bytes_process, thread_nr, g->p.nr_threads, l, val);
1081 val += do_work(thread_data, g->p.bytes_thread, 0, 1, l, val);
1082
1083 if (g->p.sleep_usecs) {
1084 pthread_mutex_lock(td->process_lock);
1085 usleep(g->p.sleep_usecs);
1086 pthread_mutex_unlock(td->process_lock);
1087 }
1088 /*
1089 * Amount of work to be done under a process-global lock:
1090 */
1091 if (g->p.bytes_process_locked) {
1092 pthread_mutex_lock(td->process_lock);
1093 val += do_work(process_data, g->p.bytes_process_locked, thread_nr, g->p.nr_threads, l, val);
1094 pthread_mutex_unlock(td->process_lock);
1095 }
1096
1097 work_done = g->p.bytes_global + g->p.bytes_process +
1098 g->p.bytes_process_locked + g->p.bytes_thread;
1099
1100 update_curr_cpu(task_nr, work_done);
1101 bytes_done += work_done;
1102
1103 if (details < 0 && !g->p.perturb_secs && !g->p.measure_convergence && !g->p.nr_secs)
1104 continue;
1105
1106 td->loops_done = l;
1107
1108 gettimeofday(&stop, NULL);
1109
1110 /* Check whether our max runtime timed out: */
1111 if (g->p.nr_secs) {
1112 timersub(&stop, &start0, &diff);
1113 if (diff.tv_sec >= g->p.nr_secs) {
1114 g->stop_work = true;
1115 break;
1116 }
1117 }
1118
1119 /* Update the summary at most once per second: */
1120 if (start.tv_sec == stop.tv_sec)
1121 continue;
1122
1123 /*
1124 * Perturb the first task's equilibrium every g->p.perturb_secs seconds,
1125 * by migrating to CPU#0:
1126 */
1127 if (first_task && g->p.perturb_secs && (int)(stop.tv_sec - last_perturbance) >= g->p.perturb_secs) {
1128 cpu_set_t orig_mask;
1129 int target_cpu;
1130 int this_cpu;
1131
1132 last_perturbance = stop.tv_sec;
1133
1134 /*
1135 * Depending on where we are running, move into
1136 * the other half of the system, to create some
1137 * real disturbance:
1138 */
1139 this_cpu = g->threads[task_nr].curr_cpu;
1140 if (this_cpu < g->p.nr_cpus/2)
1141 target_cpu = g->p.nr_cpus-1;
1142 else
1143 target_cpu = 0;
1144
1145 orig_mask = bind_to_cpu(target_cpu);
1146
1147 /* Here we are running on the target CPU already */
1148 if (details >= 1)
1149 printf(" (injecting perturbalance, moved to CPU#%d)\n", target_cpu);
1150
1151 bind_to_cpumask(orig_mask);
1152 }
1153
1154 if (details >= 3) {
1155 timersub(&stop, &start, &diff);
1156 runtime_ns_max = diff.tv_sec * 1000000000;
1157 runtime_ns_max += diff.tv_usec * 1000;
1158
1159 if (details >= 0) {
1160 printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016lx]\n",
1161 process_nr, thread_nr, runtime_ns_max / bytes_done, val);
1162 }
1163 fflush(stdout);
1164 }
1165 if (!last_task)
1166 continue;
1167
1168 timersub(&stop, &start0, &diff);
1169 runtime_ns_max = diff.tv_sec * 1000000000ULL;
1170 runtime_ns_max += diff.tv_usec * 1000ULL;
1171
1172 show_summary(runtime_ns_max, l, &convergence);
1173 }
1174
1175 gettimeofday(&stop, NULL);
1176 timersub(&stop, &start0, &diff);
1177 td->runtime_ns = diff.tv_sec * 1000000000ULL;
1178 td->runtime_ns += diff.tv_usec * 1000ULL;
1179
1180 free_data(thread_data, g->p.bytes_thread);
1181
1182 pthread_mutex_lock(&g->stop_work_mutex);
1183 g->bytes_done += bytes_done;
1184 pthread_mutex_unlock(&g->stop_work_mutex);
1185
1186 return NULL;
1187}
1188
1189/*
1190 * A worker process starts a couple of threads:
1191 */
1192static void worker_process(int process_nr)
1193{
1194 pthread_mutex_t process_lock;
1195 struct thread_data *td;
1196 pthread_t *pthreads;
1197 u8 *process_data;
1198 int task_nr;
1199 int ret;
1200 int t;
1201
1202 pthread_mutex_init(&process_lock, NULL);
1203 set_taskname("process %d", process_nr);
1204
1205 /*
1206 * Pick up the memory policy and the CPU binding of our first thread,
1207 * so that we initialize memory accordingly:
1208 */
1209 task_nr = process_nr*g->p.nr_threads;
1210 td = g->threads + task_nr;
1211
1212 bind_to_memnode(td->bind_node);
1213 bind_to_cpumask(td->bind_cpumask);
1214
1215 pthreads = zalloc(g->p.nr_threads * sizeof(pthread_t));
1216 process_data = setup_private_data(g->p.bytes_process);
1217
1218 if (g->p.show_details >= 3) {
1219 printf(" # process %2d global mem: %p, process mem: %p\n",
1220 process_nr, g->data, process_data);
1221 }
1222
1223 for (t = 0; t < g->p.nr_threads; t++) {
1224 task_nr = process_nr*g->p.nr_threads + t;
1225 td = g->threads + task_nr;
1226
1227 td->process_data = process_data;
1228 td->process_nr = process_nr;
1229 td->thread_nr = t;
1230 td->task_nr = task_nr;
1231 td->val = rand();
1232 td->curr_cpu = -1;
1233 td->process_lock = &process_lock;
1234
1235 ret = pthread_create(pthreads + t, NULL, worker_thread, td);
1236 BUG_ON(ret);
1237 }
1238
1239 for (t = 0; t < g->p.nr_threads; t++) {
1240 ret = pthread_join(pthreads[t], NULL);
1241 BUG_ON(ret);
1242 }
1243
1244 free_data(process_data, g->p.bytes_process);
1245 free(pthreads);
1246}
1247
1248static void print_summary(void)
1249{
1250 if (g->p.show_details < 0)
1251 return;
1252
1253 printf("\n ###\n");
1254 printf(" # %d %s will execute (on %d nodes, %d CPUs):\n",
1255 g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", g->p.nr_nodes, g->p.nr_cpus);
1256 printf(" # %5dx %5ldMB global shared mem operations\n",
1257 g->p.nr_loops, g->p.bytes_global/1024/1024);
1258 printf(" # %5dx %5ldMB process shared mem operations\n",
1259 g->p.nr_loops, g->p.bytes_process/1024/1024);
1260 printf(" # %5dx %5ldMB thread local mem operations\n",
1261 g->p.nr_loops, g->p.bytes_thread/1024/1024);
1262
1263 printf(" ###\n");
1264
1265 printf("\n ###\n"); fflush(stdout);
1266}
1267
1268static void init_thread_data(void)
1269{
1270 ssize_t size = sizeof(*g->threads)*g->p.nr_tasks;
1271 int t;
1272
1273 g->threads = zalloc_shared_data(size);
1274
1275 for (t = 0; t < g->p.nr_tasks; t++) {
1276 struct thread_data *td = g->threads + t;
1277 int cpu;
1278
1279 /* Allow all nodes by default: */
1280 td->bind_node = -1;
1281
1282 /* Allow all CPUs by default: */
1283 CPU_ZERO(&td->bind_cpumask);
1284 for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
1285 CPU_SET(cpu, &td->bind_cpumask);
1286 }
1287}
1288
1289static void deinit_thread_data(void)
1290{
1291 ssize_t size = sizeof(*g->threads)*g->p.nr_tasks;
1292
1293 free_data(g->threads, size);
1294}
1295
1296static int init(void)
1297{
1298 g = (void *)alloc_data(sizeof(*g), MAP_SHARED, 1, 0, 0 /* THP */, 0);
1299
1300 /* Copy over options: */
1301 g->p = p0;
1302
1303 g->p.nr_cpus = numa_num_configured_cpus();
1304
1305 g->p.nr_nodes = numa_max_node() + 1;
1306
1307 /* char array in count_process_nodes(): */
1308 BUG_ON(g->p.nr_nodes > MAX_NR_NODES || g->p.nr_nodes < 0);
1309
1310 if (g->p.show_quiet && !g->p.show_details)
1311 g->p.show_details = -1;
1312
1313 /* Some memory should be specified: */
1314 if (!g->p.mb_global_str && !g->p.mb_proc_str && !g->p.mb_thread_str)
1315 return -1;
1316
1317 if (g->p.mb_global_str) {
1318 g->p.mb_global = atof(g->p.mb_global_str);
1319 BUG_ON(g->p.mb_global < 0);
1320 }
1321
1322 if (g->p.mb_proc_str) {
1323 g->p.mb_proc = atof(g->p.mb_proc_str);
1324 BUG_ON(g->p.mb_proc < 0);
1325 }
1326
1327 if (g->p.mb_proc_locked_str) {
1328 g->p.mb_proc_locked = atof(g->p.mb_proc_locked_str);
1329 BUG_ON(g->p.mb_proc_locked < 0);
1330 BUG_ON(g->p.mb_proc_locked > g->p.mb_proc);
1331 }
1332
1333 if (g->p.mb_thread_str) {
1334 g->p.mb_thread = atof(g->p.mb_thread_str);
1335 BUG_ON(g->p.mb_thread < 0);
1336 }
1337
1338 BUG_ON(g->p.nr_threads <= 0);
1339 BUG_ON(g->p.nr_proc <= 0);
1340
1341 g->p.nr_tasks = g->p.nr_proc*g->p.nr_threads;
1342
1343 g->p.bytes_global = g->p.mb_global *1024L*1024L;
1344 g->p.bytes_process = g->p.mb_proc *1024L*1024L;
1345 g->p.bytes_process_locked = g->p.mb_proc_locked *1024L*1024L;
1346 g->p.bytes_thread = g->p.mb_thread *1024L*1024L;
1347
1348 g->data = setup_shared_data(g->p.bytes_global);
1349
1350 /* Startup serialization: */
1351 init_global_mutex(&g->start_work_mutex);
1352 init_global_mutex(&g->startup_mutex);
1353 init_global_mutex(&g->startup_done_mutex);
1354 init_global_mutex(&g->stop_work_mutex);
1355
1356 init_thread_data();
1357
1358 tprintf("#\n");
1359 parse_setup_cpu_list();
1360 parse_setup_node_list();
1361 tprintf("#\n");
1362
1363 print_summary();
1364
1365 return 0;
1366}
1367
1368static void deinit(void)
1369{
1370 free_data(g->data, g->p.bytes_global);
1371 g->data = NULL;
1372
1373 deinit_thread_data();
1374
1375 free_data(g, sizeof(*g));
1376 g = NULL;
1377}
1378
1379/*
1380 * Print a short or long result, depending on the verbosity setting:
1381 */
1382static void print_res(const char *name, double val,
1383 const char *txt_unit, const char *txt_short, const char *txt_long)
1384{
1385 if (!name)
1386 name = "main,";
1387
1388 if (g->p.show_quiet)
1389 printf(" %-30s %15.3f, %-15s %s\n", name, val, txt_unit, txt_short);
1390 else
1391 printf(" %14.3f %s\n", val, txt_long);
1392}
1393
1394static int __bench_numa(const char *name)
1395{
1396 struct timeval start, stop, diff;
1397 u64 runtime_ns_min, runtime_ns_sum;
1398 pid_t *pids, pid, wpid;
1399 double delta_runtime;
1400 double runtime_avg;
1401 double runtime_sec_max;
1402 double runtime_sec_min;
1403 int wait_stat;
1404 double bytes;
1405 int i, t;
1406
1407 if (init())
1408 return -1;
1409
1410 pids = zalloc(g->p.nr_proc * sizeof(*pids));
1411 pid = -1;
1412
1413 /* All threads try to acquire it, this way we can wait for them to start up: */
1414 pthread_mutex_lock(&g->start_work_mutex);
1415
1416 if (g->p.serialize_startup) {
1417 tprintf(" #\n");
1418 tprintf(" # Startup synchronization: ..."); fflush(stdout);
1419 }
1420
1421 gettimeofday(&start, NULL);
1422
1423 for (i = 0; i < g->p.nr_proc; i++) {
1424 pid = fork();
1425 dprintf(" # process %2d: PID %d\n", i, pid);
1426
1427 BUG_ON(pid < 0);
1428 if (!pid) {
1429 /* Child process: */
1430 worker_process(i);
1431
1432 exit(0);
1433 }
1434 pids[i] = pid;
1435
1436 }
1437 /* Wait for all the threads to start up: */
1438 while (g->nr_tasks_started != g->p.nr_tasks)
1439 usleep(1000);
1440
1441 BUG_ON(g->nr_tasks_started != g->p.nr_tasks);
1442
1443 if (g->p.serialize_startup) {
1444 double startup_sec;
1445
1446 pthread_mutex_lock(&g->startup_done_mutex);
1447
1448 /* This will start all threads: */
1449 pthread_mutex_unlock(&g->start_work_mutex);
1450
1451 /* This mutex is locked - the last started thread will wake us: */
1452 pthread_mutex_lock(&g->startup_done_mutex);
1453
1454 gettimeofday(&stop, NULL);
1455
1456 timersub(&stop, &start, &diff);
1457
1458 startup_sec = diff.tv_sec * 1000000000.0;
1459 startup_sec += diff.tv_usec * 1000.0;
1460 startup_sec /= 1e9;
1461
1462 tprintf(" threads initialized in %.6f seconds.\n", startup_sec);
1463 tprintf(" #\n");
1464
1465 start = stop;
1466 pthread_mutex_unlock(&g->startup_done_mutex);
1467 } else {
1468 gettimeofday(&start, NULL);
1469 }
1470
1471 /* Parent process: */
1472
1473
1474 for (i = 0; i < g->p.nr_proc; i++) {
1475 wpid = waitpid(pids[i], &wait_stat, 0);
1476 BUG_ON(wpid < 0);
1477 BUG_ON(!WIFEXITED(wait_stat));
1478
1479 }
1480
1481 runtime_ns_sum = 0;
1482 runtime_ns_min = -1LL;
1483
1484 for (t = 0; t < g->p.nr_tasks; t++) {
1485 u64 thread_runtime_ns = g->threads[t].runtime_ns;
1486
1487 runtime_ns_sum += thread_runtime_ns;
1488 runtime_ns_min = min(thread_runtime_ns, runtime_ns_min);
1489 }
1490
1491 gettimeofday(&stop, NULL);
1492 timersub(&stop, &start, &diff);
1493
1494 BUG_ON(bench_format != BENCH_FORMAT_DEFAULT);
1495
1496 tprintf("\n ###\n");
1497 tprintf("\n");
1498
1499 runtime_sec_max = diff.tv_sec * 1000000000.0;
1500 runtime_sec_max += diff.tv_usec * 1000.0;
1501 runtime_sec_max /= 1e9;
1502
1503 runtime_sec_min = runtime_ns_min/1e9;
1504
1505 bytes = g->bytes_done;
1506 runtime_avg = (double)runtime_ns_sum / g->p.nr_tasks / 1e9;
1507
1508 if (g->p.measure_convergence) {
1509 print_res(name, runtime_sec_max,
1510 "secs,", "NUMA-convergence-latency", "secs latency to NUMA-converge");
1511 }
1512
1513 print_res(name, runtime_sec_max,
1514 "secs,", "runtime-max/thread", "secs slowest (max) thread-runtime");
1515
1516 print_res(name, runtime_sec_min,
1517 "secs,", "runtime-min/thread", "secs fastest (min) thread-runtime");
1518
1519 print_res(name, runtime_avg,
1520 "secs,", "runtime-avg/thread", "secs average thread-runtime");
1521
1522 delta_runtime = (runtime_sec_max - runtime_sec_min)/2.0;
1523 print_res(name, delta_runtime / runtime_sec_max * 100.0,
1524 "%,", "spread-runtime/thread", "% difference between max/avg runtime");
1525
1526 print_res(name, bytes / g->p.nr_tasks / 1e9,
1527 "GB,", "data/thread", "GB data processed, per thread");
1528
1529 print_res(name, bytes / 1e9,
1530 "GB,", "data-total", "GB data processed, total");
1531
1532 print_res(name, runtime_sec_max * 1e9 / (bytes / g->p.nr_tasks),
1533 "nsecs,", "runtime/byte/thread","nsecs/byte/thread runtime");
1534
1535 print_res(name, bytes / g->p.nr_tasks / 1e9 / runtime_sec_max,
1536 "GB/sec,", "thread-speed", "GB/sec/thread speed");
1537
1538 print_res(name, bytes / runtime_sec_max / 1e9,
1539 "GB/sec,", "total-speed", "GB/sec total speed");
1540
1541 free(pids);
1542
1543 deinit();
1544
1545 return 0;
1546}
1547
1548#define MAX_ARGS 50
1549
1550static int command_size(const char **argv)
1551{
1552 int size = 0;
1553
1554 while (*argv) {
1555 size++;
1556 argv++;
1557 }
1558
1559 BUG_ON(size >= MAX_ARGS);
1560
1561 return size;
1562}
1563
1564static void init_params(struct params *p, const char *name, int argc, const char **argv)
1565{
1566 int i;
1567
1568 printf("\n # Running %s \"perf bench numa", name);
1569
1570 for (i = 0; i < argc; i++)
1571 printf(" %s", argv[i]);
1572
1573 printf("\"\n");
1574
1575 memset(p, 0, sizeof(*p));
1576
1577 /* Initialize nonzero defaults: */
1578
1579 p->serialize_startup = 1;
1580 p->data_reads = true;
1581 p->data_writes = true;
1582 p->data_backwards = true;
1583 p->data_rand_walk = true;
1584 p->nr_loops = -1;
1585 p->init_random = true;
1586}
1587
1588static int run_bench_numa(const char *name, const char **argv)
1589{
1590 int argc = command_size(argv);
1591
1592 init_params(&p0, name, argc, argv);
1593 argc = parse_options(argc, argv, options, bench_numa_usage, 0);
1594 if (argc)
1595 goto err;
1596
1597 if (__bench_numa(name))
1598 goto err;
1599
1600 return 0;
1601
1602err:
1603 usage_with_options(numa_usage, options);
1604 return -1;
1605}
1606
1607#define OPT_BW_RAM "-s", "20", "-zZq", "--thp", " 1", "--no-data_rand_walk"
1608#define OPT_BW_RAM_NOTHP OPT_BW_RAM, "--thp", "-1"
1609
1610#define OPT_CONV "-s", "100", "-zZ0qcm", "--thp", " 1"
1611#define OPT_CONV_NOTHP OPT_CONV, "--thp", "-1"
1612
1613#define OPT_BW "-s", "20", "-zZ0q", "--thp", " 1"
1614#define OPT_BW_NOTHP OPT_BW, "--thp", "-1"
1615
1616/*
1617 * The built-in test-suite executed by "perf bench numa -a".
1618 *
1619 * (A minimum of 4 nodes and 16 GB of RAM is recommended.)
1620 */
1621static const char *tests[][MAX_ARGS] = {
1622 /* Basic single-stream NUMA bandwidth measurements: */
1623 { "RAM-bw-local,", "mem", "-p", "1", "-t", "1", "-P", "1024",
1624 "-C" , "0", "-M", "0", OPT_BW_RAM },
1625 { "RAM-bw-local-NOTHP,",
1626 "mem", "-p", "1", "-t", "1", "-P", "1024",
1627 "-C" , "0", "-M", "0", OPT_BW_RAM_NOTHP },
1628 { "RAM-bw-remote,", "mem", "-p", "1", "-t", "1", "-P", "1024",
1629 "-C" , "0", "-M", "1", OPT_BW_RAM },
1630
1631 /* 2-stream NUMA bandwidth measurements: */
1632 { "RAM-bw-local-2x,", "mem", "-p", "2", "-t", "1", "-P", "1024",
1633 "-C", "0,2", "-M", "0x2", OPT_BW_RAM },
1634 { "RAM-bw-remote-2x,", "mem", "-p", "2", "-t", "1", "-P", "1024",
1635 "-C", "0,2", "-M", "1x2", OPT_BW_RAM },
1636
1637 /* Cross-stream NUMA bandwidth measurement: */
1638 { "RAM-bw-cross,", "mem", "-p", "2", "-t", "1", "-P", "1024",
1639 "-C", "0,8", "-M", "1,0", OPT_BW_RAM },
1640
1641 /* Convergence latency measurements: */
1642 { " 1x3-convergence,", "mem", "-p", "1", "-t", "3", "-P", "512", OPT_CONV },
1643 { " 1x4-convergence,", "mem", "-p", "1", "-t", "4", "-P", "512", OPT_CONV },
1644 { " 1x6-convergence,", "mem", "-p", "1", "-t", "6", "-P", "1020", OPT_CONV },
1645 { " 2x3-convergence,", "mem", "-p", "3", "-t", "3", "-P", "1020", OPT_CONV },
1646 { " 3x3-convergence,", "mem", "-p", "3", "-t", "3", "-P", "1020", OPT_CONV },
1647 { " 4x4-convergence,", "mem", "-p", "4", "-t", "4", "-P", "512", OPT_CONV },
1648 { " 4x4-convergence-NOTHP,",
1649 "mem", "-p", "4", "-t", "4", "-P", "512", OPT_CONV_NOTHP },
1650 { " 4x6-convergence,", "mem", "-p", "4", "-t", "6", "-P", "1020", OPT_CONV },
1651 { " 4x8-convergence,", "mem", "-p", "4", "-t", "8", "-P", "512", OPT_CONV },
1652 { " 8x4-convergence,", "mem", "-p", "8", "-t", "4", "-P", "512", OPT_CONV },
1653 { " 8x4-convergence-NOTHP,",
1654 "mem", "-p", "8", "-t", "4", "-P", "512", OPT_CONV_NOTHP },
1655 { " 3x1-convergence,", "mem", "-p", "3", "-t", "1", "-P", "512", OPT_CONV },
1656 { " 4x1-convergence,", "mem", "-p", "4", "-t", "1", "-P", "512", OPT_CONV },
1657 { " 8x1-convergence,", "mem", "-p", "8", "-t", "1", "-P", "512", OPT_CONV },
1658 { "16x1-convergence,", "mem", "-p", "16", "-t", "1", "-P", "256", OPT_CONV },
1659 { "32x1-convergence,", "mem", "-p", "32", "-t", "1", "-P", "128", OPT_CONV },
1660
1661 /* Various NUMA process/thread layout bandwidth measurements: */
1662 { " 2x1-bw-process,", "mem", "-p", "2", "-t", "1", "-P", "1024", OPT_BW },
1663 { " 3x1-bw-process,", "mem", "-p", "3", "-t", "1", "-P", "1024", OPT_BW },
1664 { " 4x1-bw-process,", "mem", "-p", "4", "-t", "1", "-P", "1024", OPT_BW },
1665 { " 8x1-bw-process,", "mem", "-p", "8", "-t", "1", "-P", " 512", OPT_BW },
1666 { " 8x1-bw-process-NOTHP,",
1667 "mem", "-p", "8", "-t", "1", "-P", " 512", OPT_BW_NOTHP },
1668 { "16x1-bw-process,", "mem", "-p", "16", "-t", "1", "-P", "256", OPT_BW },
1669
1670 { " 4x1-bw-thread,", "mem", "-p", "1", "-t", "4", "-T", "256", OPT_BW },
1671 { " 8x1-bw-thread,", "mem", "-p", "1", "-t", "8", "-T", "256", OPT_BW },
1672 { "16x1-bw-thread,", "mem", "-p", "1", "-t", "16", "-T", "128", OPT_BW },
1673 { "32x1-bw-thread,", "mem", "-p", "1", "-t", "32", "-T", "64", OPT_BW },
1674
1675 { " 2x3-bw-thread,", "mem", "-p", "2", "-t", "3", "-P", "512", OPT_BW },
1676 { " 4x4-bw-thread,", "mem", "-p", "4", "-t", "4", "-P", "512", OPT_BW },
1677 { " 4x6-bw-thread,", "mem", "-p", "4", "-t", "6", "-P", "512", OPT_BW },
1678 { " 4x8-bw-thread,", "mem", "-p", "4", "-t", "8", "-P", "512", OPT_BW },
1679 { " 4x8-bw-thread-NOTHP,",
1680 "mem", "-p", "4", "-t", "8", "-P", "512", OPT_BW_NOTHP },
1681 { " 3x3-bw-thread,", "mem", "-p", "3", "-t", "3", "-P", "512", OPT_BW },
1682 { " 5x5-bw-thread,", "mem", "-p", "5", "-t", "5", "-P", "512", OPT_BW },
1683
1684 { "2x16-bw-thread,", "mem", "-p", "2", "-t", "16", "-P", "512", OPT_BW },
1685 { "1x32-bw-thread,", "mem", "-p", "1", "-t", "32", "-P", "2048", OPT_BW },
1686
1687 { "numa02-bw,", "mem", "-p", "1", "-t", "32", "-T", "32", OPT_BW },
1688 { "numa02-bw-NOTHP,", "mem", "-p", "1", "-t", "32", "-T", "32", OPT_BW_NOTHP },
1689 { "numa01-bw-thread,", "mem", "-p", "2", "-t", "16", "-T", "192", OPT_BW },
1690 { "numa01-bw-thread-NOTHP,",
1691 "mem", "-p", "2", "-t", "16", "-T", "192", OPT_BW_NOTHP },
1692};
1693
1694static int bench_all(void)
1695{
1696 int nr = ARRAY_SIZE(tests);
1697 int ret;
1698 int i;
1699
1700 ret = system("echo ' #'; echo ' # Running test on: '$(uname -a); echo ' #'");
1701 BUG_ON(ret < 0);
1702
1703 for (i = 0; i < nr; i++) {
1704 if (run_bench_numa(tests[i][0], tests[i] + 1))
1705 return -1;
1706 }
1707
1708 printf("\n");
1709
1710 return 0;
1711}
1712
1713int bench_numa(int argc, const char **argv, const char *prefix __maybe_unused)
1714{
1715 init_params(&p0, "main,", argc, argv);
1716 argc = parse_options(argc, argv, options, bench_numa_usage, 0);
1717 if (argc)
1718 goto err;
1719
1720 if (p0.run_all)
1721 return bench_all();
1722
1723 if (__bench_numa(NULL))
1724 goto err;
1725
1726 return 0;
1727
1728err:
1729 usage_with_options(numa_usage, options);
1730 return -1;
1731}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index dc870cf31b79..db491e9a812b 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -34,9 +34,10 @@
34 34
35struct perf_annotate { 35struct perf_annotate {
36 struct perf_tool tool; 36 struct perf_tool tool;
37 bool force, use_tui, use_stdio; 37 bool force, use_tui, use_stdio, use_gtk;
38 bool full_paths; 38 bool full_paths;
39 bool print_line; 39 bool print_line;
40 bool skip_missing;
40 const char *sym_hist_filter; 41 const char *sym_hist_filter;
41 const char *cpu_list; 42 const char *cpu_list;
42 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 43 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@@ -62,7 +63,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
62 return 0; 63 return 0;
63 } 64 }
64 65
65 he = __hists__add_entry(&evsel->hists, al, NULL, 1); 66 he = __hists__add_entry(&evsel->hists, al, NULL, 1, 1);
66 if (he == NULL) 67 if (he == NULL)
67 return -ENOMEM; 68 return -ENOMEM;
68 69
@@ -108,14 +109,16 @@ static int process_sample_event(struct perf_tool *tool,
108 return 0; 109 return 0;
109} 110}
110 111
111static int hist_entry__tty_annotate(struct hist_entry *he, int evidx, 112static int hist_entry__tty_annotate(struct hist_entry *he,
113 struct perf_evsel *evsel,
112 struct perf_annotate *ann) 114 struct perf_annotate *ann)
113{ 115{
114 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, 116 return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel,
115 ann->print_line, ann->full_paths, 0, 0); 117 ann->print_line, ann->full_paths, 0, 0);
116} 118}
117 119
118static void hists__find_annotations(struct hists *self, int evidx, 120static void hists__find_annotations(struct hists *self,
121 struct perf_evsel *evsel,
119 struct perf_annotate *ann) 122 struct perf_annotate *ann)
120{ 123{
121 struct rb_node *nd = rb_first(&self->entries), *next; 124 struct rb_node *nd = rb_first(&self->entries), *next;
@@ -138,9 +141,22 @@ find_next:
138 continue; 141 continue;
139 } 142 }
140 143
141 if (use_browser > 0) { 144 if (use_browser == 2) {
142 key = hist_entry__tui_annotate(he, evidx, NULL); 145 int ret;
146
147 ret = hist_entry__gtk_annotate(he, evsel, NULL);
148 if (!ret || !ann->skip_missing)
149 return;
150
151 /* skip missing symbols */
152 nd = rb_next(nd);
153 } else if (use_browser == 1) {
154 key = hist_entry__tui_annotate(he, evsel, NULL);
143 switch (key) { 155 switch (key) {
156 case -1:
157 if (!ann->skip_missing)
158 return;
159 /* fall through */
144 case K_RIGHT: 160 case K_RIGHT:
145 next = rb_next(nd); 161 next = rb_next(nd);
146 break; 162 break;
@@ -154,7 +170,7 @@ find_next:
154 if (next != NULL) 170 if (next != NULL)
155 nd = next; 171 nd = next;
156 } else { 172 } else {
157 hist_entry__tty_annotate(he, evidx, ann); 173 hist_entry__tty_annotate(he, evsel, ann);
158 nd = rb_next(nd); 174 nd = rb_next(nd);
159 /* 175 /*
160 * Since we have a hist_entry per IP for the same 176 * Since we have a hist_entry per IP for the same
@@ -216,7 +232,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
216 total_nr_samples += nr_samples; 232 total_nr_samples += nr_samples;
217 hists__collapse_resort(hists); 233 hists__collapse_resort(hists);
218 hists__output_resort(hists); 234 hists__output_resort(hists);
219 hists__find_annotations(hists, pos->idx, ann); 235
236 if (symbol_conf.event_group &&
237 !perf_evsel__is_group_leader(pos))
238 continue;
239
240 hists__find_annotations(hists, pos, ann);
220 } 241 }
221 } 242 }
222 243
@@ -224,6 +245,10 @@ static int __cmd_annotate(struct perf_annotate *ann)
224 ui__error("The %s file has no samples!\n", session->filename); 245 ui__error("The %s file has no samples!\n", session->filename);
225 goto out_delete; 246 goto out_delete;
226 } 247 }
248
249 if (use_browser == 2)
250 perf_gtk__show_annotations();
251
227out_delete: 252out_delete:
228 /* 253 /*
229 * Speed up the exit process, for large files this can 254 * Speed up the exit process, for large files this can
@@ -270,6 +295,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
270 "be more verbose (show symbol address, etc)"), 295 "be more verbose (show symbol address, etc)"),
271 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 296 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
272 "dump raw trace in ASCII"), 297 "dump raw trace in ASCII"),
298 OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"),
273 OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), 299 OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
274 OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), 300 OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
275 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 301 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
@@ -280,6 +306,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
280 "print matching source lines (may be slow)"), 306 "print matching source lines (may be slow)"),
281 OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, 307 OPT_BOOLEAN('P', "full-paths", &annotate.full_paths,
282 "Don't shorten the displayed pathnames"), 308 "Don't shorten the displayed pathnames"),
309 OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
310 "Skip symbols that cannot be annotated"),
283 OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), 311 OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
284 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 312 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
285 "Look for files with symbols relative to this directory"), 313 "Look for files with symbols relative to this directory"),
@@ -291,6 +319,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
291 "Specify disassembler style (e.g. -M intel for intel syntax)"), 319 "Specify disassembler style (e.g. -M intel for intel syntax)"),
292 OPT_STRING(0, "objdump", &objdump_path, "path", 320 OPT_STRING(0, "objdump", &objdump_path, "path",
293 "objdump binary to use for disassembly and annotations"), 321 "objdump binary to use for disassembly and annotations"),
322 OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
323 "Show event group information together"),
294 OPT_END() 324 OPT_END()
295 }; 325 };
296 326
@@ -300,6 +330,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
300 use_browser = 0; 330 use_browser = 0;
301 else if (annotate.use_tui) 331 else if (annotate.use_tui)
302 use_browser = 1; 332 use_browser = 1;
333 else if (annotate.use_gtk)
334 use_browser = 2;
303 335
304 setup_browser(true); 336 setup_browser(true);
305 337
@@ -309,7 +341,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
309 if (symbol__init() < 0) 341 if (symbol__init() < 0)
310 return -1; 342 return -1;
311 343
312 setup_sorting(annotate_usage, options); 344 if (setup_sorting() < 0)
345 usage_with_options(annotate_usage, options);
313 346
314 if (argc) { 347 if (argc) {
315 /* 348 /*
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index cae9a5fd2ecf..77298bf892b8 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -35,6 +35,18 @@ struct bench_suite {
35/* sentinel: easy for help */ 35/* sentinel: easy for help */
36#define suite_all { "all", "Test all benchmark suites", NULL } 36#define suite_all { "all", "Test all benchmark suites", NULL }
37 37
38#ifdef LIBNUMA_SUPPORT
39static struct bench_suite numa_suites[] = {
40 { "mem",
41 "Benchmark for NUMA workloads",
42 bench_numa },
43 suite_all,
44 { NULL,
45 NULL,
46 NULL }
47};
48#endif
49
38static struct bench_suite sched_suites[] = { 50static struct bench_suite sched_suites[] = {
39 { "messaging", 51 { "messaging",
40 "Benchmark for scheduler and IPC mechanisms", 52 "Benchmark for scheduler and IPC mechanisms",
@@ -68,6 +80,11 @@ struct bench_subsys {
68}; 80};
69 81
70static struct bench_subsys subsystems[] = { 82static struct bench_subsys subsystems[] = {
83#ifdef LIBNUMA_SUPPORT
84 { "numa",
85 "NUMA scheduling and MM behavior",
86 numa_suites },
87#endif
71 { "sched", 88 { "sched",
72 "scheduler and IPC mechanism", 89 "scheduler and IPC mechanism",
73 sched_suites }, 90 sched_suites },
@@ -159,6 +176,7 @@ static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
159 printf("# Running %s/%s benchmark...\n", 176 printf("# Running %s/%s benchmark...\n",
160 subsys->name, 177 subsys->name,
161 suites[i].name); 178 suites[i].name);
179 fflush(stdout);
162 180
163 argv[1] = suites[i].name; 181 argv[1] = suites[i].name;
164 suites[i].fn(1, argv, NULL); 182 suites[i].fn(1, argv, NULL);
@@ -225,6 +243,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
225 printf("# Running %s/%s benchmark...\n", 243 printf("# Running %s/%s benchmark...\n",
226 subsystems[i].name, 244 subsystems[i].name,
227 subsystems[i].suites[j].name); 245 subsystems[i].suites[j].name);
246 fflush(stdout);
228 status = subsystems[i].suites[j].fn(argc - 1, 247 status = subsystems[i].suites[j].fn(argc - 1,
229 argv + 1, prefix); 248 argv + 1, prefix);
230 goto end; 249 goto end;
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index fae8b250b2ca..c96c8fa38243 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -14,6 +14,7 @@
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/strlist.h" 15#include "util/strlist.h"
16#include "util/build-id.h" 16#include "util/build-id.h"
17#include "util/session.h"
17#include "util/symbol.h" 18#include "util/symbol.h"
18 19
19static int build_id_cache__add_file(const char *filename, const char *debugdir) 20static int build_id_cache__add_file(const char *filename, const char *debugdir)
@@ -58,19 +59,89 @@ static int build_id_cache__remove_file(const char *filename,
58 return err; 59 return err;
59} 60}
60 61
62static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
63{
64 char filename[PATH_MAX];
65 u8 build_id[BUILD_ID_SIZE];
66
67 if (dso__build_id_filename(dso, filename, sizeof(filename)) &&
68 filename__read_build_id(filename, build_id,
69 sizeof(build_id)) != sizeof(build_id)) {
70 if (errno == ENOENT)
71 return false;
72
73 pr_warning("Problems with %s file, consider removing it from the cache\n",
74 filename);
75 } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) {
76 pr_warning("Problems with %s file, consider removing it from the cache\n",
77 filename);
78 }
79
80 return true;
81}
82
83static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
84{
85 struct perf_session *session = perf_session__new(filename, O_RDONLY,
86 force, false, NULL);
87 if (session == NULL)
88 return -1;
89
90 perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
91 perf_session__delete(session);
92
93 return 0;
94}
95
96static int build_id_cache__update_file(const char *filename,
97 const char *debugdir)
98{
99 u8 build_id[BUILD_ID_SIZE];
100 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
101
102 int err;
103
104 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
105 pr_debug("Couldn't read a build-id in %s\n", filename);
106 return -1;
107 }
108
109 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
110 err = build_id_cache__remove_s(sbuild_id, debugdir);
111 if (!err) {
112 err = build_id_cache__add_s(sbuild_id, debugdir, filename,
113 false, false);
114 }
115 if (verbose)
116 pr_info("Updating %s %s: %s\n", sbuild_id, filename,
117 err ? "FAIL" : "Ok");
118
119 return err;
120}
121
61int cmd_buildid_cache(int argc, const char **argv, 122int cmd_buildid_cache(int argc, const char **argv,
62 const char *prefix __maybe_unused) 123 const char *prefix __maybe_unused)
63{ 124{
64 struct strlist *list; 125 struct strlist *list;
65 struct str_node *pos; 126 struct str_node *pos;
127 int ret = 0;
128 bool force = false;
66 char debugdir[PATH_MAX]; 129 char debugdir[PATH_MAX];
67 char const *add_name_list_str = NULL, 130 char const *add_name_list_str = NULL,
68 *remove_name_list_str = NULL; 131 *remove_name_list_str = NULL,
132 *missing_filename = NULL,
133 *update_name_list_str = NULL;
134
69 const struct option buildid_cache_options[] = { 135 const struct option buildid_cache_options[] = {
70 OPT_STRING('a', "add", &add_name_list_str, 136 OPT_STRING('a', "add", &add_name_list_str,
71 "file list", "file(s) to add"), 137 "file list", "file(s) to add"),
72 OPT_STRING('r', "remove", &remove_name_list_str, "file list", 138 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
73 "file(s) to remove"), 139 "file(s) to remove"),
140 OPT_STRING('M', "missing", &missing_filename, "file",
141 "to find missing build ids in the cache"),
142 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
143 OPT_STRING('u', "update", &update_name_list_str, "file list",
144 "file(s) to update"),
74 OPT_INCR('v', "verbose", &verbose, "be more verbose"), 145 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
75 OPT_END() 146 OPT_END()
76 }; 147 };
@@ -125,5 +196,26 @@ int cmd_buildid_cache(int argc, const char **argv,
125 } 196 }
126 } 197 }
127 198
128 return 0; 199 if (missing_filename)
200 ret = build_id_cache__fprintf_missing(missing_filename, force, stdout);
201
202 if (update_name_list_str) {
203 list = strlist__new(true, update_name_list_str);
204 if (list) {
205 strlist__for_each(pos, list)
206 if (build_id_cache__update_file(pos->s, debugdir)) {
207 if (errno == ENOENT) {
208 pr_debug("%s wasn't in the cache\n",
209 pos->s);
210 continue;
211 }
212 pr_warning("Couldn't update %s: %s\n",
213 pos->s, strerror(errno));
214 }
215
216 strlist__delete(list);
217 }
218 }
219
220 return ret;
129} 221}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index a82d99fec83e..e74366a13218 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -44,23 +44,26 @@ static int filename__fprintf_build_id(const char *name, FILE *fp)
44 return fprintf(fp, "%s\n", sbuild_id); 44 return fprintf(fp, "%s\n", sbuild_id);
45} 45}
46 46
47static bool dso__skip_buildid(struct dso *dso, int with_hits)
48{
49 return with_hits && !dso->hit;
50}
51
47static int perf_session__list_build_ids(bool force, bool with_hits) 52static int perf_session__list_build_ids(bool force, bool with_hits)
48{ 53{
49 struct perf_session *session; 54 struct perf_session *session;
50 55
51 symbol__elf_init(); 56 symbol__elf_init();
52
53 session = perf_session__new(input_name, O_RDONLY, force, false,
54 &build_id__mark_dso_hit_ops);
55 if (session == NULL)
56 return -1;
57
58 /* 57 /*
59 * See if this is an ELF file first: 58 * See if this is an ELF file first:
60 */ 59 */
61 if (filename__fprintf_build_id(session->filename, stdout)) 60 if (filename__fprintf_build_id(input_name, stdout))
62 goto out; 61 goto out;
63 62
63 session = perf_session__new(input_name, O_RDONLY, force, false,
64 &build_id__mark_dso_hit_ops);
65 if (session == NULL)
66 return -1;
64 /* 67 /*
65 * in pipe-mode, the only way to get the buildids is to parse 68 * in pipe-mode, the only way to get the buildids is to parse
66 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID 69 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
@@ -68,9 +71,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
68 if (with_hits || session->fd_pipe) 71 if (with_hits || session->fd_pipe)
69 perf_session__process_events(session, &build_id__mark_dso_hit_ops); 72 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
70 73
71 perf_session__fprintf_dsos_buildid(session, stdout, with_hits); 74 perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
72out:
73 perf_session__delete(session); 75 perf_session__delete(session);
76out:
74 return 0; 77 return 0;
75} 78}
76 79
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 93b852f8a5d5..da8f8eb383a0 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -23,7 +23,6 @@ static char const *input_old = "perf.data.old",
23 *input_new = "perf.data"; 23 *input_new = "perf.data";
24static char diff__default_sort_order[] = "dso,symbol"; 24static char diff__default_sort_order[] = "dso,symbol";
25static bool force; 25static bool force;
26static bool show_displacement;
27static bool show_period; 26static bool show_period;
28static bool show_formula; 27static bool show_formula;
29static bool show_baseline_only; 28static bool show_baseline_only;
@@ -146,58 +145,47 @@ static int setup_compute(const struct option *opt, const char *str,
146 return -EINVAL; 145 return -EINVAL;
147} 146}
148 147
149static double get_period_percent(struct hist_entry *he, u64 period) 148double perf_diff__period_percent(struct hist_entry *he, u64 period)
150{ 149{
151 u64 total = he->hists->stats.total_period; 150 u64 total = he->hists->stats.total_period;
152 return (period * 100.0) / total; 151 return (period * 100.0) / total;
153} 152}
154 153
155double perf_diff__compute_delta(struct hist_entry *he) 154double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair)
156{ 155{
157 struct hist_entry *pair = hist_entry__next_pair(he); 156 double new_percent = perf_diff__period_percent(he, he->stat.period);
158 double new_percent = get_period_percent(he, he->stat.period); 157 double old_percent = perf_diff__period_percent(pair, pair->stat.period);
159 double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0;
160 158
161 he->diff.period_ratio_delta = new_percent - old_percent; 159 he->diff.period_ratio_delta = new_percent - old_percent;
162 he->diff.computed = true; 160 he->diff.computed = true;
163 return he->diff.period_ratio_delta; 161 return he->diff.period_ratio_delta;
164} 162}
165 163
166double perf_diff__compute_ratio(struct hist_entry *he) 164double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair)
167{ 165{
168 struct hist_entry *pair = hist_entry__next_pair(he);
169 double new_period = he->stat.period; 166 double new_period = he->stat.period;
170 double old_period = pair ? pair->stat.period : 0; 167 double old_period = pair->stat.period;
171 168
172 he->diff.computed = true; 169 he->diff.computed = true;
173 he->diff.period_ratio = pair ? (new_period / old_period) : 0; 170 he->diff.period_ratio = new_period / old_period;
174 return he->diff.period_ratio; 171 return he->diff.period_ratio;
175} 172}
176 173
177s64 perf_diff__compute_wdiff(struct hist_entry *he) 174s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
178{ 175{
179 struct hist_entry *pair = hist_entry__next_pair(he);
180 u64 new_period = he->stat.period; 176 u64 new_period = he->stat.period;
181 u64 old_period = pair ? pair->stat.period : 0; 177 u64 old_period = pair->stat.period;
182 178
183 he->diff.computed = true; 179 he->diff.computed = true;
184 180 he->diff.wdiff = new_period * compute_wdiff_w2 -
185 if (!pair) 181 old_period * compute_wdiff_w1;
186 he->diff.wdiff = 0;
187 else
188 he->diff.wdiff = new_period * compute_wdiff_w2 -
189 old_period * compute_wdiff_w1;
190 182
191 return he->diff.wdiff; 183 return he->diff.wdiff;
192} 184}
193 185
194static int formula_delta(struct hist_entry *he, char *buf, size_t size) 186static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
187 char *buf, size_t size)
195{ 188{
196 struct hist_entry *pair = hist_entry__next_pair(he);
197
198 if (!pair)
199 return -1;
200
201 return scnprintf(buf, size, 189 return scnprintf(buf, size,
202 "(%" PRIu64 " * 100 / %" PRIu64 ") - " 190 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
203 "(%" PRIu64 " * 100 / %" PRIu64 ")", 191 "(%" PRIu64 " * 100 / %" PRIu64 ")",
@@ -205,41 +193,36 @@ static int formula_delta(struct hist_entry *he, char *buf, size_t size)
205 pair->stat.period, pair->hists->stats.total_period); 193 pair->stat.period, pair->hists->stats.total_period);
206} 194}
207 195
208static int formula_ratio(struct hist_entry *he, char *buf, size_t size) 196static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
197 char *buf, size_t size)
209{ 198{
210 struct hist_entry *pair = hist_entry__next_pair(he);
211 double new_period = he->stat.period; 199 double new_period = he->stat.period;
212 double old_period = pair ? pair->stat.period : 0; 200 double old_period = pair->stat.period;
213
214 if (!pair)
215 return -1;
216 201
217 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); 202 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
218} 203}
219 204
220static int formula_wdiff(struct hist_entry *he, char *buf, size_t size) 205static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
206 char *buf, size_t size)
221{ 207{
222 struct hist_entry *pair = hist_entry__next_pair(he);
223 u64 new_period = he->stat.period; 208 u64 new_period = he->stat.period;
224 u64 old_period = pair ? pair->stat.period : 0; 209 u64 old_period = pair->stat.period;
225
226 if (!pair)
227 return -1;
228 210
229 return scnprintf(buf, size, 211 return scnprintf(buf, size,
230 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", 212 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
231 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); 213 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
232} 214}
233 215
234int perf_diff__formula(char *buf, size_t size, struct hist_entry *he) 216int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
217 char *buf, size_t size)
235{ 218{
236 switch (compute) { 219 switch (compute) {
237 case COMPUTE_DELTA: 220 case COMPUTE_DELTA:
238 return formula_delta(he, buf, size); 221 return formula_delta(he, pair, buf, size);
239 case COMPUTE_RATIO: 222 case COMPUTE_RATIO:
240 return formula_ratio(he, buf, size); 223 return formula_ratio(he, pair, buf, size);
241 case COMPUTE_WEIGHTED_DIFF: 224 case COMPUTE_WEIGHTED_DIFF:
242 return formula_wdiff(he, buf, size); 225 return formula_wdiff(he, pair, buf, size);
243 default: 226 default:
244 BUG_ON(1); 227 BUG_ON(1);
245 } 228 }
@@ -248,9 +231,10 @@ int perf_diff__formula(char *buf, size_t size, struct hist_entry *he)
248} 231}
249 232
250static int hists__add_entry(struct hists *self, 233static int hists__add_entry(struct hists *self,
251 struct addr_location *al, u64 period) 234 struct addr_location *al, u64 period,
235 u64 weight)
252{ 236{
253 if (__hists__add_entry(self, al, NULL, period) != NULL) 237 if (__hists__add_entry(self, al, NULL, period, weight) != NULL)
254 return 0; 238 return 0;
255 return -ENOMEM; 239 return -ENOMEM;
256} 240}
@@ -272,7 +256,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
272 if (al.filtered) 256 if (al.filtered)
273 return 0; 257 return 0;
274 258
275 if (hists__add_entry(&evsel->hists, &al, sample->period)) { 259 if (hists__add_entry(&evsel->hists, &al, sample->period, sample->weight)) {
276 pr_warning("problem incrementing symbol period, skipping event\n"); 260 pr_warning("problem incrementing symbol period, skipping event\n");
277 return -1; 261 return -1;
278 } 262 }
@@ -292,48 +276,6 @@ static struct perf_tool tool = {
292 .ordering_requires_timestamps = true, 276 .ordering_requires_timestamps = true,
293}; 277};
294 278
295static void insert_hist_entry_by_name(struct rb_root *root,
296 struct hist_entry *he)
297{
298 struct rb_node **p = &root->rb_node;
299 struct rb_node *parent = NULL;
300 struct hist_entry *iter;
301
302 while (*p != NULL) {
303 parent = *p;
304 iter = rb_entry(parent, struct hist_entry, rb_node);
305 if (hist_entry__cmp(he, iter) < 0)
306 p = &(*p)->rb_left;
307 else
308 p = &(*p)->rb_right;
309 }
310
311 rb_link_node(&he->rb_node, parent, p);
312 rb_insert_color(&he->rb_node, root);
313}
314
315static void hists__name_resort(struct hists *self, bool sort)
316{
317 unsigned long position = 1;
318 struct rb_root tmp = RB_ROOT;
319 struct rb_node *next = rb_first(&self->entries);
320
321 while (next != NULL) {
322 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
323
324 next = rb_next(&n->rb_node);
325 n->position = position++;
326
327 if (sort) {
328 rb_erase(&n->rb_node, &self->entries);
329 insert_hist_entry_by_name(&tmp, n);
330 }
331 }
332
333 if (sort)
334 self->entries = tmp;
335}
336
337static struct perf_evsel *evsel_match(struct perf_evsel *evsel, 279static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
338 struct perf_evlist *evlist) 280 struct perf_evlist *evlist)
339{ 281{
@@ -346,34 +288,34 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
346 return NULL; 288 return NULL;
347} 289}
348 290
349static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) 291static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
350{ 292{
351 struct perf_evsel *evsel; 293 struct perf_evsel *evsel;
352 294
353 list_for_each_entry(evsel, &evlist->entries, node) { 295 list_for_each_entry(evsel, &evlist->entries, node) {
354 struct hists *hists = &evsel->hists; 296 struct hists *hists = &evsel->hists;
355 297
356 hists__output_resort(hists); 298 hists__collapse_resort(hists);
357
358 /*
359 * The hists__name_resort only sets possition
360 * if name is false.
361 */
362 if (name || ((!name) && show_displacement))
363 hists__name_resort(hists, name);
364 } 299 }
365} 300}
366 301
367static void hists__baseline_only(struct hists *hists) 302static void hists__baseline_only(struct hists *hists)
368{ 303{
369 struct rb_node *next = rb_first(&hists->entries); 304 struct rb_root *root;
305 struct rb_node *next;
306
307 if (sort__need_collapse)
308 root = &hists->entries_collapsed;
309 else
310 root = hists->entries_in;
370 311
312 next = rb_first(root);
371 while (next != NULL) { 313 while (next != NULL) {
372 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 314 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
373 315
374 next = rb_next(&he->rb_node); 316 next = rb_next(&he->rb_node_in);
375 if (!hist_entry__next_pair(he)) { 317 if (!hist_entry__next_pair(he)) {
376 rb_erase(&he->rb_node, &hists->entries); 318 rb_erase(&he->rb_node_in, root);
377 hist_entry__free(he); 319 hist_entry__free(he);
378 } 320 }
379 } 321 }
@@ -381,22 +323,32 @@ static void hists__baseline_only(struct hists *hists)
381 323
382static void hists__precompute(struct hists *hists) 324static void hists__precompute(struct hists *hists)
383{ 325{
384 struct rb_node *next = rb_first(&hists->entries); 326 struct rb_root *root;
327 struct rb_node *next;
328
329 if (sort__need_collapse)
330 root = &hists->entries_collapsed;
331 else
332 root = hists->entries_in;
385 333
334 next = rb_first(root);
386 while (next != NULL) { 335 while (next != NULL) {
387 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 336 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
337 struct hist_entry *pair = hist_entry__next_pair(he);
388 338
389 next = rb_next(&he->rb_node); 339 next = rb_next(&he->rb_node_in);
340 if (!pair)
341 continue;
390 342
391 switch (compute) { 343 switch (compute) {
392 case COMPUTE_DELTA: 344 case COMPUTE_DELTA:
393 perf_diff__compute_delta(he); 345 perf_diff__compute_delta(he, pair);
394 break; 346 break;
395 case COMPUTE_RATIO: 347 case COMPUTE_RATIO:
396 perf_diff__compute_ratio(he); 348 perf_diff__compute_ratio(he, pair);
397 break; 349 break;
398 case COMPUTE_WEIGHTED_DIFF: 350 case COMPUTE_WEIGHTED_DIFF:
399 perf_diff__compute_wdiff(he); 351 perf_diff__compute_wdiff(he, pair);
400 break; 352 break;
401 default: 353 default:
402 BUG_ON(1); 354 BUG_ON(1);
@@ -470,19 +422,30 @@ static void insert_hist_entry_by_compute(struct rb_root *root,
470 422
471static void hists__compute_resort(struct hists *hists) 423static void hists__compute_resort(struct hists *hists)
472{ 424{
473 struct rb_root tmp = RB_ROOT; 425 struct rb_root *root;
474 struct rb_node *next = rb_first(&hists->entries); 426 struct rb_node *next;
427
428 if (sort__need_collapse)
429 root = &hists->entries_collapsed;
430 else
431 root = hists->entries_in;
432
433 hists->entries = RB_ROOT;
434 next = rb_first(root);
435
436 hists->nr_entries = 0;
437 hists->stats.total_period = 0;
438 hists__reset_col_len(hists);
475 439
476 while (next != NULL) { 440 while (next != NULL) {
477 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 441 struct hist_entry *he;
478 442
479 next = rb_next(&he->rb_node); 443 he = rb_entry(next, struct hist_entry, rb_node_in);
444 next = rb_next(&he->rb_node_in);
480 445
481 rb_erase(&he->rb_node, &hists->entries); 446 insert_hist_entry_by_compute(&hists->entries, he, compute);
482 insert_hist_entry_by_compute(&tmp, he, compute); 447 hists__inc_nr_entries(hists, he);
483 } 448 }
484
485 hists->entries = tmp;
486} 449}
487 450
488static void hists__process(struct hists *old, struct hists *new) 451static void hists__process(struct hists *old, struct hists *new)
@@ -497,9 +460,11 @@ static void hists__process(struct hists *old, struct hists *new)
497 if (sort_compute) { 460 if (sort_compute) {
498 hists__precompute(new); 461 hists__precompute(new);
499 hists__compute_resort(new); 462 hists__compute_resort(new);
463 } else {
464 hists__output_resort(new);
500 } 465 }
501 466
502 hists__fprintf(new, true, 0, 0, stdout); 467 hists__fprintf(new, true, 0, 0, 0, stdout);
503} 468}
504 469
505static int __cmd_diff(void) 470static int __cmd_diff(void)
@@ -528,8 +493,8 @@ static int __cmd_diff(void)
528 evlist_old = older->evlist; 493 evlist_old = older->evlist;
529 evlist_new = newer->evlist; 494 evlist_new = newer->evlist;
530 495
531 perf_evlist__resort_hists(evlist_old, true); 496 perf_evlist__collapse_resort(evlist_old);
532 perf_evlist__resort_hists(evlist_new, false); 497 perf_evlist__collapse_resort(evlist_new);
533 498
534 list_for_each_entry(evsel, &evlist_new->entries, node) { 499 list_for_each_entry(evsel, &evlist_new->entries, node) {
535 struct perf_evsel *evsel_old; 500 struct perf_evsel *evsel_old;
@@ -562,8 +527,6 @@ static const char * const diff_usage[] = {
562static const struct option options[] = { 527static const struct option options[] = {
563 OPT_INCR('v', "verbose", &verbose, 528 OPT_INCR('v', "verbose", &verbose,
564 "be more verbose (show symbol address, etc)"), 529 "be more verbose (show symbol address, etc)"),
565 OPT_BOOLEAN('M', "displacement", &show_displacement,
566 "Show position displacement relative to baseline"),
567 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, 530 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
568 "Show only items with match in baseline"), 531 "Show only items with match in baseline"),
569 OPT_CALLBACK('c', "compute", &compute, 532 OPT_CALLBACK('c', "compute", &compute,
@@ -597,40 +560,32 @@ static const struct option options[] = {
597 560
598static void ui_init(void) 561static void ui_init(void)
599{ 562{
600 perf_hpp__init();
601
602 /* No overhead column. */
603 perf_hpp__column_enable(PERF_HPP__OVERHEAD, false);
604
605 /* 563 /*
606 * Display baseline/delta/ratio/displacement/ 564 * Display baseline/delta/ratio
607 * formula/periods columns. 565 * formula/periods columns.
608 */ 566 */
609 perf_hpp__column_enable(PERF_HPP__BASELINE, true); 567 perf_hpp__column_enable(PERF_HPP__BASELINE);
610 568
611 switch (compute) { 569 switch (compute) {
612 case COMPUTE_DELTA: 570 case COMPUTE_DELTA:
613 perf_hpp__column_enable(PERF_HPP__DELTA, true); 571 perf_hpp__column_enable(PERF_HPP__DELTA);
614 break; 572 break;
615 case COMPUTE_RATIO: 573 case COMPUTE_RATIO:
616 perf_hpp__column_enable(PERF_HPP__RATIO, true); 574 perf_hpp__column_enable(PERF_HPP__RATIO);
617 break; 575 break;
618 case COMPUTE_WEIGHTED_DIFF: 576 case COMPUTE_WEIGHTED_DIFF:
619 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true); 577 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF);
620 break; 578 break;
621 default: 579 default:
622 BUG_ON(1); 580 BUG_ON(1);
623 }; 581 };
624 582
625 if (show_displacement)
626 perf_hpp__column_enable(PERF_HPP__DISPL, true);
627
628 if (show_formula) 583 if (show_formula)
629 perf_hpp__column_enable(PERF_HPP__FORMULA, true); 584 perf_hpp__column_enable(PERF_HPP__FORMULA);
630 585
631 if (show_period) { 586 if (show_period) {
632 perf_hpp__column_enable(PERF_HPP__PERIOD, true); 587 perf_hpp__column_enable(PERF_HPP__PERIOD);
633 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true); 588 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE);
634 } 589 }
635} 590}
636 591
@@ -658,12 +613,12 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
658 613
659 ui_init(); 614 ui_init();
660 615
661 setup_sorting(diff_usage, options); 616 if (setup_sorting() < 0)
617 usage_with_options(diff_usage, options);
618
662 setup_pager(); 619 setup_pager();
663 620
664 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); 621 sort__setup_elide(NULL);
665 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
666 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
667 622
668 return __cmd_diff(); 623 return __cmd_diff();
669} 624}
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index c20f1dcfb7e2..05bd9dfe875c 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,39 +15,6 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17 17
18struct perf_attr_details {
19 bool freq;
20 bool verbose;
21};
22
23static int comma_printf(bool *first, const char *fmt, ...)
24{
25 va_list args;
26 int ret = 0;
27
28 if (!*first) {
29 ret += printf(",");
30 } else {
31 ret += printf(":");
32 *first = false;
33 }
34
35 va_start(args, fmt);
36 ret += vprintf(fmt, args);
37 va_end(args);
38 return ret;
39}
40
41static int __if_print(bool *first, const char *field, u64 value)
42{
43 if (value == 0)
44 return 0;
45
46 return comma_printf(first, " %s: %" PRIu64, field, value);
47}
48
49#define if_print(field) __if_print(&first, #field, pos->attr.field)
50
51static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) 18static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
52{ 19{
53 struct perf_session *session; 20 struct perf_session *session;
@@ -57,52 +24,8 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
57 if (session == NULL) 24 if (session == NULL)
58 return -ENOMEM; 25 return -ENOMEM;
59 26
60 list_for_each_entry(pos, &session->evlist->entries, node) { 27 list_for_each_entry(pos, &session->evlist->entries, node)
61 bool first = true; 28 perf_evsel__fprintf(pos, details, stdout);
62
63 printf("%s", perf_evsel__name(pos));
64
65 if (details->verbose || details->freq) {
66 comma_printf(&first, " sample_freq=%" PRIu64,
67 (u64)pos->attr.sample_freq);
68 }
69
70 if (details->verbose) {
71 if_print(type);
72 if_print(config);
73 if_print(config1);
74 if_print(config2);
75 if_print(size);
76 if_print(sample_type);
77 if_print(read_format);
78 if_print(disabled);
79 if_print(inherit);
80 if_print(pinned);
81 if_print(exclusive);
82 if_print(exclude_user);
83 if_print(exclude_kernel);
84 if_print(exclude_hv);
85 if_print(exclude_idle);
86 if_print(mmap);
87 if_print(comm);
88 if_print(freq);
89 if_print(inherit_stat);
90 if_print(enable_on_exec);
91 if_print(task);
92 if_print(watermark);
93 if_print(precise_ip);
94 if_print(mmap_data);
95 if_print(sample_id_all);
96 if_print(exclude_host);
97 if_print(exclude_guest);
98 if_print(__reserved_1);
99 if_print(wakeup_events);
100 if_print(bp_type);
101 if_print(branch_sample_type);
102 }
103
104 putchar('\n');
105 }
106 29
107 perf_session__delete(session); 30 perf_session__delete(session);
108 return 0; 31 return 0;
@@ -116,6 +39,8 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
116 OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), 39 OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"),
117 OPT_BOOLEAN('v', "verbose", &details.verbose, 40 OPT_BOOLEAN('v', "verbose", &details.verbose,
118 "Show all event attr details"), 41 "Show all event attr details"),
42 OPT_BOOLEAN('g', "group", &details.event_group,
43 "Show event group information"),
119 OPT_END() 44 OPT_END()
120 }; 45 };
121 const char * const evlist_usage[] = { 46 const char * const evlist_usage[] = {
@@ -127,5 +52,10 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
127 if (argc) 52 if (argc)
128 usage_with_options(evlist_usage, options); 53 usage_with_options(evlist_usage, options);
129 54
55 if (details.event_group && (details.verbose || details.freq)) {
56 pr_err("--group option is not compatible with other options\n");
57 usage_with_options(evlist_usage, options);
58 }
59
130 return __cmd_evlist(input_name, &details); 60 return __cmd_evlist(input_name, &details);
131} 61}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 0b4b796167be..46878daca5cc 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -17,6 +17,7 @@
17#include "util/debug.h" 17#include "util/debug.h"
18 18
19#include <linux/rbtree.h> 19#include <linux/rbtree.h>
20#include <linux/string.h>
20 21
21struct alloc_stat; 22struct alloc_stat;
22typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); 23typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
@@ -340,7 +341,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
340 int n_lines, int is_caller) 341 int n_lines, int is_caller)
341{ 342{
342 struct rb_node *next; 343 struct rb_node *next;
343 struct machine *machine; 344 struct machine *machine = &session->machines.host;
344 345
345 printf("%.102s\n", graph_dotted_line); 346 printf("%.102s\n", graph_dotted_line);
346 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 347 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
@@ -349,11 +350,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
349 350
350 next = rb_first(root); 351 next = rb_first(root);
351 352
352 machine = perf_session__find_host_machine(session);
353 if (!machine) {
354 pr_err("__print_result: couldn't find kernel information\n");
355 return;
356 }
357 while (next && n_lines--) { 353 while (next && n_lines--) {
358 struct alloc_stat *data = rb_entry(next, struct alloc_stat, 354 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
359 node); 355 node);
@@ -614,8 +610,7 @@ static struct sort_dimension *avail_sorts[] = {
614 &pingpong_sort_dimension, 610 &pingpong_sort_dimension,
615}; 611};
616 612
617#define NUM_AVAIL_SORTS \ 613#define NUM_AVAIL_SORTS ((int)ARRAY_SIZE(avail_sorts))
618 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
619 614
620static int sort_dimension__add(const char *tok, struct list_head *list) 615static int sort_dimension__add(const char *tok, struct list_head *list)
621{ 616{
@@ -624,12 +619,11 @@ static int sort_dimension__add(const char *tok, struct list_head *list)
624 619
625 for (i = 0; i < NUM_AVAIL_SORTS; i++) { 620 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
626 if (!strcmp(avail_sorts[i]->name, tok)) { 621 if (!strcmp(avail_sorts[i]->name, tok)) {
627 sort = malloc(sizeof(*sort)); 622 sort = memdup(avail_sorts[i], sizeof(*avail_sorts[i]));
628 if (!sort) { 623 if (!sort) {
629 pr_err("%s: malloc failed\n", __func__); 624 pr_err("%s: memdup failed\n", __func__);
630 return -1; 625 return -1;
631 } 626 }
632 memcpy(sort, avail_sorts[i], sizeof(*sort));
633 list_add_tail(&sort->list, list); 627 list_add_tail(&sort->list, list);
634 return 0; 628 return 0;
635 } 629 }
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index ca3f80ebc100..24b78aecc928 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -12,7 +12,7 @@
12#include "util/parse-options.h" 12#include "util/parse-options.h"
13#include "util/trace-event.h" 13#include "util/trace-event.h"
14#include "util/debug.h" 14#include "util/debug.h"
15#include "util/debugfs.h" 15#include <lk/debugfs.h>
16#include "util/tool.h" 16#include "util/tool.h"
17#include "util/stat.h" 17#include "util/stat.h"
18 18
@@ -328,6 +328,7 @@ static int kvm_events_hash_fn(u64 key)
328static bool kvm_event_expand(struct kvm_event *event, int vcpu_id) 328static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
329{ 329{
330 int old_max_vcpu = event->max_vcpu; 330 int old_max_vcpu = event->max_vcpu;
331 void *prev;
331 332
332 if (vcpu_id < event->max_vcpu) 333 if (vcpu_id < event->max_vcpu)
333 return true; 334 return true;
@@ -335,9 +336,11 @@ static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
335 while (event->max_vcpu <= vcpu_id) 336 while (event->max_vcpu <= vcpu_id)
336 event->max_vcpu += DEFAULT_VCPU_NUM; 337 event->max_vcpu += DEFAULT_VCPU_NUM;
337 338
339 prev = event->vcpu;
338 event->vcpu = realloc(event->vcpu, 340 event->vcpu = realloc(event->vcpu,
339 event->max_vcpu * sizeof(*event->vcpu)); 341 event->max_vcpu * sizeof(*event->vcpu));
340 if (!event->vcpu) { 342 if (!event->vcpu) {
343 free(prev);
341 pr_err("Not enough memory\n"); 344 pr_err("Not enough memory\n");
342 return false; 345 return false;
343 } 346 }
@@ -973,8 +976,7 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv)
973 976
974int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) 977int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
975{ 978{
976 const char *file_name; 979 const char *file_name = NULL;
977
978 const struct option kvm_options[] = { 980 const struct option kvm_options[] = {
979 OPT_STRING('i', "input", &file_name, "file", 981 OPT_STRING('i', "input", &file_name, "file",
980 "Input file name"), 982 "Input file name"),
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
new file mode 100644
index 000000000000..a8ff6d264e50
--- /dev/null
+++ b/tools/perf/builtin-mem.c
@@ -0,0 +1,242 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/parse-options.h"
5#include "util/trace-event.h"
6#include "util/tool.h"
7#include "util/session.h"
8
9#define MEM_OPERATION_LOAD "load"
10#define MEM_OPERATION_STORE "store"
11
12static const char *mem_operation = MEM_OPERATION_LOAD;
13
14struct perf_mem {
15 struct perf_tool tool;
16 char const *input_name;
17 symbol_filter_t annotate_init;
18 bool hide_unresolved;
19 bool dump_raw;
20 const char *cpu_list;
21 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
22};
23
24static const char * const mem_usage[] = {
25 "perf mem [<options>] {record <command> |report}",
26 NULL
27};
28
29static int __cmd_record(int argc, const char **argv)
30{
31 int rec_argc, i = 0, j;
32 const char **rec_argv;
33 char event[64];
34 int ret;
35
36 rec_argc = argc + 4;
37 rec_argv = calloc(rec_argc + 1, sizeof(char *));
38 if (!rec_argv)
39 return -1;
40
41 rec_argv[i++] = strdup("record");
42 if (!strcmp(mem_operation, MEM_OPERATION_LOAD))
43 rec_argv[i++] = strdup("-W");
44 rec_argv[i++] = strdup("-d");
45 rec_argv[i++] = strdup("-e");
46
47 if (strcmp(mem_operation, MEM_OPERATION_LOAD))
48 sprintf(event, "cpu/mem-stores/pp");
49 else
50 sprintf(event, "cpu/mem-loads/pp");
51
52 rec_argv[i++] = strdup(event);
53 for (j = 1; j < argc; j++, i++)
54 rec_argv[i] = argv[j];
55
56 ret = cmd_record(i, rec_argv, NULL);
57 free(rec_argv);
58 return ret;
59}
60
61static int
62dump_raw_samples(struct perf_tool *tool,
63 union perf_event *event,
64 struct perf_sample *sample,
65 struct perf_evsel *evsel __maybe_unused,
66 struct machine *machine)
67{
68 struct perf_mem *mem = container_of(tool, struct perf_mem, tool);
69 struct addr_location al;
70 const char *fmt;
71
72 if (perf_event__preprocess_sample(event, machine, &al, sample,
73 mem->annotate_init) < 0) {
74 fprintf(stderr, "problem processing %d event, skipping it.\n",
75 event->header.type);
76 return -1;
77 }
78
79 if (al.filtered || (mem->hide_unresolved && al.sym == NULL))
80 return 0;
81
82 if (al.map != NULL)
83 al.map->dso->hit = 1;
84
85 if (symbol_conf.field_sep) {
86 fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s%"PRIu64
87 "%s0x%"PRIx64"%s%s:%s\n";
88 } else {
89 fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64
90 "%s%5"PRIu64"%s0x%06"PRIx64"%s%s:%s\n";
91 symbol_conf.field_sep = " ";
92 }
93
94 printf(fmt,
95 sample->pid,
96 symbol_conf.field_sep,
97 sample->tid,
98 symbol_conf.field_sep,
99 event->ip.ip,
100 symbol_conf.field_sep,
101 sample->addr,
102 symbol_conf.field_sep,
103 sample->weight,
104 symbol_conf.field_sep,
105 sample->data_src,
106 symbol_conf.field_sep,
107 al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???",
108 al.sym ? al.sym->name : "???");
109
110 return 0;
111}
112
113static int process_sample_event(struct perf_tool *tool,
114 union perf_event *event,
115 struct perf_sample *sample,
116 struct perf_evsel *evsel,
117 struct machine *machine)
118{
119 return dump_raw_samples(tool, event, sample, evsel, machine);
120}
121
122static int report_raw_events(struct perf_mem *mem)
123{
124 int err = -EINVAL;
125 int ret;
126 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
127 0, false, &mem->tool);
128
129 if (session == NULL)
130 return -ENOMEM;
131
132 if (mem->cpu_list) {
133 ret = perf_session__cpu_bitmap(session, mem->cpu_list,
134 mem->cpu_bitmap);
135 if (ret)
136 goto out_delete;
137 }
138
139 if (symbol__init() < 0)
140 return -1;
141
142 printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
143
144 err = perf_session__process_events(session, &mem->tool);
145 if (err)
146 return err;
147
148 return 0;
149
150out_delete:
151 perf_session__delete(session);
152 return err;
153}
154
155static int report_events(int argc, const char **argv, struct perf_mem *mem)
156{
157 const char **rep_argv;
158 int ret, i = 0, j, rep_argc;
159
160 if (mem->dump_raw)
161 return report_raw_events(mem);
162
163 rep_argc = argc + 3;
164 rep_argv = calloc(rep_argc + 1, sizeof(char *));
165 if (!rep_argv)
166 return -1;
167
168 rep_argv[i++] = strdup("report");
169 rep_argv[i++] = strdup("--mem-mode");
170 rep_argv[i++] = strdup("-n"); /* display number of samples */
171
172 /*
173 * there is no weight (cost) associated with stores, so don't print
174 * the column
175 */
176 if (strcmp(mem_operation, MEM_OPERATION_LOAD))
177 rep_argv[i++] = strdup("--sort=mem,sym,dso,symbol_daddr,"
178 "dso_daddr,tlb,locked");
179
180 for (j = 1; j < argc; j++, i++)
181 rep_argv[i] = argv[j];
182
183 ret = cmd_report(i, rep_argv, NULL);
184 free(rep_argv);
185 return ret;
186}
187
188int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
189{
190 struct stat st;
191 struct perf_mem mem = {
192 .tool = {
193 .sample = process_sample_event,
194 .mmap = perf_event__process_mmap,
195 .comm = perf_event__process_comm,
196 .lost = perf_event__process_lost,
197 .fork = perf_event__process_fork,
198 .build_id = perf_event__process_build_id,
199 .ordered_samples = true,
200 },
201 .input_name = "perf.data",
202 };
203 const struct option mem_options[] = {
204 OPT_STRING('t', "type", &mem_operation,
205 "type", "memory operations(load/store)"),
206 OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw,
207 "dump raw samples in ASCII"),
208 OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved,
209 "Only display entries resolved to a symbol"),
210 OPT_STRING('i', "input", &input_name, "file",
211 "input file name"),
212 OPT_STRING('C', "cpu", &mem.cpu_list, "cpu",
213 "list of cpus to profile"),
214 OPT_STRING('x', "field-separator", &symbol_conf.field_sep,
215 "separator",
216 "separator for columns, no spaces will be added"
217 " between columns '.' is reserved."),
218 OPT_END()
219 };
220
221 argc = parse_options(argc, argv, mem_options, mem_usage,
222 PARSE_OPT_STOP_AT_NON_OPTION);
223
224 if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation))
225 usage_with_options(mem_usage, mem_options);
226
227 if (!mem.input_name || !strlen(mem.input_name)) {
228 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
229 mem.input_name = "-";
230 else
231 mem.input_name = "perf.data";
232 }
233
234 if (!strncmp(argv[0], "rec", 3))
235 return __cmd_record(argc, argv);
236 else if (!strncmp(argv[0], "rep", 3))
237 return report_events(argc, argv, &mem);
238 else
239 usage_with_options(mem_usage, mem_options);
240
241 return 0;
242}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index de38a034b129..e8a66f9a6715 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -37,7 +37,7 @@
37#include "util/strfilter.h" 37#include "util/strfilter.h"
38#include "util/symbol.h" 38#include "util/symbol.h"
39#include "util/debug.h" 39#include "util/debug.h"
40#include "util/debugfs.h" 40#include <lk/debugfs.h>
41#include "util/parse-options.h" 41#include "util/parse-options.h"
42#include "util/probe-finder.h" 42#include "util/probe-finder.h"
43#include "util/probe-event.h" 43#include "util/probe-event.h"
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f3151d3c70ce..fff985cf3852 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -5,8 +5,6 @@
5 * (or a CPU, or a PID) into the perf.data output file - for 5 * (or a CPU, or a PID) into the perf.data output file - for
6 * later analysis via perf report. 6 * later analysis via perf report.
7 */ 7 */
8#define _FILE_OFFSET_BITS 64
9
10#include "builtin.h" 8#include "builtin.h"
11 9
12#include "perf.h" 10#include "perf.h"
@@ -200,7 +198,6 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
200 return; 198 return;
201 199
202 signal(signr, SIG_DFL); 200 signal(signr, SIG_DFL);
203 kill(getpid(), signr);
204} 201}
205 202
206static bool perf_evlist__equal(struct perf_evlist *evlist, 203static bool perf_evlist__equal(struct perf_evlist *evlist,
@@ -224,130 +221,28 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
224 221
225static int perf_record__open(struct perf_record *rec) 222static int perf_record__open(struct perf_record *rec)
226{ 223{
224 char msg[512];
227 struct perf_evsel *pos; 225 struct perf_evsel *pos;
228 struct perf_evlist *evlist = rec->evlist; 226 struct perf_evlist *evlist = rec->evlist;
229 struct perf_session *session = rec->session; 227 struct perf_session *session = rec->session;
230 struct perf_record_opts *opts = &rec->opts; 228 struct perf_record_opts *opts = &rec->opts;
231 int rc = 0; 229 int rc = 0;
232 230
233 /* 231 perf_evlist__config(evlist, opts);
234 * Set the evsel leader links before we configure attributes,
235 * since some might depend on this info.
236 */
237 if (opts->group)
238 perf_evlist__set_leader(evlist);
239
240 perf_evlist__config_attrs(evlist, opts);
241 232
242 list_for_each_entry(pos, &evlist->entries, node) { 233 list_for_each_entry(pos, &evlist->entries, node) {
243 struct perf_event_attr *attr = &pos->attr;
244 /*
245 * Check if parse_single_tracepoint_event has already asked for
246 * PERF_SAMPLE_TIME.
247 *
248 * XXX this is kludgy but short term fix for problems introduced by
249 * eac23d1c that broke 'perf script' by having different sample_types
250 * when using multiple tracepoint events when we use a perf binary
251 * that tries to use sample_id_all on an older kernel.
252 *
253 * We need to move counter creation to perf_session, support
254 * different sample_types, etc.
255 */
256 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
257
258fallback_missing_features:
259 if (opts->exclude_guest_missing)
260 attr->exclude_guest = attr->exclude_host = 0;
261retry_sample_id:
262 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
263try_again: 234try_again:
264 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 235 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
265 int err = errno; 236 if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
266
267 if (err == EPERM || err == EACCES) {
268 ui__error_paranoid();
269 rc = -err;
270 goto out;
271 } else if (err == ENODEV && opts->target.cpu_list) {
272 pr_err("No such device - did you specify"
273 " an out-of-range profile CPU?\n");
274 rc = -err;
275 goto out;
276 } else if (err == EINVAL) {
277 if (!opts->exclude_guest_missing &&
278 (attr->exclude_guest || attr->exclude_host)) {
279 pr_debug("Old kernel, cannot exclude "
280 "guest or host samples.\n");
281 opts->exclude_guest_missing = true;
282 goto fallback_missing_features;
283 } else if (!opts->sample_id_all_missing) {
284 /*
285 * Old kernel, no attr->sample_id_type_all field
286 */
287 opts->sample_id_all_missing = true;
288 if (!opts->sample_time && !opts->raw_samples && !time_needed)
289 attr->sample_type &= ~PERF_SAMPLE_TIME;
290
291 goto retry_sample_id;
292 }
293 }
294
295 /*
296 * If it's cycles then fall back to hrtimer
297 * based cpu-clock-tick sw counter, which
298 * is always available even if no PMU support.
299 *
300 * PPC returns ENXIO until 2.6.37 (behavior changed
301 * with commit b0a873e).
302 */
303 if ((err == ENOENT || err == ENXIO)
304 && attr->type == PERF_TYPE_HARDWARE
305 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
306
307 if (verbose) 237 if (verbose)
308 ui__warning("The cycles event is not supported, " 238 ui__warning("%s\n", msg);
309 "trying to fall back to cpu-clock-ticks\n");
310 attr->type = PERF_TYPE_SOFTWARE;
311 attr->config = PERF_COUNT_SW_CPU_CLOCK;
312 if (pos->name) {
313 free(pos->name);
314 pos->name = NULL;
315 }
316 goto try_again; 239 goto try_again;
317 } 240 }
318 241
319 if (err == ENOENT) { 242 rc = -errno;
320 ui__error("The %s event is not supported.\n", 243 perf_evsel__open_strerror(pos, &opts->target,
321 perf_evsel__name(pos)); 244 errno, msg, sizeof(msg));
322 rc = -err; 245 ui__error("%s\n", msg);
323 goto out;
324 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
325 ui__error("\'precise\' request may not be supported. "
326 "Try removing 'p' modifier\n");
327 rc = -err;
328 goto out;
329 }
330
331 printf("\n");
332 error("sys_perf_event_open() syscall returned with %d "
333 "(%s) for event %s. /bin/dmesg may provide "
334 "additional information.\n",
335 err, strerror(err), perf_evsel__name(pos));
336
337#if defined(__i386__) || defined(__x86_64__)
338 if (attr->type == PERF_TYPE_HARDWARE &&
339 err == EOPNOTSUPP) {
340 pr_err("No hardware sampling interrupt available."
341 " No APIC? If so then you can boot the kernel"
342 " with the \"lapic\" boot parameter to"
343 " force-enable it.\n");
344 rc = -err;
345 goto out;
346 }
347#endif
348
349 pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
350 rc = -err;
351 goto out; 246 goto out;
352 } 247 }
353 } 248 }
@@ -430,10 +325,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
430{ 325{
431 int err; 326 int err;
432 struct perf_tool *tool = data; 327 struct perf_tool *tool = data;
433
434 if (machine__is_host(machine))
435 return;
436
437 /* 328 /*
438 *As for guest kernel when processing subcommand record&report, 329 *As for guest kernel when processing subcommand record&report,
439 *we arrange module mmap prior to guest kernel mmap and trigger 330 *we arrange module mmap prior to guest kernel mmap and trigger
@@ -512,6 +403,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
512 signal(SIGCHLD, sig_handler); 403 signal(SIGCHLD, sig_handler);
513 signal(SIGINT, sig_handler); 404 signal(SIGINT, sig_handler);
514 signal(SIGUSR1, sig_handler); 405 signal(SIGUSR1, sig_handler);
406 signal(SIGTERM, sig_handler);
515 407
516 if (!output_name) { 408 if (!output_name) {
517 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) 409 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
@@ -580,7 +472,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
580 } 472 }
581 473
582 if (forks) { 474 if (forks) {
583 err = perf_evlist__prepare_workload(evsel_list, opts, argv); 475 err = perf_evlist__prepare_workload(evsel_list, &opts->target,
476 argv, opts->pipe_output,
477 true);
584 if (err < 0) { 478 if (err < 0) {
585 pr_err("Couldn't run the workload!\n"); 479 pr_err("Couldn't run the workload!\n");
586 goto out_delete_session; 480 goto out_delete_session;
@@ -592,6 +486,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
592 goto out_delete_session; 486 goto out_delete_session;
593 } 487 }
594 488
489 if (!evsel_list->nr_groups)
490 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
491
595 /* 492 /*
596 * perf_session__delete(session) will be called at perf_record__exit() 493 * perf_session__delete(session) will be called at perf_record__exit()
597 */ 494 */
@@ -618,12 +515,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
618 515
619 rec->post_processing_offset = lseek(output, 0, SEEK_CUR); 516 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
620 517
621 machine = perf_session__find_host_machine(session); 518 machine = &session->machines.host;
622 if (!machine) {
623 pr_err("Couldn't find native kernel information.\n");
624 err = -1;
625 goto out_delete_session;
626 }
627 519
628 if (opts->pipe_output) { 520 if (opts->pipe_output) {
629 err = perf_event__synthesize_attrs(tool, session, 521 err = perf_event__synthesize_attrs(tool, session,
@@ -676,17 +568,20 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
676 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 568 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
677 "Check /proc/modules permission or run as root.\n"); 569 "Check /proc/modules permission or run as root.\n");
678 570
679 if (perf_guest) 571 if (perf_guest) {
680 perf_session__process_machines(session, tool, 572 machines__process_guests(&session->machines,
681 perf_event__synthesize_guest_os); 573 perf_event__synthesize_guest_os, tool);
574 }
682 575
683 if (!opts->target.system_wide) 576 if (perf_target__has_task(&opts->target))
684 err = perf_event__synthesize_thread_map(tool, evsel_list->threads, 577 err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
685 process_synthesized_event, 578 process_synthesized_event,
686 machine); 579 machine);
687 else 580 else if (perf_target__has_cpu(&opts->target))
688 err = perf_event__synthesize_threads(tool, process_synthesized_event, 581 err = perf_event__synthesize_threads(tool, process_synthesized_event,
689 machine); 582 machine);
583 else /* command specified */
584 err = 0;
690 585
691 if (err != 0) 586 if (err != 0)
692 goto out_delete_session; 587 goto out_delete_session;
@@ -875,11 +770,10 @@ static int get_stack_size(char *str, unsigned long *_size)
875} 770}
876#endif /* LIBUNWIND_SUPPORT */ 771#endif /* LIBUNWIND_SUPPORT */
877 772
878static int 773int record_parse_callchain_opt(const struct option *opt,
879parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, 774 const char *arg, int unset)
880 int unset)
881{ 775{
882 struct perf_record *rec = (struct perf_record *)opt->value; 776 struct perf_record_opts *opts = opt->value;
883 char *tok, *name, *saveptr = NULL; 777 char *tok, *name, *saveptr = NULL;
884 char *buf; 778 char *buf;
885 int ret = -1; 779 int ret = -1;
@@ -905,7 +799,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
905 /* Framepointer style */ 799 /* Framepointer style */
906 if (!strncmp(name, "fp", sizeof("fp"))) { 800 if (!strncmp(name, "fp", sizeof("fp"))) {
907 if (!strtok_r(NULL, ",", &saveptr)) { 801 if (!strtok_r(NULL, ",", &saveptr)) {
908 rec->opts.call_graph = CALLCHAIN_FP; 802 opts->call_graph = CALLCHAIN_FP;
909 ret = 0; 803 ret = 0;
910 } else 804 } else
911 pr_err("callchain: No more arguments " 805 pr_err("callchain: No more arguments "
@@ -918,20 +812,20 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
918 const unsigned long default_stack_dump_size = 8192; 812 const unsigned long default_stack_dump_size = 8192;
919 813
920 ret = 0; 814 ret = 0;
921 rec->opts.call_graph = CALLCHAIN_DWARF; 815 opts->call_graph = CALLCHAIN_DWARF;
922 rec->opts.stack_dump_size = default_stack_dump_size; 816 opts->stack_dump_size = default_stack_dump_size;
923 817
924 tok = strtok_r(NULL, ",", &saveptr); 818 tok = strtok_r(NULL, ",", &saveptr);
925 if (tok) { 819 if (tok) {
926 unsigned long size = 0; 820 unsigned long size = 0;
927 821
928 ret = get_stack_size(tok, &size); 822 ret = get_stack_size(tok, &size);
929 rec->opts.stack_dump_size = size; 823 opts->stack_dump_size = size;
930 } 824 }
931 825
932 if (!ret) 826 if (!ret)
933 pr_debug("callchain: stack dump size %d\n", 827 pr_debug("callchain: stack dump size %d\n",
934 rec->opts.stack_dump_size); 828 opts->stack_dump_size);
935#endif /* LIBUNWIND_SUPPORT */ 829#endif /* LIBUNWIND_SUPPORT */
936 } else { 830 } else {
937 pr_err("callchain: Unknown -g option " 831 pr_err("callchain: Unknown -g option "
@@ -944,7 +838,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
944 free(buf); 838 free(buf);
945 839
946 if (!ret) 840 if (!ret)
947 pr_debug("callchain: type %d\n", rec->opts.call_graph); 841 pr_debug("callchain: type %d\n", opts->call_graph);
948 842
949 return ret; 843 return ret;
950} 844}
@@ -982,9 +876,9 @@ static struct perf_record record = {
982#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " 876#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
983 877
984#ifdef LIBUNWIND_SUPPORT 878#ifdef LIBUNWIND_SUPPORT
985static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; 879const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
986#else 880#else
987static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; 881const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
988#endif 882#endif
989 883
990/* 884/*
@@ -1028,9 +922,9 @@ const struct option record_options[] = {
1028 "number of mmap data pages"), 922 "number of mmap data pages"),
1029 OPT_BOOLEAN(0, "group", &record.opts.group, 923 OPT_BOOLEAN(0, "group", &record.opts.group,
1030 "put the counters into a counter group"), 924 "put the counters into a counter group"),
1031 OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]", 925 OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
1032 callchain_help, &parse_callchain_opt, 926 "mode[,dump_size]", record_callchain_help,
1033 "fp"), 927 &record_parse_callchain_opt, "fp"),
1034 OPT_INCR('v', "verbose", &verbose, 928 OPT_INCR('v', "verbose", &verbose,
1035 "be more verbose (show counter open errors, etc)"), 929 "be more verbose (show counter open errors, etc)"),
1036 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 930 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
@@ -1059,6 +953,8 @@ const struct option record_options[] = {
1059 OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack, 953 OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1060 "branch filter mask", "branch stack filter modes", 954 "branch filter mask", "branch stack filter modes",
1061 parse_branch_stack), 955 parse_branch_stack),
956 OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
957 "sample by weight (on special events only)"),
1062 OPT_END() 958 OPT_END()
1063}; 959};
1064 960
@@ -1070,7 +966,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1070 struct perf_record *rec = &record; 966 struct perf_record *rec = &record;
1071 char errbuf[BUFSIZ]; 967 char errbuf[BUFSIZ];
1072 968
1073 evsel_list = perf_evlist__new(NULL, NULL); 969 evsel_list = perf_evlist__new();
1074 if (evsel_list == NULL) 970 if (evsel_list == NULL)
1075 return -ENOMEM; 971 return -ENOMEM;
1076 972
@@ -1132,7 +1028,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1132 ui__error("%s", errbuf); 1028 ui__error("%s", errbuf);
1133 1029
1134 err = -saved_errno; 1030 err = -saved_errno;
1135 goto out_free_fd; 1031 goto out_symbol_exit;
1136 } 1032 }
1137 1033
1138 err = -ENOMEM; 1034 err = -ENOMEM;
@@ -1163,6 +1059,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1163 } 1059 }
1164 1060
1165 err = __cmd_record(&record, argc, argv); 1061 err = __cmd_record(&record, argc, argv);
1062
1063 perf_evlist__munmap(evsel_list);
1064 perf_evlist__close(evsel_list);
1166out_free_fd: 1065out_free_fd:
1167 perf_evlist__delete_maps(evsel_list); 1066 perf_evlist__delete_maps(evsel_list);
1168out_symbol_exit: 1067out_symbol_exit:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index fc251005dd3d..ca98d34cd58b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -8,11 +8,11 @@
8#include "builtin.h" 8#include "builtin.h"
9 9
10#include "util/util.h" 10#include "util/util.h"
11#include "util/cache.h"
11 12
12#include "util/annotate.h" 13#include "util/annotate.h"
13#include "util/color.h" 14#include "util/color.h"
14#include <linux/list.h> 15#include <linux/list.h>
15#include "util/cache.h"
16#include <linux/rbtree.h> 16#include <linux/rbtree.h>
17#include "util/symbol.h" 17#include "util/symbol.h"
18#include "util/callchain.h" 18#include "util/callchain.h"
@@ -46,14 +46,124 @@ struct perf_report {
46 bool show_full_info; 46 bool show_full_info;
47 bool show_threads; 47 bool show_threads;
48 bool inverted_callchain; 48 bool inverted_callchain;
49 bool mem_mode;
49 struct perf_read_values show_threads_values; 50 struct perf_read_values show_threads_values;
50 const char *pretty_printing_style; 51 const char *pretty_printing_style;
51 symbol_filter_t annotate_init; 52 symbol_filter_t annotate_init;
52 const char *cpu_list; 53 const char *cpu_list;
53 const char *symbol_filter_str; 54 const char *symbol_filter_str;
55 float min_percent;
54 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 56 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
55}; 57};
56 58
59static int perf_report_config(const char *var, const char *value, void *cb)
60{
61 if (!strcmp(var, "report.group")) {
62 symbol_conf.event_group = perf_config_bool(var, value);
63 return 0;
64 }
65 if (!strcmp(var, "report.percent-limit")) {
66 struct perf_report *rep = cb;
67 rep->min_percent = strtof(value, NULL);
68 return 0;
69 }
70
71 return perf_default_config(var, value, cb);
72}
73
74static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
75 struct addr_location *al,
76 struct perf_sample *sample,
77 struct perf_evsel *evsel,
78 struct machine *machine,
79 union perf_event *event)
80{
81 struct perf_report *rep = container_of(tool, struct perf_report, tool);
82 struct symbol *parent = NULL;
83 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
84 int err = 0;
85 struct hist_entry *he;
86 struct mem_info *mi, *mx;
87 uint64_t cost;
88
89 if ((sort__has_parent || symbol_conf.use_callchain) &&
90 sample->callchain) {
91 err = machine__resolve_callchain(machine, evsel, al->thread,
92 sample, &parent);
93 if (err)
94 return err;
95 }
96
97 mi = machine__resolve_mem(machine, al->thread, sample, cpumode);
98 if (!mi)
99 return -ENOMEM;
100
101 if (rep->hide_unresolved && !al->sym)
102 return 0;
103
104 cost = sample->weight;
105 if (!cost)
106 cost = 1;
107
108 /*
109 * must pass period=weight in order to get the correct
110 * sorting from hists__collapse_resort() which is solely
111 * based on periods. We want sorting be done on nr_events * weight
112 * and this is indirectly achieved by passing period=weight here
113 * and the he_stat__add_period() function.
114 */
115 he = __hists__add_mem_entry(&evsel->hists, al, parent, mi, cost, cost);
116 if (!he)
117 return -ENOMEM;
118
119 /*
120 * In the TUI browser, we are doing integrated annotation,
121 * so we don't allocate the extra space needed because the stdio
122 * code will not use it.
123 */
124 if (sort__has_sym && he->ms.sym && use_browser > 0) {
125 struct annotation *notes = symbol__annotation(he->ms.sym);
126
127 assert(evsel != NULL);
128
129 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
130 goto out;
131
132 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
133 if (err)
134 goto out;
135 }
136
137 if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) {
138 struct annotation *notes;
139
140 mx = he->mem_info;
141
142 notes = symbol__annotation(mx->daddr.sym);
143 if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0)
144 goto out;
145
146 err = symbol__inc_addr_samples(mx->daddr.sym,
147 mx->daddr.map,
148 evsel->idx,
149 mx->daddr.al_addr);
150 if (err)
151 goto out;
152 }
153
154 evsel->hists.stats.total_period += cost;
155 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
156 err = 0;
157
158 if (symbol_conf.use_callchain) {
159 err = callchain_append(he->callchain,
160 &callchain_cursor,
161 sample->period);
162 }
163out:
164 return err;
165}
166
57static int perf_report__add_branch_hist_entry(struct perf_tool *tool, 167static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
58 struct addr_location *al, 168 struct addr_location *al,
59 struct perf_sample *sample, 169 struct perf_sample *sample,
@@ -83,15 +193,17 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
83 for (i = 0; i < sample->branch_stack->nr; i++) { 193 for (i = 0; i < sample->branch_stack->nr; i++) {
84 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) 194 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
85 continue; 195 continue;
196
197 err = -ENOMEM;
198
86 /* 199 /*
87 * The report shows the percentage of total branches captured 200 * The report shows the percentage of total branches captured
88 * and not events sampled. Thus we use a pseudo period of 1. 201 * and not events sampled. Thus we use a pseudo period of 1.
89 */ 202 */
90 he = __hists__add_branch_entry(&evsel->hists, al, parent, 203 he = __hists__add_branch_entry(&evsel->hists, al, parent,
91 &bi[i], 1); 204 &bi[i], 1, 1);
92 if (he) { 205 if (he) {
93 struct annotation *notes; 206 struct annotation *notes;
94 err = -ENOMEM;
95 bx = he->branch_info; 207 bx = he->branch_info;
96 if (bx->from.sym && use_browser == 1 && sort__has_sym) { 208 if (bx->from.sym && use_browser == 1 && sort__has_sym) {
97 notes = symbol__annotation(bx->from.sym); 209 notes = symbol__annotation(bx->from.sym);
@@ -122,11 +234,12 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
122 } 234 }
123 evsel->hists.stats.total_period += 1; 235 evsel->hists.stats.total_period += 1;
124 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 236 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
125 err = 0;
126 } else 237 } else
127 return -ENOMEM; 238 goto out;
128 } 239 }
240 err = 0;
129out: 241out:
242 free(bi);
130 return err; 243 return err;
131} 244}
132 245
@@ -146,7 +259,8 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
146 return err; 259 return err;
147 } 260 }
148 261
149 he = __hists__add_entry(&evsel->hists, al, parent, sample->period); 262 he = __hists__add_entry(&evsel->hists, al, parent, sample->period,
263 sample->weight);
150 if (he == NULL) 264 if (he == NULL)
151 return -ENOMEM; 265 return -ENOMEM;
152 266
@@ -158,7 +272,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
158 return err; 272 return err;
159 } 273 }
160 /* 274 /*
161 * Only in the newt browser we are doing integrated annotation, 275 * Only in the TUI browser we are doing integrated annotation,
162 * so we don't allocated the extra space needed because the stdio 276 * so we don't allocated the extra space needed because the stdio
163 * code will not use it. 277 * code will not use it.
164 */ 278 */
@@ -189,6 +303,7 @@ static int process_sample_event(struct perf_tool *tool,
189{ 303{
190 struct perf_report *rep = container_of(tool, struct perf_report, tool); 304 struct perf_report *rep = container_of(tool, struct perf_report, tool);
191 struct addr_location al; 305 struct addr_location al;
306 int ret;
192 307
193 if (perf_event__preprocess_sample(event, machine, &al, sample, 308 if (perf_event__preprocess_sample(event, machine, &al, sample,
194 rep->annotate_init) < 0) { 309 rep->annotate_init) < 0) {
@@ -203,22 +318,25 @@ static int process_sample_event(struct perf_tool *tool,
203 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 318 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
204 return 0; 319 return 0;
205 320
206 if (sort__branch_mode == 1) { 321 if (sort__mode == SORT_MODE__BRANCH) {
207 if (perf_report__add_branch_hist_entry(tool, &al, sample, 322 ret = perf_report__add_branch_hist_entry(tool, &al, sample,
208 evsel, machine)) { 323 evsel, machine);
324 if (ret < 0)
209 pr_debug("problem adding lbr entry, skipping event\n"); 325 pr_debug("problem adding lbr entry, skipping event\n");
210 return -1; 326 } else if (rep->mem_mode == 1) {
211 } 327 ret = perf_report__add_mem_hist_entry(tool, &al, sample,
328 evsel, machine, event);
329 if (ret < 0)
330 pr_debug("problem adding mem entry, skipping event\n");
212 } else { 331 } else {
213 if (al.map != NULL) 332 if (al.map != NULL)
214 al.map->dso->hit = 1; 333 al.map->dso->hit = 1;
215 334
216 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { 335 ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine);
336 if (ret < 0)
217 pr_debug("problem incrementing symbol period, skipping event\n"); 337 pr_debug("problem incrementing symbol period, skipping event\n");
218 return -1;
219 }
220 } 338 }
221 return 0; 339 return ret;
222} 340}
223 341
224static int process_read_event(struct perf_tool *tool, 342static int process_read_event(struct perf_tool *tool,
@@ -273,7 +391,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
273 } 391 }
274 } 392 }
275 393
276 if (sort__branch_mode == 1) { 394 if (sort__mode == SORT_MODE__BRANCH) {
277 if (!self->fd_pipe && 395 if (!self->fd_pipe &&
278 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { 396 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
279 ui__error("Selected -b but no branch data. " 397 ui__error("Selected -b but no branch data. "
@@ -292,20 +410,40 @@ static void sig_handler(int sig __maybe_unused)
292 session_done = 1; 410 session_done = 1;
293} 411}
294 412
295static size_t hists__fprintf_nr_sample_events(struct hists *self, 413static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
414 struct hists *self,
296 const char *evname, FILE *fp) 415 const char *evname, FILE *fp)
297{ 416{
298 size_t ret; 417 size_t ret;
299 char unit; 418 char unit;
300 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; 419 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
301 u64 nr_events = self->stats.total_period; 420 u64 nr_events = self->stats.total_period;
421 struct perf_evsel *evsel = hists_to_evsel(self);
422 char buf[512];
423 size_t size = sizeof(buf);
424
425 if (perf_evsel__is_group_event(evsel)) {
426 struct perf_evsel *pos;
427
428 perf_evsel__group_desc(evsel, buf, size);
429 evname = buf;
430
431 for_each_group_member(pos, evsel) {
432 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
433 nr_events += pos->hists.stats.total_period;
434 }
435 }
302 436
303 nr_samples = convert_unit(nr_samples, &unit); 437 nr_samples = convert_unit(nr_samples, &unit);
304 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit); 438 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
305 if (evname != NULL) 439 if (evname != NULL)
306 ret += fprintf(fp, " of event '%s'", evname); 440 ret += fprintf(fp, " of event '%s'", evname);
307 441
308 ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events); 442 if (rep->mem_mode) {
443 ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
444 ret += fprintf(fp, "\n# Sort order : %s", sort_order);
445 } else
446 ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
309 return ret + fprintf(fp, "\n#\n"); 447 return ret + fprintf(fp, "\n#\n");
310} 448}
311 449
@@ -319,8 +457,12 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
319 struct hists *hists = &pos->hists; 457 struct hists *hists = &pos->hists;
320 const char *evname = perf_evsel__name(pos); 458 const char *evname = perf_evsel__name(pos);
321 459
322 hists__fprintf_nr_sample_events(hists, evname, stdout); 460 if (symbol_conf.event_group &&
323 hists__fprintf(hists, true, 0, 0, stdout); 461 !perf_evsel__is_group_leader(pos))
462 continue;
463
464 hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
465 hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
324 fprintf(stdout, "\n\n"); 466 fprintf(stdout, "\n\n");
325 } 467 }
326 468
@@ -372,7 +514,7 @@ static int __cmd_report(struct perf_report *rep)
372 if (ret) 514 if (ret)
373 goto out_delete; 515 goto out_delete;
374 516
375 kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION]; 517 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
376 kernel_kmap = map__kmap(kernel_map); 518 kernel_kmap = map__kmap(kernel_map);
377 if (kernel_map == NULL || 519 if (kernel_map == NULL ||
378 (kernel_map->dso->hit && 520 (kernel_map->dso->hit &&
@@ -416,8 +558,16 @@ static int __cmd_report(struct perf_report *rep)
416 hists->symbol_filter_str = rep->symbol_filter_str; 558 hists->symbol_filter_str = rep->symbol_filter_str;
417 559
418 hists__collapse_resort(hists); 560 hists__collapse_resort(hists);
419 hists__output_resort(hists);
420 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; 561 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
562
563 /* Non-group events are considered as leader */
564 if (symbol_conf.event_group &&
565 !perf_evsel__is_group_leader(pos)) {
566 struct hists *leader_hists = &pos->leader->hists;
567
568 hists__match(leader_hists, hists);
569 hists__link(leader_hists, hists);
570 }
421 } 571 }
422 572
423 if (nr_samples == 0) { 573 if (nr_samples == 0) {
@@ -425,14 +575,25 @@ static int __cmd_report(struct perf_report *rep)
425 goto out_delete; 575 goto out_delete;
426 } 576 }
427 577
578 list_for_each_entry(pos, &session->evlist->entries, node)
579 hists__output_resort(&pos->hists);
580
428 if (use_browser > 0) { 581 if (use_browser > 0) {
429 if (use_browser == 1) { 582 if (use_browser == 1) {
430 perf_evlist__tui_browse_hists(session->evlist, help, 583 ret = perf_evlist__tui_browse_hists(session->evlist,
431 NULL, 584 help, NULL,
432 &session->header.env); 585 rep->min_percent,
586 &session->header.env);
587 /*
588 * Usually "ret" is the last pressed key, and we only
589 * care if the key notifies us to switch data file.
590 */
591 if (ret != K_SWITCH_INPUT_DATA)
592 ret = 0;
593
433 } else if (use_browser == 2) { 594 } else if (use_browser == 2) {
434 perf_evlist__gtk_browse_hists(session->evlist, help, 595 perf_evlist__gtk_browse_hists(session->evlist, help,
435 NULL); 596 NULL, rep->min_percent);
436 } 597 }
437 } else 598 } else
438 perf_evlist__tty_browse_hists(session->evlist, rep, help); 599 perf_evlist__tty_browse_hists(session->evlist, rep, help);
@@ -537,7 +698,19 @@ static int
537parse_branch_mode(const struct option *opt __maybe_unused, 698parse_branch_mode(const struct option *opt __maybe_unused,
538 const char *str __maybe_unused, int unset) 699 const char *str __maybe_unused, int unset)
539{ 700{
540 sort__branch_mode = !unset; 701 int *branch_mode = opt->value;
702
703 *branch_mode = !unset;
704 return 0;
705}
706
707static int
708parse_percent_limit(const struct option *opt, const char *str,
709 int unset __maybe_unused)
710{
711 struct perf_report *rep = opt->value;
712
713 rep->min_percent = strtof(str, NULL);
541 return 0; 714 return 0;
542} 715}
543 716
@@ -546,6 +719,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
546 struct perf_session *session; 719 struct perf_session *session;
547 struct stat st; 720 struct stat st;
548 bool has_br_stack = false; 721 bool has_br_stack = false;
722 int branch_mode = -1;
549 int ret = -1; 723 int ret = -1;
550 char callchain_default_opt[] = "fractal,0.5,callee"; 724 char callchain_default_opt[] = "fractal,0.5,callee";
551 const char * const report_usage[] = { 725 const char * const report_usage[] = {
@@ -595,8 +769,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
595 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 769 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
596 "Use the stdio interface"), 770 "Use the stdio interface"),
597 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 771 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
598 "sort by key(s): pid, comm, dso, symbol, parent, dso_to," 772 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
599 " dso_from, symbol_to, symbol_from, mispredict"), 773 " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
774 " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
775 "snoop, locked"),
600 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 776 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
601 "Show sample percentage for different cpu modes"), 777 "Show sample percentage for different cpu modes"),
602 OPT_STRING('p', "parent", &parent_pattern, "regex", 778 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -638,13 +814,22 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
638 "Specify disassembler style (e.g. -M intel for intel syntax)"), 814 "Specify disassembler style (e.g. -M intel for intel syntax)"),
639 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 815 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
640 "Show a column with the sum of periods"), 816 "Show a column with the sum of periods"),
641 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "", 817 OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
818 "Show event group information together"),
819 OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
642 "use branch records for histogram filling", parse_branch_mode), 820 "use branch records for histogram filling", parse_branch_mode),
643 OPT_STRING(0, "objdump", &objdump_path, "path", 821 OPT_STRING(0, "objdump", &objdump_path, "path",
644 "objdump binary to use for disassembly and annotations"), 822 "objdump binary to use for disassembly and annotations"),
823 OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
824 "Disable symbol demangling"),
825 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
826 OPT_CALLBACK(0, "percent-limit", &report, "percent",
827 "Don't show entries under that percent", parse_percent_limit),
645 OPT_END() 828 OPT_END()
646 }; 829 };
647 830
831 perf_config(perf_report_config, &report);
832
648 argc = parse_options(argc, argv, options, report_usage, 0); 833 argc = parse_options(argc, argv, options, report_usage, 0);
649 834
650 if (report.use_stdio) 835 if (report.use_stdio)
@@ -663,6 +848,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
663 else 848 else
664 input_name = "perf.data"; 849 input_name = "perf.data";
665 } 850 }
851
852 if (strcmp(input_name, "-") != 0)
853 setup_browser(true);
854 else {
855 use_browser = 0;
856 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
857 perf_hpp__init();
858 }
859
860repeat:
666 session = perf_session__new(input_name, O_RDONLY, 861 session = perf_session__new(input_name, O_RDONLY,
667 report.force, false, &report.tool); 862 report.force, false, &report.tool);
668 if (session == NULL) 863 if (session == NULL)
@@ -673,11 +868,11 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
673 has_br_stack = perf_header__has_feat(&session->header, 868 has_br_stack = perf_header__has_feat(&session->header,
674 HEADER_BRANCH_STACK); 869 HEADER_BRANCH_STACK);
675 870
676 if (sort__branch_mode == -1 && has_br_stack) 871 if (branch_mode == -1 && has_br_stack)
677 sort__branch_mode = 1; 872 sort__mode = SORT_MODE__BRANCH;
678 873
679 /* sort__branch_mode could be 0 if --no-branch-stack */ 874 /* sort__mode could be NORMAL if --no-branch-stack */
680 if (sort__branch_mode == 1) { 875 if (sort__mode == SORT_MODE__BRANCH) {
681 /* 876 /*
682 * if no sort_order is provided, then specify 877 * if no sort_order is provided, then specify
683 * branch-mode specific order 878 * branch-mode specific order
@@ -687,18 +882,26 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
687 "dso_to,symbol_to"; 882 "dso_to,symbol_to";
688 883
689 } 884 }
885 if (report.mem_mode) {
886 if (sort__mode == SORT_MODE__BRANCH) {
887 fprintf(stderr, "branch and mem mode incompatible\n");
888 goto error;
889 }
890 sort__mode = SORT_MODE__MEMORY;
690 891
691 if (strcmp(input_name, "-") != 0) 892 /*
692 setup_browser(true); 893 * if no sort_order is provided, then specify
693 else { 894 * branch-mode specific order
694 use_browser = 0; 895 */
695 perf_hpp__init(); 896 if (sort_order == default_sort_order)
897 sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
696 } 898 }
697 899
698 setup_sorting(report_usage, options); 900 if (setup_sorting() < 0)
901 usage_with_options(report_usage, options);
699 902
700 /* 903 /*
701 * Only in the newt browser we are doing integrated annotation, 904 * Only in the TUI browser we are doing integrated annotation,
702 * so don't allocate extra space that won't be used in the stdio 905 * so don't allocate extra space that won't be used in the stdio
703 * implementation. 906 * implementation.
704 */ 907 */
@@ -750,19 +953,15 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
750 report.symbol_filter_str = argv[0]; 953 report.symbol_filter_str = argv[0];
751 } 954 }
752 955
753 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 956 sort__setup_elide(stdout);
754
755 if (sort__branch_mode == 1) {
756 sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
757 sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
758 sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
759 sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
760 } else {
761 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
762 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
763 }
764 957
765 ret = __cmd_report(&report); 958 ret = __cmd_report(&report);
959 if (ret == K_SWITCH_INPUT_DATA) {
960 perf_session__delete(session);
961 goto repeat;
962 } else
963 ret = 0;
964
766error: 965error:
767 perf_session__delete(session); 966 perf_session__delete(session);
768 return ret; 967 return ret;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index cc28b85dabd5..2da2a6ca22bf 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1475,9 +1475,9 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1475 goto out_delete; 1475 goto out_delete;
1476 } 1476 }
1477 1477
1478 sched->nr_events = session->hists.stats.nr_events[0]; 1478 sched->nr_events = session->stats.nr_events[0];
1479 sched->nr_lost_events = session->hists.stats.total_lost; 1479 sched->nr_lost_events = session->stats.total_lost;
1480 sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; 1480 sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
1481 } 1481 }
1482 1482
1483 if (destroy) 1483 if (destroy)
@@ -1671,7 +1671,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1671 .sample = perf_sched__process_tracepoint_sample, 1671 .sample = perf_sched__process_tracepoint_sample,
1672 .comm = perf_event__process_comm, 1672 .comm = perf_event__process_comm,
1673 .lost = perf_event__process_lost, 1673 .lost = perf_event__process_lost,
1674 .exit = perf_event__process_exit,
1675 .fork = perf_event__process_fork, 1674 .fork = perf_event__process_fork,
1676 .ordered_samples = true, 1675 .ordered_samples = true,
1677 }, 1676 },
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b363e7b292b2..92d4658f56fb 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -692,7 +692,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
692 const char *arg, int unset __maybe_unused) 692 const char *arg, int unset __maybe_unused)
693{ 693{
694 char *tok; 694 char *tok;
695 int i, imax = sizeof(all_output_options) / sizeof(struct output_option); 695 int i, imax = ARRAY_SIZE(all_output_options);
696 int j; 696 int j;
697 int rc = 0; 697 int rc = 0;
698 char *str = strdup(arg); 698 char *str = strdup(arg);
@@ -909,18 +909,6 @@ static const char *ends_with(const char *str, const char *suffix)
909 return NULL; 909 return NULL;
910} 910}
911 911
912static char *ltrim(char *str)
913{
914 int len = strlen(str);
915
916 while (len && isspace(*str)) {
917 len--;
918 str++;
919 }
920
921 return str;
922}
923
924static int read_script_info(struct script_desc *desc, const char *filename) 912static int read_script_info(struct script_desc *desc, const char *filename)
925{ 913{
926 char line[BUFSIZ], *p; 914 char line[BUFSIZ], *p;
@@ -1487,7 +1475,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1487 return -1; 1475 return -1;
1488 } 1476 }
1489 1477
1490 perf_session__fprintf_info(session, stdout, show_full_info); 1478 if (!script_name && !generate_script_lang)
1479 perf_session__fprintf_info(session, stdout, show_full_info);
1491 1480
1492 if (!no_callchain) 1481 if (!no_callchain)
1493 symbol_conf.use_callchain = true; 1482 symbol_conf.use_callchain = true;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c247faca7127..7e910bab1097 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -65,16 +65,28 @@
65#define CNTR_NOT_SUPPORTED "<not supported>" 65#define CNTR_NOT_SUPPORTED "<not supported>"
66#define CNTR_NOT_COUNTED "<not counted>" 66#define CNTR_NOT_COUNTED "<not counted>"
67 67
68static void print_stat(int argc, const char **argv);
69static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
70static void print_counter(struct perf_evsel *counter, char *prefix);
71static void print_aggr(char *prefix);
72
68static struct perf_evlist *evsel_list; 73static struct perf_evlist *evsel_list;
69 74
70static struct perf_target target = { 75static struct perf_target target = {
71 .uid = UINT_MAX, 76 .uid = UINT_MAX,
72}; 77};
73 78
79enum aggr_mode {
80 AGGR_NONE,
81 AGGR_GLOBAL,
82 AGGR_SOCKET,
83 AGGR_CORE,
84};
85
74static int run_count = 1; 86static int run_count = 1;
75static bool no_inherit = false; 87static bool no_inherit = false;
76static bool scale = true; 88static bool scale = true;
77static bool no_aggr = false; 89static enum aggr_mode aggr_mode = AGGR_GLOBAL;
78static pid_t child_pid = -1; 90static pid_t child_pid = -1;
79static bool null_run = false; 91static bool null_run = false;
80static int detailed_run = 0; 92static int detailed_run = 0;
@@ -87,6 +99,11 @@ static FILE *output = NULL;
87static const char *pre_cmd = NULL; 99static const char *pre_cmd = NULL;
88static const char *post_cmd = NULL; 100static const char *post_cmd = NULL;
89static bool sync_run = false; 101static bool sync_run = false;
102static unsigned int interval = 0;
103static bool forever = false;
104static struct timespec ref_time;
105static struct cpu_map *aggr_map;
106static int (*aggr_get_id)(struct cpu_map *m, int cpu);
90 107
91static volatile int done = 0; 108static volatile int done = 0;
92 109
@@ -94,6 +111,33 @@ struct perf_stat {
94 struct stats res_stats[3]; 111 struct stats res_stats[3];
95}; 112};
96 113
114static inline void diff_timespec(struct timespec *r, struct timespec *a,
115 struct timespec *b)
116{
117 r->tv_sec = a->tv_sec - b->tv_sec;
118 if (a->tv_nsec < b->tv_nsec) {
119 r->tv_nsec = a->tv_nsec + 1000000000L - b->tv_nsec;
120 r->tv_sec--;
121 } else {
122 r->tv_nsec = a->tv_nsec - b->tv_nsec ;
123 }
124}
125
126static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
127{
128 return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
129}
130
131static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
132{
133 return perf_evsel__cpus(evsel)->nr;
134}
135
136static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
137{
138 memset(evsel->priv, 0, sizeof(struct perf_stat));
139}
140
97static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 141static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
98{ 142{
99 evsel->priv = zalloc(sizeof(struct perf_stat)); 143 evsel->priv = zalloc(sizeof(struct perf_stat));
@@ -106,14 +150,56 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
106 evsel->priv = NULL; 150 evsel->priv = NULL;
107} 151}
108 152
109static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) 153static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
110{ 154{
111 return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; 155 void *addr;
156 size_t sz;
157
158 sz = sizeof(*evsel->counts) +
159 (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values));
160
161 addr = zalloc(sz);
162 if (!addr)
163 return -ENOMEM;
164
165 evsel->prev_raw_counts = addr;
166
167 return 0;
112} 168}
113 169
114static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) 170static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
115{ 171{
116 return perf_evsel__cpus(evsel)->nr; 172 free(evsel->prev_raw_counts);
173 evsel->prev_raw_counts = NULL;
174}
175
176static void perf_evlist__free_stats(struct perf_evlist *evlist)
177{
178 struct perf_evsel *evsel;
179
180 list_for_each_entry(evsel, &evlist->entries, node) {
181 perf_evsel__free_stat_priv(evsel);
182 perf_evsel__free_counts(evsel);
183 perf_evsel__free_prev_raw_counts(evsel);
184 }
185}
186
187static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
188{
189 struct perf_evsel *evsel;
190
191 list_for_each_entry(evsel, &evlist->entries, node) {
192 if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
193 perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 ||
194 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0))
195 goto out_free;
196 }
197
198 return 0;
199
200out_free:
201 perf_evlist__free_stats(evlist);
202 return -1;
117} 203}
118 204
119static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 205static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
@@ -129,11 +215,32 @@ static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
129static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 215static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
130static struct stats walltime_nsecs_stats; 216static struct stats walltime_nsecs_stats;
131 217
218static void perf_stat__reset_stats(struct perf_evlist *evlist)
219{
220 struct perf_evsel *evsel;
221
222 list_for_each_entry(evsel, &evlist->entries, node) {
223 perf_evsel__reset_stat_priv(evsel);
224 perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel));
225 }
226
227 memset(runtime_nsecs_stats, 0, sizeof(runtime_nsecs_stats));
228 memset(runtime_cycles_stats, 0, sizeof(runtime_cycles_stats));
229 memset(runtime_stalled_cycles_front_stats, 0, sizeof(runtime_stalled_cycles_front_stats));
230 memset(runtime_stalled_cycles_back_stats, 0, sizeof(runtime_stalled_cycles_back_stats));
231 memset(runtime_branches_stats, 0, sizeof(runtime_branches_stats));
232 memset(runtime_cacherefs_stats, 0, sizeof(runtime_cacherefs_stats));
233 memset(runtime_l1_dcache_stats, 0, sizeof(runtime_l1_dcache_stats));
234 memset(runtime_l1_icache_stats, 0, sizeof(runtime_l1_icache_stats));
235 memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats));
236 memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats));
237 memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats));
238 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
239}
240
132static int create_perf_stat_counter(struct perf_evsel *evsel) 241static int create_perf_stat_counter(struct perf_evsel *evsel)
133{ 242{
134 struct perf_event_attr *attr = &evsel->attr; 243 struct perf_event_attr *attr = &evsel->attr;
135 bool exclude_guest_missing = false;
136 int ret;
137 244
138 if (scale) 245 if (scale)
139 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 246 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -141,38 +248,16 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
141 248
142 attr->inherit = !no_inherit; 249 attr->inherit = !no_inherit;
143 250
144retry: 251 if (perf_target__has_cpu(&target))
145 if (exclude_guest_missing) 252 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
146 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
147
148 if (perf_target__has_cpu(&target)) {
149 ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
150 if (ret)
151 goto check_ret;
152 return 0;
153 }
154 253
155 if (!perf_target__has_task(&target) && 254 if (!perf_target__has_task(&target) &&
156 !perf_evsel__is_group_member(evsel)) { 255 perf_evsel__is_group_leader(evsel)) {
157 attr->disabled = 1; 256 attr->disabled = 1;
158 attr->enable_on_exec = 1; 257 attr->enable_on_exec = 1;
159 } 258 }
160 259
161 ret = perf_evsel__open_per_thread(evsel, evsel_list->threads); 260 return perf_evsel__open_per_thread(evsel, evsel_list->threads);
162 if (!ret)
163 return 0;
164 /* fall through */
165check_ret:
166 if (ret && errno == EINVAL) {
167 if (!exclude_guest_missing &&
168 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
169 pr_debug("Old kernel, cannot exclude "
170 "guest or host samples.\n");
171 exclude_guest_missing = true;
172 goto retry;
173 }
174 }
175 return ret;
176} 261}
177 262
178/* 263/*
@@ -229,7 +314,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
229 int i; 314 int i;
230 315
231 if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), 316 if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
232 evsel_list->threads->nr, scale) < 0) 317 thread_map__nr(evsel_list->threads), scale) < 0)
233 return -1; 318 return -1;
234 319
235 for (i = 0; i < 3; i++) 320 for (i = 0; i < 3; i++)
@@ -269,64 +354,91 @@ static int read_counter(struct perf_evsel *counter)
269 return 0; 354 return 0;
270} 355}
271 356
272static int __run_perf_stat(int argc __maybe_unused, const char **argv) 357static void print_interval(void)
273{ 358{
274 unsigned long long t0, t1; 359 static int num_print_interval;
275 struct perf_evsel *counter; 360 struct perf_evsel *counter;
276 int status = 0; 361 struct perf_stat *ps;
277 int child_ready_pipe[2], go_pipe[2]; 362 struct timespec ts, rs;
278 const bool forks = (argc > 0); 363 char prefix[64];
279 char buf;
280 364
281 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 365 if (aggr_mode == AGGR_GLOBAL) {
282 perror("failed to create pipes"); 366 list_for_each_entry(counter, &evsel_list->entries, node) {
283 return -1; 367 ps = counter->priv;
368 memset(ps->res_stats, 0, sizeof(ps->res_stats));
369 read_counter_aggr(counter);
370 }
371 } else {
372 list_for_each_entry(counter, &evsel_list->entries, node) {
373 ps = counter->priv;
374 memset(ps->res_stats, 0, sizeof(ps->res_stats));
375 read_counter(counter);
376 }
284 } 377 }
285 378
286 if (forks) { 379 clock_gettime(CLOCK_MONOTONIC, &ts);
287 if ((child_pid = fork()) < 0) 380 diff_timespec(&rs, &ts, &ref_time);
288 perror("failed to fork"); 381 sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);
382
383 if (num_print_interval == 0 && !csv_output) {
384 switch (aggr_mode) {
385 case AGGR_SOCKET:
386 fprintf(output, "# time socket cpus counts events\n");
387 break;
388 case AGGR_CORE:
389 fprintf(output, "# time core cpus counts events\n");
390 break;
391 case AGGR_NONE:
392 fprintf(output, "# time CPU counts events\n");
393 break;
394 case AGGR_GLOBAL:
395 default:
396 fprintf(output, "# time counts events\n");
397 }
398 }
289 399
290 if (!child_pid) { 400 if (++num_print_interval == 25)
291 close(child_ready_pipe[0]); 401 num_print_interval = 0;
292 close(go_pipe[1]);
293 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
294 402
295 /* 403 switch (aggr_mode) {
296 * Do a dummy execvp to get the PLT entry resolved, 404 case AGGR_CORE:
297 * so we avoid the resolver overhead on the real 405 case AGGR_SOCKET:
298 * execvp call. 406 print_aggr(prefix);
299 */ 407 break;
300 execvp("", (char **)argv); 408 case AGGR_NONE:
301 409 list_for_each_entry(counter, &evsel_list->entries, node)
302 /* 410 print_counter(counter, prefix);
303 * Tell the parent we're ready to go 411 break;
304 */ 412 case AGGR_GLOBAL:
305 close(child_ready_pipe[1]); 413 default:
414 list_for_each_entry(counter, &evsel_list->entries, node)
415 print_counter_aggr(counter, prefix);
416 }
417}
306 418
307 /* 419static int __run_perf_stat(int argc, const char **argv)
308 * Wait until the parent tells us to go. 420{
309 */ 421 char msg[512];
310 if (read(go_pipe[0], &buf, 1) == -1) 422 unsigned long long t0, t1;
311 perror("unable to read pipe"); 423 struct perf_evsel *counter;
424 struct timespec ts;
425 int status = 0;
426 const bool forks = (argc > 0);
312 427
313 execvp(argv[0], (char **)argv); 428 if (interval) {
429 ts.tv_sec = interval / 1000;
430 ts.tv_nsec = (interval % 1000) * 1000000;
431 } else {
432 ts.tv_sec = 1;
433 ts.tv_nsec = 0;
434 }
314 435
315 perror(argv[0]); 436 if (forks) {
316 exit(-1); 437 if (perf_evlist__prepare_workload(evsel_list, &target, argv,
438 false, false) < 0) {
439 perror("failed to prepare workload");
440 return -1;
317 } 441 }
318
319 if (perf_target__none(&target))
320 evsel_list->threads->map[0] = child_pid;
321
322 /*
323 * Wait for the child to be ready to exec.
324 */
325 close(child_ready_pipe[1]);
326 close(go_pipe[0]);
327 if (read(child_ready_pipe[0], &buf, 1) == -1)
328 perror("unable to read pipe");
329 close(child_ready_pipe[0]);
330 } 442 }
331 443
332 if (group) 444 if (group)
@@ -348,20 +460,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
348 continue; 460 continue;
349 } 461 }
350 462
351 if (errno == EPERM || errno == EACCES) { 463 perf_evsel__open_strerror(counter, &target,
352 error("You may not have permission to collect %sstats.\n" 464 errno, msg, sizeof(msg));
353 "\t Consider tweaking" 465 ui__error("%s\n", msg);
354 " /proc/sys/kernel/perf_event_paranoid or running as root.", 466
355 target.system_wide ? "system-wide " : "");
356 } else {
357 error("open_counter returned with %d (%s). "
358 "/bin/dmesg may provide additional information.\n",
359 errno, strerror(errno));
360 }
361 if (child_pid != -1) 467 if (child_pid != -1)
362 kill(child_pid, SIGTERM); 468 kill(child_pid, SIGTERM);
363 469
364 pr_err("Not all events could be opened.\n");
365 return -1; 470 return -1;
366 } 471 }
367 counter->supported = true; 472 counter->supported = true;
@@ -377,30 +482,42 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
377 * Enable counters and exec the command: 482 * Enable counters and exec the command:
378 */ 483 */
379 t0 = rdclock(); 484 t0 = rdclock();
485 clock_gettime(CLOCK_MONOTONIC, &ref_time);
380 486
381 if (forks) { 487 if (forks) {
382 close(go_pipe[1]); 488 perf_evlist__start_workload(evsel_list);
489
490 if (interval) {
491 while (!waitpid(child_pid, &status, WNOHANG)) {
492 nanosleep(&ts, NULL);
493 print_interval();
494 }
495 }
383 wait(&status); 496 wait(&status);
384 if (WIFSIGNALED(status)) 497 if (WIFSIGNALED(status))
385 psignal(WTERMSIG(status), argv[0]); 498 psignal(WTERMSIG(status), argv[0]);
386 } else { 499 } else {
387 while(!done) sleep(1); 500 while (!done) {
501 nanosleep(&ts, NULL);
502 if (interval)
503 print_interval();
504 }
388 } 505 }
389 506
390 t1 = rdclock(); 507 t1 = rdclock();
391 508
392 update_stats(&walltime_nsecs_stats, t1 - t0); 509 update_stats(&walltime_nsecs_stats, t1 - t0);
393 510
394 if (no_aggr) { 511 if (aggr_mode == AGGR_GLOBAL) {
395 list_for_each_entry(counter, &evsel_list->entries, node) { 512 list_for_each_entry(counter, &evsel_list->entries, node) {
396 read_counter(counter); 513 read_counter_aggr(counter);
397 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); 514 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
515 thread_map__nr(evsel_list->threads));
398 } 516 }
399 } else { 517 } else {
400 list_for_each_entry(counter, &evsel_list->entries, node) { 518 list_for_each_entry(counter, &evsel_list->entries, node) {
401 read_counter_aggr(counter); 519 read_counter(counter);
402 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 520 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
403 evsel_list->threads->nr);
404 } 521 }
405 } 522 }
406 523
@@ -454,23 +571,52 @@ static void print_noise(struct perf_evsel *evsel, double avg)
454 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); 571 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
455} 572}
456 573
457static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) 574static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
575{
576 switch (aggr_mode) {
577 case AGGR_CORE:
578 fprintf(output, "S%d-C%*d%s%*d%s",
579 cpu_map__id_to_socket(id),
580 csv_output ? 0 : -8,
581 cpu_map__id_to_cpu(id),
582 csv_sep,
583 csv_output ? 0 : 4,
584 nr,
585 csv_sep);
586 break;
587 case AGGR_SOCKET:
588 fprintf(output, "S%*d%s%*d%s",
589 csv_output ? 0 : -5,
590 id,
591 csv_sep,
592 csv_output ? 0 : 4,
593 nr,
594 csv_sep);
595 break;
596 case AGGR_NONE:
597 fprintf(output, "CPU%*d%s",
598 csv_output ? 0 : -4,
599 perf_evsel__cpus(evsel)->map[id], csv_sep);
600 break;
601 case AGGR_GLOBAL:
602 default:
603 break;
604 }
605}
606
607static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
458{ 608{
459 double msecs = avg / 1e6; 609 double msecs = avg / 1e6;
460 char cpustr[16] = { '\0', }; 610 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s";
461 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s";
462 611
463 if (no_aggr) 612 aggr_printout(evsel, cpu, nr);
464 sprintf(cpustr, "CPU%*d%s",
465 csv_output ? 0 : -4,
466 perf_evsel__cpus(evsel)->map[cpu], csv_sep);
467 613
468 fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); 614 fprintf(output, fmt, msecs, csv_sep, perf_evsel__name(evsel));
469 615
470 if (evsel->cgrp) 616 if (evsel->cgrp)
471 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 617 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
472 618
473 if (csv_output) 619 if (csv_output || interval)
474 return; 620 return;
475 621
476 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 622 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
@@ -659,37 +805,33 @@ static void print_ll_cache_misses(int cpu,
659 fprintf(output, " of all LL-cache hits "); 805 fprintf(output, " of all LL-cache hits ");
660} 806}
661 807
662static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 808static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
663{ 809{
664 double total, ratio = 0.0; 810 double total, ratio = 0.0;
665 char cpustr[16] = { '\0', };
666 const char *fmt; 811 const char *fmt;
667 812
668 if (csv_output) 813 if (csv_output)
669 fmt = "%s%.0f%s%s"; 814 fmt = "%.0f%s%s";
670 else if (big_num) 815 else if (big_num)
671 fmt = "%s%'18.0f%s%-25s"; 816 fmt = "%'18.0f%s%-25s";
672 else 817 else
673 fmt = "%s%18.0f%s%-25s"; 818 fmt = "%18.0f%s%-25s";
674 819
675 if (no_aggr) 820 aggr_printout(evsel, cpu, nr);
676 sprintf(cpustr, "CPU%*d%s", 821
677 csv_output ? 0 : -4, 822 if (aggr_mode == AGGR_GLOBAL)
678 perf_evsel__cpus(evsel)->map[cpu], csv_sep);
679 else
680 cpu = 0; 823 cpu = 0;
681 824
682 fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel)); 825 fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel));
683 826
684 if (evsel->cgrp) 827 if (evsel->cgrp)
685 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 828 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
686 829
687 if (csv_output) 830 if (csv_output || interval)
688 return; 831 return;
689 832
690 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { 833 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
691 total = avg_stats(&runtime_cycles_stats[cpu]); 834 total = avg_stats(&runtime_cycles_stats[cpu]);
692
693 if (total) 835 if (total)
694 ratio = avg / total; 836 ratio = avg / total;
695 837
@@ -779,16 +921,80 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
779 } 921 }
780} 922}
781 923
924static void print_aggr(char *prefix)
925{
926 struct perf_evsel *counter;
927 int cpu, s, s2, id, nr;
928 u64 ena, run, val;
929
930 if (!(aggr_map || aggr_get_id))
931 return;
932
933 for (s = 0; s < aggr_map->nr; s++) {
934 id = aggr_map->map[s];
935 list_for_each_entry(counter, &evsel_list->entries, node) {
936 val = ena = run = 0;
937 nr = 0;
938 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
939 s2 = aggr_get_id(evsel_list->cpus, cpu);
940 if (s2 != id)
941 continue;
942 val += counter->counts->cpu[cpu].val;
943 ena += counter->counts->cpu[cpu].ena;
944 run += counter->counts->cpu[cpu].run;
945 nr++;
946 }
947 if (prefix)
948 fprintf(output, "%s", prefix);
949
950 if (run == 0 || ena == 0) {
951 aggr_printout(counter, cpu, nr);
952
953 fprintf(output, "%*s%s%*s",
954 csv_output ? 0 : 18,
955 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
956 csv_sep,
957 csv_output ? 0 : -24,
958 perf_evsel__name(counter));
959
960 if (counter->cgrp)
961 fprintf(output, "%s%s",
962 csv_sep, counter->cgrp->name);
963
964 fputc('\n', output);
965 continue;
966 }
967
968 if (nsec_counter(counter))
969 nsec_printout(id, nr, counter, val);
970 else
971 abs_printout(id, nr, counter, val);
972
973 if (!csv_output) {
974 print_noise(counter, 1.0);
975
976 if (run != ena)
977 fprintf(output, " (%.2f%%)",
978 100.0 * run / ena);
979 }
980 fputc('\n', output);
981 }
982 }
983}
984
782/* 985/*
783 * Print out the results of a single counter: 986 * Print out the results of a single counter:
784 * aggregated counts in system-wide mode 987 * aggregated counts in system-wide mode
785 */ 988 */
786static void print_counter_aggr(struct perf_evsel *counter) 989static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
787{ 990{
788 struct perf_stat *ps = counter->priv; 991 struct perf_stat *ps = counter->priv;
789 double avg = avg_stats(&ps->res_stats[0]); 992 double avg = avg_stats(&ps->res_stats[0]);
790 int scaled = counter->counts->scaled; 993 int scaled = counter->counts->scaled;
791 994
995 if (prefix)
996 fprintf(output, "%s", prefix);
997
792 if (scaled == -1) { 998 if (scaled == -1) {
793 fprintf(output, "%*s%s%*s", 999 fprintf(output, "%*s%s%*s",
794 csv_output ? 0 : 18, 1000 csv_output ? 0 : 18,
@@ -805,9 +1011,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
805 } 1011 }
806 1012
807 if (nsec_counter(counter)) 1013 if (nsec_counter(counter))
808 nsec_printout(-1, counter, avg); 1014 nsec_printout(-1, 0, counter, avg);
809 else 1015 else
810 abs_printout(-1, counter, avg); 1016 abs_printout(-1, 0, counter, avg);
811 1017
812 print_noise(counter, avg); 1018 print_noise(counter, avg);
813 1019
@@ -831,7 +1037,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
831 * Print out the results of a single counter: 1037 * Print out the results of a single counter:
832 * does not use aggregated count in system-wide 1038 * does not use aggregated count in system-wide
833 */ 1039 */
834static void print_counter(struct perf_evsel *counter) 1040static void print_counter(struct perf_evsel *counter, char *prefix)
835{ 1041{
836 u64 ena, run, val; 1042 u64 ena, run, val;
837 int cpu; 1043 int cpu;
@@ -840,6 +1046,10 @@ static void print_counter(struct perf_evsel *counter)
840 val = counter->counts->cpu[cpu].val; 1046 val = counter->counts->cpu[cpu].val;
841 ena = counter->counts->cpu[cpu].ena; 1047 ena = counter->counts->cpu[cpu].ena;
842 run = counter->counts->cpu[cpu].run; 1048 run = counter->counts->cpu[cpu].run;
1049
1050 if (prefix)
1051 fprintf(output, "%s", prefix);
1052
843 if (run == 0 || ena == 0) { 1053 if (run == 0 || ena == 0) {
844 fprintf(output, "CPU%*d%s%*s%s%*s", 1054 fprintf(output, "CPU%*d%s%*s%s%*s",
845 csv_output ? 0 : -4, 1055 csv_output ? 0 : -4,
@@ -859,9 +1069,9 @@ static void print_counter(struct perf_evsel *counter)
859 } 1069 }
860 1070
861 if (nsec_counter(counter)) 1071 if (nsec_counter(counter))
862 nsec_printout(cpu, counter, val); 1072 nsec_printout(cpu, 0, counter, val);
863 else 1073 else
864 abs_printout(cpu, counter, val); 1074 abs_printout(cpu, 0, counter, val);
865 1075
866 if (!csv_output) { 1076 if (!csv_output) {
867 print_noise(counter, 1.0); 1077 print_noise(counter, 1.0);
@@ -899,12 +1109,21 @@ static void print_stat(int argc, const char **argv)
899 fprintf(output, ":\n\n"); 1109 fprintf(output, ":\n\n");
900 } 1110 }
901 1111
902 if (no_aggr) { 1112 switch (aggr_mode) {
1113 case AGGR_CORE:
1114 case AGGR_SOCKET:
1115 print_aggr(NULL);
1116 break;
1117 case AGGR_GLOBAL:
903 list_for_each_entry(counter, &evsel_list->entries, node) 1118 list_for_each_entry(counter, &evsel_list->entries, node)
904 print_counter(counter); 1119 print_counter_aggr(counter, NULL);
905 } else { 1120 break;
1121 case AGGR_NONE:
906 list_for_each_entry(counter, &evsel_list->entries, node) 1122 list_for_each_entry(counter, &evsel_list->entries, node)
907 print_counter_aggr(counter); 1123 print_counter(counter, NULL);
1124 break;
1125 default:
1126 break;
908 } 1127 }
909 1128
910 if (!csv_output) { 1129 if (!csv_output) {
@@ -925,7 +1144,7 @@ static volatile int signr = -1;
925 1144
926static void skip_signal(int signo) 1145static void skip_signal(int signo)
927{ 1146{
928 if(child_pid == -1) 1147 if ((child_pid == -1) || interval)
929 done = 1; 1148 done = 1;
930 1149
931 signr = signo; 1150 signr = signo;
@@ -950,6 +1169,32 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,
950 return 0; 1169 return 0;
951} 1170}
952 1171
1172static int perf_stat_init_aggr_mode(void)
1173{
1174 switch (aggr_mode) {
1175 case AGGR_SOCKET:
1176 if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) {
1177 perror("cannot build socket map");
1178 return -1;
1179 }
1180 aggr_get_id = cpu_map__get_socket;
1181 break;
1182 case AGGR_CORE:
1183 if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) {
1184 perror("cannot build core map");
1185 return -1;
1186 }
1187 aggr_get_id = cpu_map__get_core;
1188 break;
1189 case AGGR_NONE:
1190 case AGGR_GLOBAL:
1191 default:
1192 break;
1193 }
1194 return 0;
1195}
1196
1197
953/* 1198/*
954 * Add default attributes, if there were no attributes specified or 1199 * Add default attributes, if there were no attributes specified or
955 * if -d/--detailed, -d -d or -d -d -d is used: 1200 * if -d/--detailed, -d -d or -d -d -d is used:
@@ -1120,7 +1365,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1120 OPT_INCR('v', "verbose", &verbose, 1365 OPT_INCR('v', "verbose", &verbose,
1121 "be more verbose (show counter open errors, etc)"), 1366 "be more verbose (show counter open errors, etc)"),
1122 OPT_INTEGER('r', "repeat", &run_count, 1367 OPT_INTEGER('r', "repeat", &run_count,
1123 "repeat command and print average + stddev (max: 100)"), 1368 "repeat command and print average + stddev (max: 100, forever: 0)"),
1124 OPT_BOOLEAN('n', "null", &null_run, 1369 OPT_BOOLEAN('n', "null", &null_run,
1125 "null run - dont start any counters"), 1370 "null run - dont start any counters"),
1126 OPT_INCR('d', "detailed", &detailed_run, 1371 OPT_INCR('d', "detailed", &detailed_run,
@@ -1132,7 +1377,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1132 stat__set_big_num), 1377 stat__set_big_num),
1133 OPT_STRING('C', "cpu", &target.cpu_list, "cpu", 1378 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
1134 "list of cpus to monitor in system-wide"), 1379 "list of cpus to monitor in system-wide"),
1135 OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), 1380 OPT_SET_UINT('A', "no-aggr", &aggr_mode,
1381 "disable CPU count aggregation", AGGR_NONE),
1136 OPT_STRING('x', "field-separator", &csv_sep, "separator", 1382 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1137 "print counts with custom separator"), 1383 "print counts with custom separator"),
1138 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1384 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
@@ -1145,19 +1391,24 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1145 "command to run prior to the measured command"), 1391 "command to run prior to the measured command"),
1146 OPT_STRING(0, "post", &post_cmd, "command", 1392 OPT_STRING(0, "post", &post_cmd, "command",
1147 "command to run after to the measured command"), 1393 "command to run after to the measured command"),
1394 OPT_UINTEGER('I', "interval-print", &interval,
1395 "print counts at regular interval in ms (>= 100)"),
1396 OPT_SET_UINT(0, "per-socket", &aggr_mode,
1397 "aggregate counts per processor socket", AGGR_SOCKET),
1398 OPT_SET_UINT(0, "per-core", &aggr_mode,
1399 "aggregate counts per physical processor core", AGGR_CORE),
1148 OPT_END() 1400 OPT_END()
1149 }; 1401 };
1150 const char * const stat_usage[] = { 1402 const char * const stat_usage[] = {
1151 "perf stat [<options>] [<command>]", 1403 "perf stat [<options>] [<command>]",
1152 NULL 1404 NULL
1153 }; 1405 };
1154 struct perf_evsel *pos;
1155 int status = -ENOMEM, run_idx; 1406 int status = -ENOMEM, run_idx;
1156 const char *mode; 1407 const char *mode;
1157 1408
1158 setlocale(LC_ALL, ""); 1409 setlocale(LC_ALL, "");
1159 1410
1160 evsel_list = perf_evlist__new(NULL, NULL); 1411 evsel_list = perf_evlist__new();
1161 if (evsel_list == NULL) 1412 if (evsel_list == NULL)
1162 return -ENOMEM; 1413 return -ENOMEM;
1163 1414
@@ -1220,15 +1471,21 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1220 1471
1221 if (!argc && !perf_target__has_task(&target)) 1472 if (!argc && !perf_target__has_task(&target))
1222 usage_with_options(stat_usage, options); 1473 usage_with_options(stat_usage, options);
1223 if (run_count <= 0) 1474 if (run_count < 0) {
1224 usage_with_options(stat_usage, options); 1475 usage_with_options(stat_usage, options);
1476 } else if (run_count == 0) {
1477 forever = true;
1478 run_count = 1;
1479 }
1225 1480
1226 /* no_aggr, cgroup are for system-wide only */ 1481 /* no_aggr, cgroup are for system-wide only */
1227 if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) { 1482 if ((aggr_mode != AGGR_GLOBAL || nr_cgroups)
1483 && !perf_target__has_cpu(&target)) {
1228 fprintf(stderr, "both cgroup and no-aggregation " 1484 fprintf(stderr, "both cgroup and no-aggregation "
1229 "modes only available in system-wide mode\n"); 1485 "modes only available in system-wide mode\n");
1230 1486
1231 usage_with_options(stat_usage, options); 1487 usage_with_options(stat_usage, options);
1488 return -1;
1232 } 1489 }
1233 1490
1234 if (add_default_attributes()) 1491 if (add_default_attributes())
@@ -1245,13 +1502,18 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1245 usage_with_options(stat_usage, options); 1502 usage_with_options(stat_usage, options);
1246 return -1; 1503 return -1;
1247 } 1504 }
1248 1505 if (interval && interval < 100) {
1249 list_for_each_entry(pos, &evsel_list->entries, node) { 1506 pr_err("print interval must be >= 100ms\n");
1250 if (perf_evsel__alloc_stat_priv(pos) < 0 || 1507 usage_with_options(stat_usage, options);
1251 perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) 1508 return -1;
1252 goto out_free_fd;
1253 } 1509 }
1254 1510
1511 if (perf_evlist__alloc_stats(evsel_list, interval))
1512 goto out_free_maps;
1513
1514 if (perf_stat_init_aggr_mode())
1515 goto out;
1516
1255 /* 1517 /*
1256 * We dont want to block the signals - that would cause 1518 * We dont want to block the signals - that would cause
1257 * child tasks to inherit that and Ctrl-C would not work. 1519 * child tasks to inherit that and Ctrl-C would not work.
@@ -1259,24 +1521,30 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1259 * task, but being ignored by perf stat itself: 1521 * task, but being ignored by perf stat itself:
1260 */ 1522 */
1261 atexit(sig_atexit); 1523 atexit(sig_atexit);
1262 signal(SIGINT, skip_signal); 1524 if (!forever)
1525 signal(SIGINT, skip_signal);
1526 signal(SIGCHLD, skip_signal);
1263 signal(SIGALRM, skip_signal); 1527 signal(SIGALRM, skip_signal);
1264 signal(SIGABRT, skip_signal); 1528 signal(SIGABRT, skip_signal);
1265 1529
1266 status = 0; 1530 status = 0;
1267 for (run_idx = 0; run_idx < run_count; run_idx++) { 1531 for (run_idx = 0; forever || run_idx < run_count; run_idx++) {
1268 if (run_count != 1 && verbose) 1532 if (run_count != 1 && verbose)
1269 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 1533 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
1270 run_idx + 1); 1534 run_idx + 1);
1271 1535
1272 status = run_perf_stat(argc, argv); 1536 status = run_perf_stat(argc, argv);
1537 if (forever && status != -1) {
1538 print_stat(argc, argv);
1539 perf_stat__reset_stats(evsel_list);
1540 }
1273 } 1541 }
1274 1542
1275 if (status != -1) 1543 if (!forever && status != -1 && !interval)
1276 print_stat(argc, argv); 1544 print_stat(argc, argv);
1277out_free_fd: 1545
1278 list_for_each_entry(pos, &evsel_list->entries, node) 1546 perf_evlist__free_stats(evsel_list);
1279 perf_evsel__free_stat_priv(pos); 1547out_free_maps:
1280 perf_evlist__delete_maps(evsel_list); 1548 perf_evlist__delete_maps(evsel_list);
1281out: 1549out:
1282 perf_evlist__delete(evsel_list); 1550 perf_evlist__delete(evsel_list);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c9ff3950cd4b..f036af9b6f09 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -68,32 +68,13 @@
68#include <linux/unistd.h> 68#include <linux/unistd.h>
69#include <linux/types.h> 69#include <linux/types.h>
70 70
71void get_term_dimensions(struct winsize *ws) 71static volatile int done;
72{ 72
73 char *s = getenv("LINES"); 73#define HEADER_LINE_NR 5
74
75 if (s != NULL) {
76 ws->ws_row = atoi(s);
77 s = getenv("COLUMNS");
78 if (s != NULL) {
79 ws->ws_col = atoi(s);
80 if (ws->ws_row && ws->ws_col)
81 return;
82 }
83 }
84#ifdef TIOCGWINSZ
85 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
86 ws->ws_row && ws->ws_col)
87 return;
88#endif
89 ws->ws_row = 25;
90 ws->ws_col = 80;
91}
92 74
93static void perf_top__update_print_entries(struct perf_top *top) 75static void perf_top__update_print_entries(struct perf_top *top)
94{ 76{
95 if (top->print_entries > 9) 77 top->print_entries = top->winsize.ws_row - HEADER_LINE_NR;
96 top->print_entries -= 9;
97} 78}
98 79
99static void perf_top__sig_winch(int sig __maybe_unused, 80static void perf_top__sig_winch(int sig __maybe_unused,
@@ -102,13 +83,6 @@ static void perf_top__sig_winch(int sig __maybe_unused,
102 struct perf_top *top = arg; 83 struct perf_top *top = arg;
103 84
104 get_term_dimensions(&top->winsize); 85 get_term_dimensions(&top->winsize);
105 if (!top->print_entries
106 || (top->print_entries+4) > top->winsize.ws_row) {
107 top->print_entries = top->winsize.ws_row;
108 } else {
109 top->print_entries += 4;
110 top->winsize.ws_row = top->print_entries;
111 }
112 perf_top__update_print_entries(top); 86 perf_top__update_print_entries(top);
113} 87}
114 88
@@ -251,7 +225,7 @@ static void perf_top__show_details(struct perf_top *top)
251 printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); 225 printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name);
252 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); 226 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
253 227
254 more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, 228 more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel,
255 0, top->sym_pcnt_filter, top->print_entries, 4); 229 0, top->sym_pcnt_filter, top->print_entries, 4);
256 if (top->zero) 230 if (top->zero)
257 symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); 231 symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx);
@@ -271,7 +245,11 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
271{ 245{
272 struct hist_entry *he; 246 struct hist_entry *he;
273 247
274 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period); 248 pthread_mutex_lock(&evsel->hists.lock);
249 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
250 sample->weight);
251 pthread_mutex_unlock(&evsel->hists.lock);
252
275 if (he == NULL) 253 if (he == NULL)
276 return NULL; 254 return NULL;
277 255
@@ -309,16 +287,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
309 return; 287 return;
310 } 288 }
311 289
312 hists__collapse_resort_threaded(&top->sym_evsel->hists); 290 hists__collapse_resort(&top->sym_evsel->hists);
313 hists__output_resort_threaded(&top->sym_evsel->hists); 291 hists__output_resort(&top->sym_evsel->hists);
314 hists__decay_entries_threaded(&top->sym_evsel->hists, 292 hists__decay_entries(&top->sym_evsel->hists,
315 top->hide_user_symbols, 293 top->hide_user_symbols,
316 top->hide_kernel_symbols); 294 top->hide_kernel_symbols);
317 hists__output_recalc_col_len(&top->sym_evsel->hists, 295 hists__output_recalc_col_len(&top->sym_evsel->hists,
318 top->winsize.ws_row - 3); 296 top->print_entries - printed);
319 putchar('\n'); 297 putchar('\n');
320 hists__fprintf(&top->sym_evsel->hists, false, 298 hists__fprintf(&top->sym_evsel->hists, false,
321 top->winsize.ws_row - 4 - printed, win_width, stdout); 299 top->print_entries - printed, win_width,
300 top->min_percent, stdout);
322} 301}
323 302
324static void prompt_integer(int *target, const char *msg) 303static void prompt_integer(int *target, const char *msg)
@@ -453,8 +432,10 @@ static int perf_top__key_mapped(struct perf_top *top, int c)
453 return 0; 432 return 0;
454} 433}
455 434
456static void perf_top__handle_keypress(struct perf_top *top, int c) 435static bool perf_top__handle_keypress(struct perf_top *top, int c)
457{ 436{
437 bool ret = true;
438
458 if (!perf_top__key_mapped(top, c)) { 439 if (!perf_top__key_mapped(top, c)) {
459 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 440 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
460 struct termios tc, save; 441 struct termios tc, save;
@@ -475,7 +456,7 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
475 456
476 tcsetattr(0, TCSAFLUSH, &save); 457 tcsetattr(0, TCSAFLUSH, &save);
477 if (!perf_top__key_mapped(top, c)) 458 if (!perf_top__key_mapped(top, c))
478 return; 459 return ret;
479 } 460 }
480 461
481 switch (c) { 462 switch (c) {
@@ -494,7 +475,6 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
494 perf_top__sig_winch(SIGWINCH, NULL, top); 475 perf_top__sig_winch(SIGWINCH, NULL, top);
495 sigaction(SIGWINCH, &act, NULL); 476 sigaction(SIGWINCH, &act, NULL);
496 } else { 477 } else {
497 perf_top__sig_winch(SIGWINCH, NULL, top);
498 signal(SIGWINCH, SIG_DFL); 478 signal(SIGWINCH, SIG_DFL);
499 } 479 }
500 break; 480 break;
@@ -537,7 +517,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
537 printf("exiting.\n"); 517 printf("exiting.\n");
538 if (top->dump_symtab) 518 if (top->dump_symtab)
539 perf_session__fprintf_dsos(top->session, stderr); 519 perf_session__fprintf_dsos(top->session, stderr);
540 exit(0); 520 ret = false;
521 break;
541 case 's': 522 case 's':
542 perf_top__prompt_symbol(top, "Enter details symbol"); 523 perf_top__prompt_symbol(top, "Enter details symbol");
543 break; 524 break;
@@ -560,6 +541,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
560 default: 541 default:
561 break; 542 break;
562 } 543 }
544
545 return ret;
563} 546}
564 547
565static void perf_top__sort_new_samples(void *arg) 548static void perf_top__sort_new_samples(void *arg)
@@ -570,11 +553,11 @@ static void perf_top__sort_new_samples(void *arg)
570 if (t->evlist->selected != NULL) 553 if (t->evlist->selected != NULL)
571 t->sym_evsel = t->evlist->selected; 554 t->sym_evsel = t->evlist->selected;
572 555
573 hists__collapse_resort_threaded(&t->sym_evsel->hists); 556 hists__collapse_resort(&t->sym_evsel->hists);
574 hists__output_resort_threaded(&t->sym_evsel->hists); 557 hists__output_resort(&t->sym_evsel->hists);
575 hists__decay_entries_threaded(&t->sym_evsel->hists, 558 hists__decay_entries(&t->sym_evsel->hists,
576 t->hide_user_symbols, 559 t->hide_user_symbols,
577 t->hide_kernel_symbols); 560 t->hide_kernel_symbols);
578} 561}
579 562
580static void *display_thread_tui(void *arg) 563static void *display_thread_tui(void *arg)
@@ -596,13 +579,12 @@ static void *display_thread_tui(void *arg)
596 * via --uid. 579 * via --uid.
597 */ 580 */
598 list_for_each_entry(pos, &top->evlist->entries, node) 581 list_for_each_entry(pos, &top->evlist->entries, node)
599 pos->hists.uid_filter_str = top->target.uid_str; 582 pos->hists.uid_filter_str = top->record_opts.target.uid_str;
600 583
601 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, 584 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
602 &top->session->header.env); 585 &top->session->header.env);
603 586
604 exit_browser(0); 587 done = 1;
605 exit(0);
606 return NULL; 588 return NULL;
607} 589}
608 590
@@ -626,7 +608,7 @@ repeat:
626 /* trash return*/ 608 /* trash return*/
627 getc(stdin); 609 getc(stdin);
628 610
629 while (1) { 611 while (!done) {
630 perf_top__print_sym_table(top); 612 perf_top__print_sym_table(top);
631 /* 613 /*
632 * Either timeout expired or we got an EINTR due to SIGWINCH, 614 * Either timeout expired or we got an EINTR due to SIGWINCH,
@@ -640,15 +622,14 @@ repeat:
640 continue; 622 continue;
641 /* Fall trhu */ 623 /* Fall trhu */
642 default: 624 default:
643 goto process_hotkey; 625 c = getc(stdin);
626 tcsetattr(0, TCSAFLUSH, &save);
627
628 if (perf_top__handle_keypress(top, c))
629 goto repeat;
630 done = 1;
644 } 631 }
645 } 632 }
646process_hotkey:
647 c = getc(stdin);
648 tcsetattr(0, TCSAFLUSH, &save);
649
650 perf_top__handle_keypress(top, c);
651 goto repeat;
652 633
653 return NULL; 634 return NULL;
654} 635}
@@ -716,7 +697,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
716 static struct intlist *seen; 697 static struct intlist *seen;
717 698
718 if (!seen) 699 if (!seen)
719 seen = intlist__new(); 700 seen = intlist__new(NULL);
720 701
721 if (!intlist__has_entry(seen, event->ip.pid)) { 702 if (!intlist__has_entry(seen, event->ip.pid)) {
722 pr_err("Can't find guest [%d]'s kernel information\n", 703 pr_err("Can't find guest [%d]'s kernel information\n",
@@ -727,8 +708,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
727 } 708 }
728 709
729 if (!machine) { 710 if (!machine) {
730 pr_err("%u unprocessable samples recorded.", 711 pr_err("%u unprocessable samples recorded.\r",
731 top->session->hists.stats.nr_unprocessable_samples++); 712 top->session->stats.nr_unprocessable_samples++);
732 return; 713 return;
733 } 714 }
734 715
@@ -810,7 +791,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
810 return; 791 return;
811 } 792 }
812 793
813 if (top->sort_has_symbols) 794 if (sort__has_sym)
814 perf_top__record_precise_ip(top, he, evsel->idx, ip); 795 perf_top__record_precise_ip(top, he, evsel->idx, ip);
815 } 796 }
816 797
@@ -847,13 +828,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
847 ++top->us_samples; 828 ++top->us_samples;
848 if (top->hide_user_symbols) 829 if (top->hide_user_symbols)
849 continue; 830 continue;
850 machine = perf_session__find_host_machine(session); 831 machine = &session->machines.host;
851 break; 832 break;
852 case PERF_RECORD_MISC_KERNEL: 833 case PERF_RECORD_MISC_KERNEL:
853 ++top->kernel_samples; 834 ++top->kernel_samples;
854 if (top->hide_kernel_symbols) 835 if (top->hide_kernel_symbols)
855 continue; 836 continue;
856 machine = perf_session__find_host_machine(session); 837 machine = &session->machines.host;
857 break; 838 break;
858 case PERF_RECORD_MISC_GUEST_KERNEL: 839 case PERF_RECORD_MISC_GUEST_KERNEL:
859 ++top->guest_kernel_samples; 840 ++top->guest_kernel_samples;
@@ -878,7 +859,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
878 hists__inc_nr_events(&evsel->hists, event->header.type); 859 hists__inc_nr_events(&evsel->hists, event->header.type);
879 machine__process_event(machine, event); 860 machine__process_event(machine, event);
880 } else 861 } else
881 ++session->hists.stats.nr_unknown_events; 862 ++session->stats.nr_unknown_events;
882 } 863 }
883} 864}
884 865
@@ -890,133 +871,52 @@ static void perf_top__mmap_read(struct perf_top *top)
890 perf_top__mmap_read_idx(top, i); 871 perf_top__mmap_read_idx(top, i);
891} 872}
892 873
893static void perf_top__start_counters(struct perf_top *top) 874static int perf_top__start_counters(struct perf_top *top)
894{ 875{
876 char msg[512];
895 struct perf_evsel *counter; 877 struct perf_evsel *counter;
896 struct perf_evlist *evlist = top->evlist; 878 struct perf_evlist *evlist = top->evlist;
879 struct perf_record_opts *opts = &top->record_opts;
897 880
898 if (top->group) 881 perf_evlist__config(evlist, opts);
899 perf_evlist__set_leader(evlist);
900 882
901 list_for_each_entry(counter, &evlist->entries, node) { 883 list_for_each_entry(counter, &evlist->entries, node) {
902 struct perf_event_attr *attr = &counter->attr;
903
904 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
905
906 if (top->freq) {
907 attr->sample_type |= PERF_SAMPLE_PERIOD;
908 attr->freq = 1;
909 attr->sample_freq = top->freq;
910 }
911
912 if (evlist->nr_entries > 1) {
913 attr->sample_type |= PERF_SAMPLE_ID;
914 attr->read_format |= PERF_FORMAT_ID;
915 }
916
917 if (perf_target__has_cpu(&top->target))
918 attr->sample_type |= PERF_SAMPLE_CPU;
919
920 if (symbol_conf.use_callchain)
921 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
922
923 attr->mmap = 1;
924 attr->comm = 1;
925 attr->inherit = top->inherit;
926fallback_missing_features:
927 if (top->exclude_guest_missing)
928 attr->exclude_guest = attr->exclude_host = 0;
929retry_sample_id:
930 attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
931try_again: 884try_again:
932 if (perf_evsel__open(counter, top->evlist->cpus, 885 if (perf_evsel__open(counter, top->evlist->cpus,
933 top->evlist->threads) < 0) { 886 top->evlist->threads) < 0) {
934 int err = errno; 887 if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) {
935
936 if (err == EPERM || err == EACCES) {
937 ui__error_paranoid();
938 goto out_err;
939 } else if (err == EINVAL) {
940 if (!top->exclude_guest_missing &&
941 (attr->exclude_guest || attr->exclude_host)) {
942 pr_debug("Old kernel, cannot exclude "
943 "guest or host samples.\n");
944 top->exclude_guest_missing = true;
945 goto fallback_missing_features;
946 } else if (!top->sample_id_all_missing) {
947 /*
948 * Old kernel, no attr->sample_id_type_all field
949 */
950 top->sample_id_all_missing = true;
951 goto retry_sample_id;
952 }
953 }
954 /*
955 * If it's cycles then fall back to hrtimer
956 * based cpu-clock-tick sw counter, which
957 * is always available even if no PMU support:
958 */
959 if ((err == ENOENT || err == ENXIO) &&
960 (attr->type == PERF_TYPE_HARDWARE) &&
961 (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
962
963 if (verbose) 888 if (verbose)
964 ui__warning("Cycles event not supported,\n" 889 ui__warning("%s\n", msg);
965 "trying to fall back to cpu-clock-ticks\n");
966
967 attr->type = PERF_TYPE_SOFTWARE;
968 attr->config = PERF_COUNT_SW_CPU_CLOCK;
969 if (counter->name) {
970 free(counter->name);
971 counter->name = NULL;
972 }
973 goto try_again; 890 goto try_again;
974 } 891 }
975 892
976 if (err == ENOENT) { 893 perf_evsel__open_strerror(counter, &opts->target,
977 ui__error("The %s event is not supported.\n", 894 errno, msg, sizeof(msg));
978 perf_evsel__name(counter)); 895 ui__error("%s\n", msg);
979 goto out_err;
980 } else if (err == EMFILE) {
981 ui__error("Too many events are opened.\n"
982 "Try again after reducing the number of events\n");
983 goto out_err;
984 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
985 ui__error("\'precise\' request may not be supported. "
986 "Try removing 'p' modifier\n");
987 goto out_err;
988 }
989
990 ui__error("The sys_perf_event_open() syscall "
991 "returned with %d (%s). /bin/dmesg "
992 "may provide additional information.\n"
993 "No CONFIG_PERF_EVENTS=y kernel support "
994 "configured?\n", err, strerror(err));
995 goto out_err; 896 goto out_err;
996 } 897 }
997 } 898 }
998 899
999 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { 900 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
1000 ui__error("Failed to mmap with %d (%s)\n", 901 ui__error("Failed to mmap with %d (%s)\n",
1001 errno, strerror(errno)); 902 errno, strerror(errno));
1002 goto out_err; 903 goto out_err;
1003 } 904 }
1004 905
1005 return; 906 return 0;
1006 907
1007out_err: 908out_err:
1008 exit_browser(0); 909 return -1;
1009 exit(0);
1010} 910}
1011 911
1012static int perf_top__setup_sample_type(struct perf_top *top) 912static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused)
1013{ 913{
1014 if (!top->sort_has_symbols) { 914 if (!sort__has_sym) {
1015 if (symbol_conf.use_callchain) { 915 if (symbol_conf.use_callchain) {
1016 ui__error("Selected -g but \"sym\" not present in --sort/-s."); 916 ui__error("Selected -g but \"sym\" not present in --sort/-s.");
1017 return -EINVAL; 917 return -EINVAL;
1018 } 918 }
1019 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { 919 } else if (callchain_param.mode != CHAIN_NONE) {
1020 if (callchain_register_param(&callchain_param) < 0) { 920 if (callchain_register_param(&callchain_param) < 0) {
1021 ui__error("Can't register callchain params.\n"); 921 ui__error("Can't register callchain params.\n");
1022 return -EINVAL; 922 return -EINVAL;
@@ -1028,6 +928,7 @@ static int perf_top__setup_sample_type(struct perf_top *top)
1028 928
1029static int __cmd_top(struct perf_top *top) 929static int __cmd_top(struct perf_top *top)
1030{ 930{
931 struct perf_record_opts *opts = &top->record_opts;
1031 pthread_t thread; 932 pthread_t thread;
1032 int ret; 933 int ret;
1033 /* 934 /*
@@ -1042,26 +943,42 @@ static int __cmd_top(struct perf_top *top)
1042 if (ret) 943 if (ret)
1043 goto out_delete; 944 goto out_delete;
1044 945
1045 if (perf_target__has_task(&top->target)) 946 if (perf_target__has_task(&opts->target))
1046 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 947 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
1047 perf_event__process, 948 perf_event__process,
1048 &top->session->host_machine); 949 &top->session->machines.host);
1049 else 950 else
1050 perf_event__synthesize_threads(&top->tool, perf_event__process, 951 perf_event__synthesize_threads(&top->tool, perf_event__process,
1051 &top->session->host_machine); 952 &top->session->machines.host);
1052 perf_top__start_counters(top); 953
954 ret = perf_top__start_counters(top);
955 if (ret)
956 goto out_delete;
957
1053 top->session->evlist = top->evlist; 958 top->session->evlist = top->evlist;
1054 perf_session__set_id_hdr_size(top->session); 959 perf_session__set_id_hdr_size(top->session);
1055 960
961 /*
962 * When perf is starting the traced process, all the events (apart from
963 * group members) have enable_on_exec=1 set, so don't spoil it by
964 * prematurely enabling them.
965 *
966 * XXX 'top' still doesn't start workloads like record, trace, but should,
967 * so leave the check here.
968 */
969 if (!perf_target__none(&opts->target))
970 perf_evlist__enable(top->evlist);
971
1056 /* Wait for a minimal set of events before starting the snapshot */ 972 /* Wait for a minimal set of events before starting the snapshot */
1057 poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 973 poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1058 974
1059 perf_top__mmap_read(top); 975 perf_top__mmap_read(top);
1060 976
977 ret = -1;
1061 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 978 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
1062 display_thread), top)) { 979 display_thread), top)) {
1063 ui__error("Could not create display thread.\n"); 980 ui__error("Could not create display thread.\n");
1064 exit(-1); 981 goto out_delete;
1065 } 982 }
1066 983
1067 if (top->realtime_prio) { 984 if (top->realtime_prio) {
@@ -1070,11 +987,11 @@ static int __cmd_top(struct perf_top *top)
1070 param.sched_priority = top->realtime_prio; 987 param.sched_priority = top->realtime_prio;
1071 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 988 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
1072 ui__error("Could not set realtime priority.\n"); 989 ui__error("Could not set realtime priority.\n");
1073 exit(-1); 990 goto out_delete;
1074 } 991 }
1075 } 992 }
1076 993
1077 while (1) { 994 while (!done) {
1078 u64 hits = top->samples; 995 u64 hits = top->samples;
1079 996
1080 perf_top__mmap_read(top); 997 perf_top__mmap_read(top);
@@ -1083,126 +1000,77 @@ static int __cmd_top(struct perf_top *top)
1083 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 1000 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1084 } 1001 }
1085 1002
1003 ret = 0;
1086out_delete: 1004out_delete:
1087 perf_session__delete(top->session); 1005 perf_session__delete(top->session);
1088 top->session = NULL; 1006 top->session = NULL;
1089 1007
1090 return 0; 1008 return ret;
1091} 1009}
1092 1010
1093static int 1011static int
1094parse_callchain_opt(const struct option *opt, const char *arg, int unset) 1012parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1095{ 1013{
1096 struct perf_top *top = (struct perf_top *)opt->value;
1097 char *tok, *tok2;
1098 char *endptr;
1099
1100 /* 1014 /*
1101 * --no-call-graph 1015 * --no-call-graph
1102 */ 1016 */
1103 if (unset) { 1017 if (unset)
1104 top->dont_use_callchains = true;
1105 return 0; 1018 return 0;
1106 }
1107 1019
1108 symbol_conf.use_callchain = true; 1020 symbol_conf.use_callchain = true;
1109 1021
1110 if (!arg) 1022 return record_parse_callchain_opt(opt, arg, unset);
1111 return 0; 1023}
1112
1113 tok = strtok((char *)arg, ",");
1114 if (!tok)
1115 return -1;
1116
1117 /* get the output mode */
1118 if (!strncmp(tok, "graph", strlen(arg)))
1119 callchain_param.mode = CHAIN_GRAPH_ABS;
1120
1121 else if (!strncmp(tok, "flat", strlen(arg)))
1122 callchain_param.mode = CHAIN_FLAT;
1123
1124 else if (!strncmp(tok, "fractal", strlen(arg)))
1125 callchain_param.mode = CHAIN_GRAPH_REL;
1126
1127 else if (!strncmp(tok, "none", strlen(arg))) {
1128 callchain_param.mode = CHAIN_NONE;
1129 symbol_conf.use_callchain = false;
1130
1131 return 0;
1132 } else
1133 return -1;
1134
1135 /* get the min percentage */
1136 tok = strtok(NULL, ",");
1137 if (!tok)
1138 goto setup;
1139
1140 callchain_param.min_percent = strtod(tok, &endptr);
1141 if (tok == endptr)
1142 return -1;
1143
1144 /* get the print limit */
1145 tok2 = strtok(NULL, ",");
1146 if (!tok2)
1147 goto setup;
1148 1024
1149 if (tok2[0] != 'c') { 1025static int
1150 callchain_param.print_limit = strtod(tok2, &endptr); 1026parse_percent_limit(const struct option *opt, const char *arg,
1151 tok2 = strtok(NULL, ","); 1027 int unset __maybe_unused)
1152 if (!tok2) 1028{
1153 goto setup; 1029 struct perf_top *top = opt->value;
1154 }
1155 1030
1156 /* get the call chain order */ 1031 top->min_percent = strtof(arg, NULL);
1157 if (!strcmp(tok2, "caller"))
1158 callchain_param.order = ORDER_CALLER;
1159 else if (!strcmp(tok2, "callee"))
1160 callchain_param.order = ORDER_CALLEE;
1161 else
1162 return -1;
1163setup:
1164 if (callchain_register_param(&callchain_param) < 0) {
1165 fprintf(stderr, "Can't register callchain params\n");
1166 return -1;
1167 }
1168 return 0; 1032 return 0;
1169} 1033}
1170 1034
1171int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 1035int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1172{ 1036{
1173 struct perf_evsel *pos;
1174 int status; 1037 int status;
1175 char errbuf[BUFSIZ]; 1038 char errbuf[BUFSIZ];
1176 struct perf_top top = { 1039 struct perf_top top = {
1177 .count_filter = 5, 1040 .count_filter = 5,
1178 .delay_secs = 2, 1041 .delay_secs = 2,
1179 .freq = 4000, /* 4 KHz */ 1042 .record_opts = {
1180 .mmap_pages = 128, 1043 .mmap_pages = UINT_MAX,
1181 .sym_pcnt_filter = 5, 1044 .user_freq = UINT_MAX,
1182 .target = { 1045 .user_interval = ULLONG_MAX,
1183 .uses_mmap = true, 1046 .freq = 4000, /* 4 KHz */
1047 .target = {
1048 .uses_mmap = true,
1049 },
1184 }, 1050 },
1051 .sym_pcnt_filter = 5,
1185 }; 1052 };
1186 char callchain_default_opt[] = "fractal,0.5,callee"; 1053 struct perf_record_opts *opts = &top.record_opts;
1054 struct perf_target *target = &opts->target;
1187 const struct option options[] = { 1055 const struct option options[] = {
1188 OPT_CALLBACK('e', "event", &top.evlist, "event", 1056 OPT_CALLBACK('e', "event", &top.evlist, "event",
1189 "event selector. use 'perf list' to list available events", 1057 "event selector. use 'perf list' to list available events",
1190 parse_events_option), 1058 parse_events_option),
1191 OPT_INTEGER('c', "count", &top.default_interval, 1059 OPT_U64('c', "count", &opts->user_interval, "event period to sample"),
1192 "event period to sample"), 1060 OPT_STRING('p', "pid", &target->pid, "pid",
1193 OPT_STRING('p', "pid", &top.target.pid, "pid",
1194 "profile events on existing process id"), 1061 "profile events on existing process id"),
1195 OPT_STRING('t', "tid", &top.target.tid, "tid", 1062 OPT_STRING('t', "tid", &target->tid, "tid",
1196 "profile events on existing thread id"), 1063 "profile events on existing thread id"),
1197 OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide, 1064 OPT_BOOLEAN('a', "all-cpus", &target->system_wide,
1198 "system-wide collection from all CPUs"), 1065 "system-wide collection from all CPUs"),
1199 OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu", 1066 OPT_STRING('C', "cpu", &target->cpu_list, "cpu",
1200 "list of cpus to monitor"), 1067 "list of cpus to monitor"),
1201 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1068 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1202 "file", "vmlinux pathname"), 1069 "file", "vmlinux pathname"),
1203 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, 1070 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1204 "hide kernel symbols"), 1071 "hide kernel symbols"),
1205 OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), 1072 OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages,
1073 "number of mmap data pages"),
1206 OPT_INTEGER('r', "realtime", &top.realtime_prio, 1074 OPT_INTEGER('r', "realtime", &top.realtime_prio,
1207 "collect data with this RT SCHED_FIFO priority"), 1075 "collect data with this RT SCHED_FIFO priority"),
1208 OPT_INTEGER('d', "delay", &top.delay_secs, 1076 OPT_INTEGER('d', "delay", &top.delay_secs,
@@ -1211,16 +1079,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1211 "dump the symbol table used for profiling"), 1079 "dump the symbol table used for profiling"),
1212 OPT_INTEGER('f', "count-filter", &top.count_filter, 1080 OPT_INTEGER('f', "count-filter", &top.count_filter,
1213 "only display functions with more events than this"), 1081 "only display functions with more events than this"),
1214 OPT_BOOLEAN('g', "group", &top.group, 1082 OPT_BOOLEAN('g', "group", &opts->group,
1215 "put the counters into a counter group"), 1083 "put the counters into a counter group"),
1216 OPT_BOOLEAN('i', "inherit", &top.inherit, 1084 OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit,
1217 "child tasks inherit counters"), 1085 "child tasks do not inherit counters"),
1218 OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", 1086 OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
1219 "symbol to annotate"), 1087 "symbol to annotate"),
1220 OPT_BOOLEAN('z', "zero", &top.zero, 1088 OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"),
1221 "zero history across updates"), 1089 OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"),
1222 OPT_INTEGER('F', "freq", &top.freq,
1223 "profile at this frequency"),
1224 OPT_INTEGER('E', "entries", &top.print_entries, 1090 OPT_INTEGER('E', "entries", &top.print_entries,
1225 "display this many functions"), 1091 "display this many functions"),
1226 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, 1092 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
@@ -1230,13 +1096,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1230 OPT_INCR('v', "verbose", &verbose, 1096 OPT_INCR('v', "verbose", &verbose,
1231 "be more verbose (show counter open errors, etc)"), 1097 "be more verbose (show counter open errors, etc)"),
1232 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1098 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1233 "sort by key(s): pid, comm, dso, symbol, parent"), 1099 "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"),
1234 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1100 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1235 "Show a column with the number of samples"), 1101 "Show a column with the number of samples"),
1236 OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", 1102 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
1237 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " 1103 "mode[,dump_size]", record_callchain_help,
1238 "Default: fractal,0.5,callee", &parse_callchain_opt, 1104 &parse_callchain_opt, "fp"),
1239 callchain_default_opt),
1240 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 1105 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1241 "Show a column with the sum of periods"), 1106 "Show a column with the sum of periods"),
1242 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 1107 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -1251,7 +1116,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1251 "Display raw encoding of assembly instructions (default)"), 1116 "Display raw encoding of assembly instructions (default)"),
1252 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1117 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1253 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1118 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1254 OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), 1119 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
1120 OPT_CALLBACK(0, "percent-limit", &top, "percent",
1121 "Don't show entries under that percent", parse_percent_limit),
1255 OPT_END() 1122 OPT_END()
1256 }; 1123 };
1257 const char * const top_usage[] = { 1124 const char * const top_usage[] = {
@@ -1259,7 +1126,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1259 NULL 1126 NULL
1260 }; 1127 };
1261 1128
1262 top.evlist = perf_evlist__new(NULL, NULL); 1129 top.evlist = perf_evlist__new();
1263 if (top.evlist == NULL) 1130 if (top.evlist == NULL)
1264 return -ENOMEM; 1131 return -ENOMEM;
1265 1132
@@ -1272,7 +1139,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1272 if (sort_order == default_sort_order) 1139 if (sort_order == default_sort_order)
1273 sort_order = "dso,symbol"; 1140 sort_order = "dso,symbol";
1274 1141
1275 setup_sorting(top_usage, options); 1142 if (setup_sorting() < 0)
1143 usage_with_options(top_usage, options);
1144
1145 /* display thread wants entries to be collapsed in a different tree */
1146 sort__need_collapse = 1;
1276 1147
1277 if (top.use_stdio) 1148 if (top.use_stdio)
1278 use_browser = 0; 1149 use_browser = 0;
@@ -1281,33 +1152,33 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1281 1152
1282 setup_browser(false); 1153 setup_browser(false);
1283 1154
1284 status = perf_target__validate(&top.target); 1155 status = perf_target__validate(target);
1285 if (status) { 1156 if (status) {
1286 perf_target__strerror(&top.target, status, errbuf, BUFSIZ); 1157 perf_target__strerror(target, status, errbuf, BUFSIZ);
1287 ui__warning("%s", errbuf); 1158 ui__warning("%s", errbuf);
1288 } 1159 }
1289 1160
1290 status = perf_target__parse_uid(&top.target); 1161 status = perf_target__parse_uid(target);
1291 if (status) { 1162 if (status) {
1292 int saved_errno = errno; 1163 int saved_errno = errno;
1293 1164
1294 perf_target__strerror(&top.target, status, errbuf, BUFSIZ); 1165 perf_target__strerror(target, status, errbuf, BUFSIZ);
1295 ui__error("%s", errbuf); 1166 ui__error("%s", errbuf);
1296 1167
1297 status = -saved_errno; 1168 status = -saved_errno;
1298 goto out_delete_evlist; 1169 goto out_delete_evlist;
1299 } 1170 }
1300 1171
1301 if (perf_target__none(&top.target)) 1172 if (perf_target__none(target))
1302 top.target.system_wide = true; 1173 target->system_wide = true;
1303 1174
1304 if (perf_evlist__create_maps(top.evlist, &top.target) < 0) 1175 if (perf_evlist__create_maps(top.evlist, target) < 0)
1305 usage_with_options(top_usage, options); 1176 usage_with_options(top_usage, options);
1306 1177
1307 if (!top.evlist->nr_entries && 1178 if (!top.evlist->nr_entries &&
1308 perf_evlist__add_default(top.evlist) < 0) { 1179 perf_evlist__add_default(top.evlist) < 0) {
1309 ui__error("Not enough memory for event selector list\n"); 1180 ui__error("Not enough memory for event selector list\n");
1310 return -ENOMEM; 1181 goto out_delete_maps;
1311 } 1182 }
1312 1183
1313 symbol_conf.nr_events = top.evlist->nr_entries; 1184 symbol_conf.nr_events = top.evlist->nr_entries;
@@ -1315,24 +1186,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1315 if (top.delay_secs < 1) 1186 if (top.delay_secs < 1)
1316 top.delay_secs = 1; 1187 top.delay_secs = 1;
1317 1188
1189 if (opts->user_interval != ULLONG_MAX)
1190 opts->default_interval = opts->user_interval;
1191 if (opts->user_freq != UINT_MAX)
1192 opts->freq = opts->user_freq;
1193
1318 /* 1194 /*
1319 * User specified count overrides default frequency. 1195 * User specified count overrides default frequency.
1320 */ 1196 */
1321 if (top.default_interval) 1197 if (opts->default_interval)
1322 top.freq = 0; 1198 opts->freq = 0;
1323 else if (top.freq) { 1199 else if (opts->freq) {
1324 top.default_interval = top.freq; 1200 opts->default_interval = opts->freq;
1325 } else { 1201 } else {
1326 ui__error("frequency and count are zero, aborting\n"); 1202 ui__error("frequency and count are zero, aborting\n");
1327 exit(EXIT_FAILURE); 1203 status = -EINVAL;
1328 } 1204 goto out_delete_maps;
1329
1330 list_for_each_entry(pos, &top.evlist->entries, node) {
1331 /*
1332 * Fill in the ones not specifically initialized via -c:
1333 */
1334 if (!pos->attr.sample_period)
1335 pos->attr.sample_period = top.default_interval;
1336 } 1205 }
1337 1206
1338 top.sym_evsel = perf_evlist__first(top.evlist); 1207 top.sym_evsel = perf_evlist__first(top.evlist);
@@ -1343,15 +1212,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1343 if (symbol__init() < 0) 1212 if (symbol__init() < 0)
1344 return -1; 1213 return -1;
1345 1214
1346 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout); 1215 sort__setup_elide(stdout);
1347 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1348 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1349
1350 /*
1351 * Avoid annotation data structures overhead when symbols aren't on the
1352 * sort list.
1353 */
1354 top.sort_has_symbols = sort_sym.list.next != NULL;
1355 1216
1356 get_term_dimensions(&top.winsize); 1217 get_term_dimensions(&top.winsize);
1357 if (top.print_entries == 0) { 1218 if (top.print_entries == 0) {
@@ -1365,6 +1226,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1365 1226
1366 status = __cmd_top(&top); 1227 status = __cmd_top(&top);
1367 1228
1229out_delete_maps:
1230 perf_evlist__delete_maps(top.evlist);
1368out_delete_evlist: 1231out_delete_evlist:
1369 perf_evlist__delete(top.evlist); 1232 perf_evlist__delete(top.evlist);
1370 1233
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 7932ffa29889..ab3ed4af1466 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -419,7 +419,7 @@ out_dump:
419 419
420static int trace__run(struct trace *trace, int argc, const char **argv) 420static int trace__run(struct trace *trace, int argc, const char **argv)
421{ 421{
422 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 422 struct perf_evlist *evlist = perf_evlist__new();
423 struct perf_evsel *evsel; 423 struct perf_evsel *evsel;
424 int err = -1, i; 424 int err = -1, i;
425 unsigned long before; 425 unsigned long before;
@@ -452,32 +452,33 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
452 err = trace__symbols_init(trace, evlist); 452 err = trace__symbols_init(trace, evlist);
453 if (err < 0) { 453 if (err < 0) {
454 printf("Problems initializing symbol libraries!\n"); 454 printf("Problems initializing symbol libraries!\n");
455 goto out_delete_evlist; 455 goto out_delete_maps;
456 } 456 }
457 457
458 perf_evlist__config_attrs(evlist, &trace->opts); 458 perf_evlist__config(evlist, &trace->opts);
459 459
460 signal(SIGCHLD, sig_handler); 460 signal(SIGCHLD, sig_handler);
461 signal(SIGINT, sig_handler); 461 signal(SIGINT, sig_handler);
462 462
463 if (forks) { 463 if (forks) {
464 err = perf_evlist__prepare_workload(evlist, &trace->opts, argv); 464 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
465 argv, false, false);
465 if (err < 0) { 466 if (err < 0) {
466 printf("Couldn't run the workload!\n"); 467 printf("Couldn't run the workload!\n");
467 goto out_delete_evlist; 468 goto out_delete_maps;
468 } 469 }
469 } 470 }
470 471
471 err = perf_evlist__open(evlist); 472 err = perf_evlist__open(evlist);
472 if (err < 0) { 473 if (err < 0) {
473 printf("Couldn't create the events: %s\n", strerror(errno)); 474 printf("Couldn't create the events: %s\n", strerror(errno));
474 goto out_delete_evlist; 475 goto out_delete_maps;
475 } 476 }
476 477
477 err = perf_evlist__mmap(evlist, UINT_MAX, false); 478 err = perf_evlist__mmap(evlist, UINT_MAX, false);
478 if (err < 0) { 479 if (err < 0) {
479 printf("Couldn't mmap the events: %s\n", strerror(errno)); 480 printf("Couldn't mmap the events: %s\n", strerror(errno));
480 goto out_delete_evlist; 481 goto out_close_evlist;
481 } 482 }
482 483
483 perf_evlist__enable(evlist); 484 perf_evlist__enable(evlist);
@@ -526,13 +527,6 @@ again:
526 continue; 527 continue;
527 } 528 }
528 529
529 if (sample.raw_data == NULL) {
530 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
531 perf_evsel__name(evsel), sample.tid,
532 sample.cpu, sample.raw_size);
533 continue;
534 }
535
536 handler = evsel->handler.func; 530 handler = evsel->handler.func;
537 handler(trace, evsel, &sample); 531 handler(trace, evsel, &sample);
538 } 532 }
@@ -540,7 +534,7 @@ again:
540 534
541 if (trace->nr_events == before) { 535 if (trace->nr_events == before) {
542 if (done) 536 if (done)
543 goto out_delete_evlist; 537 goto out_unmap_evlist;
544 538
545 poll(evlist->pollfd, evlist->nr_fds, -1); 539 poll(evlist->pollfd, evlist->nr_fds, -1);
546 } 540 }
@@ -550,6 +544,12 @@ again:
550 544
551 goto again; 545 goto again;
552 546
547out_unmap_evlist:
548 perf_evlist__munmap(evlist);
549out_close_evlist:
550 perf_evlist__close(evlist);
551out_delete_maps:
552 perf_evlist__delete_maps(evlist);
553out_delete_evlist: 553out_delete_evlist:
554 perf_evlist__delete(evlist); 554 perf_evlist__delete(evlist);
555out: 555out:
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 08143bd854c7..b210d62907e4 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -36,6 +36,7 @@ extern int cmd_kvm(int argc, const char **argv, const char *prefix);
36extern int cmd_test(int argc, const char **argv, const char *prefix); 36extern int cmd_test(int argc, const char **argv, const char *prefix);
37extern int cmd_trace(int argc, const char **argv, const char *prefix); 37extern int cmd_trace(int argc, const char **argv, const char *prefix);
38extern int cmd_inject(int argc, const char **argv, const char *prefix); 38extern int cmd_inject(int argc, const char **argv, const char *prefix);
39extern int cmd_mem(int argc, const char **argv, const char *prefix);
39 40
40extern int find_scripts(char **scripts_array, char **scripts_path_array); 41extern int find_scripts(char **scripts_array, char **scripts_path_array);
41#endif 42#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 3e86bbd8c2d5..0906fc401c52 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -10,17 +10,18 @@ perf-buildid-list mainporcelain common
10perf-diff mainporcelain common 10perf-diff mainporcelain common
11perf-evlist mainporcelain common 11perf-evlist mainporcelain common
12perf-inject mainporcelain common 12perf-inject mainporcelain common
13perf-kmem mainporcelain common
14perf-kvm mainporcelain common
13perf-list mainporcelain common 15perf-list mainporcelain common
14perf-sched mainporcelain common 16perf-lock mainporcelain common
17perf-mem mainporcelain common
18perf-probe mainporcelain full
15perf-record mainporcelain common 19perf-record mainporcelain common
16perf-report mainporcelain common 20perf-report mainporcelain common
21perf-sched mainporcelain common
22perf-script mainporcelain common
17perf-stat mainporcelain common 23perf-stat mainporcelain common
24perf-test mainporcelain common
18perf-timechart mainporcelain common 25perf-timechart mainporcelain common
19perf-top mainporcelain common 26perf-top mainporcelain common
20perf-trace mainporcelain common 27perf-trace mainporcelain common
21perf-script mainporcelain common
22perf-probe mainporcelain full
23perf-kmem mainporcelain common
24perf-lock mainporcelain common
25perf-kvm mainporcelain common
26perf-test mainporcelain common
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
new file mode 100644
index 000000000000..f139dcd2796e
--- /dev/null
+++ b/tools/perf/config/Makefile
@@ -0,0 +1,477 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2
3ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
4 -e s/arm.*/arm/ -e s/sa110/arm/ \
5 -e s/s390x/s390/ -e s/parisc64/parisc/ \
6 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
7 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
8NO_PERF_REGS := 1
9CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
10
11# Additional ARCH settings for x86
12ifeq ($(ARCH),i386)
13 override ARCH := x86
14 NO_PERF_REGS := 0
15 LIBUNWIND_LIBS = -lunwind -lunwind-x86
16endif
17
18ifeq ($(ARCH),x86_64)
19 override ARCH := x86
20 IS_X86_64 := 0
21 ifeq (, $(findstring m32,$(CFLAGS)))
22 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
23 endif
24 ifeq (${IS_X86_64}, 1)
25 RAW_ARCH := x86_64
26 CFLAGS += -DARCH_X86_64
27 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
28 endif
29 NO_PERF_REGS := 0
30 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
31endif
32
33ifeq ($(NO_PERF_REGS),0)
34 CFLAGS += -DHAVE_PERF_REGS
35endif
36
37ifeq ($(src-perf),)
38src-perf := $(srctree)/tools/perf
39endif
40
41ifeq ($(obj-perf),)
42obj-perf := $(objtree)
43endif
44
45ifneq ($(obj-perf),)
46obj-perf := $(abspath $(obj-perf))/
47endif
48
49# include ARCH specific config
50-include $(src-perf)/arch/$(ARCH)/Makefile
51
52include $(src-perf)/config/feature-tests.mak
53include $(src-perf)/config/utilities.mak
54
55ifeq ($(call get-executable,$(FLEX)),)
56 dummy := $(error Error: $(FLEX) is missing on this system, please install it)
57endif
58
59ifeq ($(call get-executable,$(BISON)),)
60 dummy := $(error Error: $(BISON) is missing on this system, please install it)
61endif
62
63# Treat warnings as errors unless directed not to
64ifneq ($(WERROR),0)
65 CFLAGS += -Werror
66endif
67
68ifeq ("$(origin DEBUG)", "command line")
69 PERF_DEBUG = $(DEBUG)
70endif
71ifndef PERF_DEBUG
72 CFLAGS += -O6
73endif
74
75ifdef PARSER_DEBUG
76 PARSER_DEBUG_BISON := -t
77 PARSER_DEBUG_FLEX := -d
78 CFLAGS += -DPARSER_DEBUG
79endif
80
81CFLAGS += -fno-omit-frame-pointer
82CFLAGS += -ggdb3
83CFLAGS += -funwind-tables
84CFLAGS += -Wall
85CFLAGS += -Wextra
86CFLAGS += -std=gnu99
87
88EXTLIBS = -lpthread -lrt -lelf -lm
89
90ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
91 CFLAGS += -fstack-protector-all
92endif
93
94ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y)
95 CFLAGS += -Wstack-protector
96endif
97
98ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y)
99 CFLAGS += -Wvolatile-register-var
100endif
101
102ifndef PERF_DEBUG
103 ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y)
104 CFLAGS += -D_FORTIFY_SOURCE=2
105 endif
106endif
107
108CFLAGS += -I$(src-perf)/util/include
109CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
110CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi
111CFLAGS += -I$(srctree)/arch/$(ARCH)/include
112CFLAGS += -I$(srctree)/include/uapi
113CFLAGS += -I$(srctree)/include
114
115# $(obj-perf) for generated common-cmds.h
116# $(obj-perf)/util for generated bison/flex headers
117ifneq ($(OUTPUT),)
118CFLAGS += -I$(obj-perf)/util
119CFLAGS += -I$(obj-perf)
120endif
121
122CFLAGS += -I$(src-perf)/util
123CFLAGS += -I$(src-perf)
124CFLAGS += -I$(TRACE_EVENT_DIR)
125CFLAGS += -I$(srctree)/tools/lib/
126
127CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
128
129ifndef NO_BIONIC
130ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
131 BIONIC := 1
132 EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
133 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
134endif
135endif # NO_BIONIC
136
137ifdef NO_LIBELF
138 NO_DWARF := 1
139 NO_DEMANGLE := 1
140 NO_LIBUNWIND := 1
141else
142FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
143ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
144 FLAGS_GLIBC=$(CFLAGS) $(LDFLAGS)
145 ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
146 LIBC_SUPPORT := 1
147 endif
148 ifeq ($(BIONIC),1)
149 LIBC_SUPPORT := 1
150 endif
151 ifeq ($(LIBC_SUPPORT),1)
152 msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
153
154 NO_LIBELF := 1
155 NO_DWARF := 1
156 NO_DEMANGLE := 1
157 else
158 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
159 endif
160else
161 # for linking with debug library, run like:
162 # make DEBUG=1 LIBDW_DIR=/opt/libdw/
163 ifdef LIBDW_DIR
164 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
165 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
166 endif
167
168 FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS)
169 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
170 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
171 NO_DWARF := 1
172 endif # Dwarf support
173endif # SOURCE_LIBELF
174endif # NO_LIBELF
175
176ifndef NO_LIBELF
177CFLAGS += -DLIBELF_SUPPORT
178FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
179ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
180 CFLAGS += -DLIBELF_MMAP
181endif
182
183# include ARCH specific config
184-include $(src-perf)/arch/$(ARCH)/Makefile
185
186ifndef NO_DWARF
187ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
188 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
189 NO_DWARF := 1
190else
191 CFLAGS += -DDWARF_SUPPORT $(LIBDW_CFLAGS)
192 LDFLAGS += $(LIBDW_LDFLAGS)
193 EXTLIBS += -lelf -ldw
194endif # PERF_HAVE_DWARF_REGS
195endif # NO_DWARF
196
197endif # NO_LIBELF
198
199ifndef NO_LIBELF
200CFLAGS += -DLIBELF_SUPPORT
201FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
202ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
203 CFLAGS += -DLIBELF_MMAP
204endif # try-cc
205endif # NO_LIBELF
206
207# There's only x86 (both 32 and 64) support for CFI unwind so far
208ifneq ($(ARCH),x86)
209 NO_LIBUNWIND := 1
210endif
211
212ifndef NO_LIBUNWIND
213# for linking with debug library, run like:
214# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
215ifdef LIBUNWIND_DIR
216 LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
217 LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
218endif
219
220FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(CFLAGS) $(LIBUNWIND_LDFLAGS) $(LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
221ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
222 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
223 NO_LIBUNWIND := 1
224endif # Libunwind support
225endif # NO_LIBUNWIND
226
227ifndef NO_LIBUNWIND
228 CFLAGS += -DLIBUNWIND_SUPPORT
229 EXTLIBS += $(LIBUNWIND_LIBS)
230 CFLAGS += $(LIBUNWIND_CFLAGS)
231 LDFLAGS += $(LIBUNWIND_LDFLAGS)
232endif # NO_LIBUNWIND
233
234ifndef NO_LIBAUDIT
235 FLAGS_LIBAUDIT = $(CFLAGS) $(LDFLAGS) -laudit
236 ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
237 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
238 NO_LIBAUDIT := 1
239 else
240 CFLAGS += -DLIBAUDIT_SUPPORT
241 EXTLIBS += -laudit
242 endif
243endif
244
245ifdef NO_NEWT
246 NO_SLANG=1
247endif
248
249ifndef NO_SLANG
250 FLAGS_SLANG=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang
251 ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y)
252 msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
253 NO_SLANG := 1
254 else
255 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
256 CFLAGS += -I/usr/include/slang
257 CFLAGS += -DSLANG_SUPPORT
258 EXTLIBS += -lslang
259 endif
260endif
261
262ifndef NO_GTK2
263 FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
264 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y)
265 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
266 NO_GTK2 := 1
267 else
268 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
269 CFLAGS += -DHAVE_GTK_INFO_BAR
270 endif
271 CFLAGS += -DGTK2_SUPPORT
272 CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
273 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
274 endif
275endif
276
277grep-libs = $(filter -l%,$(1))
278strip-libs = $(filter-out -l%,$(1))
279
280ifdef NO_LIBPERL
281 CFLAGS += -DNO_LIBPERL
282else
283 PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
284 PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
285 PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
286 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
287 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
288
289 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
290 CFLAGS += -DNO_LIBPERL
291 NO_LIBPERL := 1
292 else
293 LDFLAGS += $(PERL_EMBED_LDFLAGS)
294 EXTLIBS += $(PERL_EMBED_LIBADD)
295 endif
296endif
297
298disable-python = $(eval $(disable-python_code))
299define disable-python_code
300 CFLAGS += -DNO_LIBPYTHON
301 $(if $(1),$(warning No $(1) was found))
302 $(warning Python support will not be built)
303 NO_LIBPYTHON := 1
304endef
305
306override PYTHON := \
307 $(call get-executable-or-default,PYTHON,python)
308
309ifndef PYTHON
310 $(call disable-python,python interpreter)
311else
312
313 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
314
315 ifdef NO_LIBPYTHON
316 $(call disable-python)
317 else
318
319 override PYTHON_CONFIG := \
320 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
321
322 ifndef PYTHON_CONFIG
323 $(call disable-python,python-config tool)
324 else
325
326 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
327
328 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
329 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
330 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
331 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
332 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
333
334 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
335 $(call disable-python,Python.h (for Python 2.x))
336 else
337
338 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
339 $(warning Python 3 is not yet supported; please set)
340 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
341 $(warning If you also have Python 2 installed, then)
342 $(warning try something like:)
343 $(warning $(and ,))
344 $(warning $(and ,) make PYTHON=python2)
345 $(warning $(and ,))
346 $(warning Otherwise, disable Python support entirely:)
347 $(warning $(and ,))
348 $(warning $(and ,) make NO_LIBPYTHON=1)
349 $(warning $(and ,))
350 $(error $(and ,))
351 else
352 LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
353 EXTLIBS += $(PYTHON_EMBED_LIBADD)
354 LANG_BINDINGS += $(obj-perf)python/perf.so
355 endif
356 endif
357 endif
358 endif
359endif
360
361ifdef NO_DEMANGLE
362 CFLAGS += -DNO_DEMANGLE
363else
364 ifdef HAVE_CPLUS_DEMANGLE
365 EXTLIBS += -liberty
366 CFLAGS += -DHAVE_CPLUS_DEMANGLE
367 else
368 FLAGS_BFD=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
369 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
370 ifeq ($(has_bfd),y)
371 EXTLIBS += -lbfd
372 else
373 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
374 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
375 ifeq ($(has_bfd_iberty),y)
376 EXTLIBS += -lbfd -liberty
377 else
378 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
379 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
380 ifeq ($(has_bfd_iberty_z),y)
381 EXTLIBS += -lbfd -liberty -lz
382 else
383 FLAGS_CPLUS_DEMANGLE=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -liberty
384 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
385 ifeq ($(has_cplus_demangle),y)
386 EXTLIBS += -liberty
387 CFLAGS += -DHAVE_CPLUS_DEMANGLE
388 else
389 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
390 CFLAGS += -DNO_DEMANGLE
391 endif
392 endif
393 endif
394 endif
395 endif
396endif
397
398ifndef NO_STRLCPY
399 ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
400 CFLAGS += -DHAVE_STRLCPY
401 endif
402endif
403
404ifndef NO_ON_EXIT
405 ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
406 CFLAGS += -DHAVE_ON_EXIT
407 endif
408endif
409
410ifndef NO_BACKTRACE
411 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
412 CFLAGS += -DBACKTRACE_SUPPORT
413 endif
414endif
415
416ifndef NO_LIBNUMA
417 FLAGS_LIBNUMA = $(CFLAGS) $(LDFLAGS) -lnuma
418 ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
419 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
420 NO_LIBNUMA := 1
421 else
422 CFLAGS += -DLIBNUMA_SUPPORT
423 EXTLIBS += -lnuma
424 endif
425endif
426
427# Among the variables below, these:
428# perfexecdir
429# template_dir
430# mandir
431# infodir
432# htmldir
433# ETC_PERFCONFIG (but not sysconfdir)
434# can be specified as a relative path some/where/else;
435# this is interpreted as relative to $(prefix) and "perf" at
436# runtime figures out where they are based on the path to the executable.
437# This can help installing the suite in a relocatable way.
438
439# Make the path relative to DESTDIR, not to prefix
440ifndef DESTDIR
441prefix = $(HOME)
442endif
443bindir_relative = bin
444bindir = $(prefix)/$(bindir_relative)
445mandir = share/man
446infodir = share/info
447perfexecdir = libexec/perf-core
448sharedir = $(prefix)/share
449template_dir = share/perf-core/templates
450htmldir = share/doc/perf-doc
451ifeq ($(prefix),/usr)
452sysconfdir = /etc
453ETC_PERFCONFIG = $(sysconfdir)/perfconfig
454else
455sysconfdir = $(prefix)/etc
456ETC_PERFCONFIG = etc/perfconfig
457endif
458lib = lib
459
460# Shell quote (do not use $(call) to accommodate ancient setups);
461ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
462DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
463bindir_SQ = $(subst ','\'',$(bindir))
464mandir_SQ = $(subst ','\'',$(mandir))
465infodir_SQ = $(subst ','\'',$(infodir))
466perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
467template_dir_SQ = $(subst ','\'',$(template_dir))
468htmldir_SQ = $(subst ','\'',$(htmldir))
469prefix_SQ = $(subst ','\'',$(prefix))
470sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
471
472ifneq ($(filter /%,$(firstword $(perfexecdir))),)
473perfexec_instdir = $(perfexecdir)
474else
475perfexec_instdir = $(prefix)/$(perfexecdir)
476endif
477perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index f5ac77485a4f..708fb8e9822a 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -61,15 +61,13 @@ int main(void)
61} 61}
62endef 62endef
63 63
64ifndef NO_NEWT 64ifndef NO_SLANG
65define SOURCE_NEWT 65define SOURCE_SLANG
66#include <newt.h> 66#include <slang.h>
67 67
68int main(void) 68int main(void)
69{ 69{
70 newtInit(); 70 return SLsmg_init_smg();
71 newtCls();
72 return newtFinished();
73} 71}
74endef 72endef
75endif 73endif
@@ -225,3 +223,14 @@ int main(void)
225 return on_exit(NULL, NULL); 223 return on_exit(NULL, NULL);
226} 224}
227endef 225endef
226
227define SOURCE_LIBNUMA
228#include <numa.h>
229#include <numaif.h>
230
231int main(void)
232{
233 numa_available();
234 return 0;
235}
236endef
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index e5413125e6bb..8ef3bd30a549 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -13,7 +13,7 @@ newline := $(newline)
13# what should replace a newline when escaping 13# what should replace a newline when escaping
14# newlines; the default is a bizarre string. 14# newlines; the default is a bizarre string.
15# 15#
16nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n) 16nl-escape = $(if $(1),$(1),m822df3020w6a44id34bt574ctac44eb9f4n)
17 17
18# escape-nl 18# escape-nl
19# 19#
@@ -173,9 +173,9 @@ _ge-abspath = $(if $(is-executable),$(1))
173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) 173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
174# 174#
175define get-executable-or-default 175define get-executable-or-default
176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) 176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1)))
177endef 177endef
178_ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2))) 178_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2)))
179_gea_warn = $(warning The path '$(1)' is not executable.) 179_gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) 180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181 181
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 0f661fbce6a8..85e1aed95204 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -13,7 +13,7 @@
13#include "util/quote.h" 13#include "util/quote.h"
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include "util/debugfs.h" 16#include <lk/debugfs.h>
17#include <pthread.h> 17#include <pthread.h>
18 18
19const char perf_usage_string[] = 19const char perf_usage_string[] =
@@ -60,6 +60,7 @@ static struct cmd_struct commands[] = {
60 { "trace", cmd_trace, 0 }, 60 { "trace", cmd_trace, 0 },
61#endif 61#endif
62 { "inject", cmd_inject, 0 }, 62 { "inject", cmd_inject, 0 },
63 { "mem", cmd_mem, 0 },
63}; 64};
64 65
65struct pager_config { 66struct pager_config {
@@ -193,13 +194,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
193 fprintf(stderr, "No directory given for --debugfs-dir.\n"); 194 fprintf(stderr, "No directory given for --debugfs-dir.\n");
194 usage(perf_usage_string); 195 usage(perf_usage_string);
195 } 196 }
196 debugfs_set_path((*argv)[1]); 197 perf_debugfs_set_path((*argv)[1]);
197 if (envchanged) 198 if (envchanged)
198 *envchanged = 1; 199 *envchanged = 1;
199 (*argv)++; 200 (*argv)++;
200 (*argc)--; 201 (*argc)--;
201 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { 202 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
202 debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); 203 perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
203 fprintf(stderr, "dir: %s\n", debugfs_mountpoint); 204 fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
204 if (envchanged) 205 if (envchanged)
205 *envchanged = 1; 206 *envchanged = 1;
@@ -328,14 +329,23 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
328 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) 329 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
329 return 0; 330 return 0;
330 331
332 status = 1;
331 /* Check for ENOSPC and EIO errors.. */ 333 /* Check for ENOSPC and EIO errors.. */
332 if (fflush(stdout)) 334 if (fflush(stdout)) {
333 die("write failure on standard output: %s", strerror(errno)); 335 fprintf(stderr, "write failure on standard output: %s", strerror(errno));
334 if (ferror(stdout)) 336 goto out;
335 die("unknown write failure on standard output"); 337 }
336 if (fclose(stdout)) 338 if (ferror(stdout)) {
337 die("close failed on standard output: %s", strerror(errno)); 339 fprintf(stderr, "unknown write failure on standard output");
338 return 0; 340 goto out;
341 }
342 if (fclose(stdout)) {
343 fprintf(stderr, "close failed on standard output: %s", strerror(errno));
344 goto out;
345 }
346 status = 0;
347out:
348 return status;
339} 349}
340 350
341static void handle_internal_command(int argc, const char **argv) 351static void handle_internal_command(int argc, const char **argv)
@@ -452,7 +462,7 @@ int main(int argc, const char **argv)
452 if (!cmd) 462 if (!cmd)
453 cmd = "perf-help"; 463 cmd = "perf-help";
454 /* get debugfs mount point from /proc/mounts */ 464 /* get debugfs mount point from /proc/mounts */
455 debugfs_mount(NULL); 465 perf_debugfs_mount(NULL);
456 /* 466 /*
457 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 467 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
458 * 468 *
@@ -467,7 +477,8 @@ int main(int argc, const char **argv)
467 cmd += 5; 477 cmd += 5;
468 argv[0] = cmd; 478 argv[0] = cmd;
469 handle_internal_command(argc, argv); 479 handle_internal_command(argc, argv);
470 die("cannot handle %s internally", cmd); 480 fprintf(stderr, "cannot handle %s internally", cmd);
481 goto out;
471 } 482 }
472 483
473 /* Look for flags.. */ 484 /* Look for flags.. */
@@ -485,7 +496,7 @@ int main(int argc, const char **argv)
485 printf("\n usage: %s\n\n", perf_usage_string); 496 printf("\n usage: %s\n\n", perf_usage_string);
486 list_common_cmds_help(); 497 list_common_cmds_help();
487 printf("\n %s\n\n", perf_more_info_string); 498 printf("\n %s\n\n", perf_more_info_string);
488 exit(1); 499 goto out;
489 } 500 }
490 cmd = argv[0]; 501 cmd = argv[0];
491 502
@@ -507,9 +518,8 @@ int main(int argc, const char **argv)
507 518
508 while (1) { 519 while (1) {
509 static int done_help; 520 static int done_help;
510 static int was_alias; 521 int was_alias = run_argv(&argc, &argv);
511 522
512 was_alias = run_argv(&argc, &argv);
513 if (errno != ENOENT) 523 if (errno != ENOENT)
514 break; 524 break;
515 525
@@ -517,7 +527,7 @@ int main(int argc, const char **argv)
517 fprintf(stderr, "Expansion of alias '%s' failed; " 527 fprintf(stderr, "Expansion of alias '%s' failed; "
518 "'%s' is not a perf-command\n", 528 "'%s' is not a perf-command\n",
519 cmd, argv[0]); 529 cmd, argv[0]);
520 exit(1); 530 goto out;
521 } 531 }
522 if (!done_help) { 532 if (!done_help) {
523 cmd = argv[0] = help_unknown_cmd(cmd); 533 cmd = argv[0] = help_unknown_cmd(cmd);
@@ -528,6 +538,6 @@ int main(int argc, const char **argv)
528 538
529 fprintf(stderr, "Failed to run command '%s': %s\n", 539 fprintf(stderr, "Failed to run command '%s': %s\n",
530 cmd, strerror(errno)); 540 cmd, strerror(errno));
531 541out:
532 return 1; 542 return 1;
533} 543}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 2c340e7da458..32bd102c32b6 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -1,10 +1,6 @@
1#ifndef _PERF_PERF_H 1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H 2#define _PERF_PERF_H
3 3
4struct winsize;
5
6void get_term_dimensions(struct winsize *ws);
7
8#include <asm/unistd.h> 4#include <asm/unistd.h>
9 5
10#if defined(__i386__) 6#if defined(__i386__)
@@ -98,6 +94,18 @@ void get_term_dimensions(struct winsize *ws);
98#define CPUINFO_PROC "cpu model" 94#define CPUINFO_PROC "cpu model"
99#endif 95#endif
100 96
97#ifdef __arc__
98#define rmb() asm volatile("" ::: "memory")
99#define cpu_relax() rmb()
100#define CPUINFO_PROC "Processor"
101#endif
102
103#ifdef __metag__
104#define rmb() asm volatile("" ::: "memory")
105#define cpu_relax() asm volatile("" ::: "memory")
106#define CPUINFO_PROC "CPU"
107#endif
108
101#include <time.h> 109#include <time.h>
102#include <unistd.h> 110#include <unistd.h>
103#include <sys/types.h> 111#include <sys/types.h>
@@ -107,32 +115,6 @@ void get_term_dimensions(struct winsize *ws);
107#include "util/types.h" 115#include "util/types.h"
108#include <stdbool.h> 116#include <stdbool.h>
109 117
110struct perf_mmap {
111 void *base;
112 int mask;
113 unsigned int prev;
114};
115
116static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
117{
118 struct perf_event_mmap_page *pc = mm->base;
119 int head = pc->data_head;
120 rmb();
121 return head;
122}
123
124static inline void perf_mmap__write_tail(struct perf_mmap *md,
125 unsigned long tail)
126{
127 struct perf_event_mmap_page *pc = md->base;
128
129 /*
130 * ensure all reads are done before we write the tail out.
131 */
132 /* mb(); */
133 pc->data_tail = tail;
134}
135
136/* 118/*
137 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all 119 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
138 * counters in the current task. 120 * counters in the current task.
@@ -236,9 +218,8 @@ struct perf_record_opts {
236 bool pipe_output; 218 bool pipe_output;
237 bool raw_samples; 219 bool raw_samples;
238 bool sample_address; 220 bool sample_address;
221 bool sample_weight;
239 bool sample_time; 222 bool sample_time;
240 bool sample_id_all_missing;
241 bool exclude_guest_missing;
242 bool period; 223 bool period;
243 unsigned int freq; 224 unsigned int freq;
244 unsigned int mmap_pages; 225 unsigned int mmap_pages;
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
deleted file mode 100644
index 8edda9078d5d..000000000000
--- a/tools/perf/scripts/perl/bin/workqueue-stats-record
+++ /dev/null
@@ -1,2 +0,0 @@
1#!/bin/bash
2perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
deleted file mode 100644
index 6d91411d248c..000000000000
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ /dev/null
@@ -1,3 +0,0 @@
1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy)
3perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl
diff --git a/tools/perf/scripts/perl/rwtop.pl b/tools/perf/scripts/perl/rwtop.pl
index 4bb3ecd33472..8b20787021c1 100644
--- a/tools/perf/scripts/perl/rwtop.pl
+++ b/tools/perf/scripts/perl/rwtop.pl
@@ -17,6 +17,7 @@ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib"; 17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core; 18use Perf::Trace::Core;
19use Perf::Trace::Util; 19use Perf::Trace::Util;
20use POSIX qw/SIGALRM SA_RESTART/;
20 21
21my $default_interval = 3; 22my $default_interval = 3;
22my $nlines = 20; 23my $nlines = 20;
@@ -90,7 +91,10 @@ sub syscalls::sys_enter_write
90 91
91sub trace_begin 92sub trace_begin
92{ 93{
93 $SIG{ALRM} = \&set_print_pending; 94 my $sa = POSIX::SigAction->new(\&set_print_pending);
95 $sa->flags(SA_RESTART);
96 $sa->safe(1);
97 POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n";
94 alarm 1; 98 alarm 1;
95} 99}
96 100
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
deleted file mode 100644
index a8eaff5119e0..000000000000
--- a/tools/perf/scripts/perl/workqueue-stats.pl
+++ /dev/null
@@ -1,129 +0,0 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Displays workqueue stats
6#
7# Usage:
8#
9# perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e
10# workqueue:workqueue_destruction -e workqueue:workqueue_execution
11# -e workqueue:workqueue_insertion
12#
13# perf script -p -s tools/perf/scripts/perl/workqueue-stats.pl
14
15use 5.010000;
16use strict;
17use warnings;
18
19use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
20use lib "./Perf-Trace-Util/lib";
21use Perf::Trace::Core;
22use Perf::Trace::Util;
23
24my @cpus;
25
26sub workqueue::workqueue_destruction
27{
28 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
29 $common_pid, $common_comm,
30 $thread_comm, $thread_pid) = @_;
31
32 $cpus[$common_cpu]{$thread_pid}{destroyed}++;
33 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
34}
35
36sub workqueue::workqueue_creation
37{
38 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
39 $common_pid, $common_comm,
40 $thread_comm, $thread_pid, $cpu) = @_;
41
42 $cpus[$common_cpu]{$thread_pid}{created}++;
43 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
44}
45
46sub workqueue::workqueue_execution
47{
48 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
49 $common_pid, $common_comm,
50 $thread_comm, $thread_pid, $func) = @_;
51
52 $cpus[$common_cpu]{$thread_pid}{executed}++;
53 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
54}
55
56sub workqueue::workqueue_insertion
57{
58 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
59 $common_pid, $common_comm,
60 $thread_comm, $thread_pid, $func) = @_;
61
62 $cpus[$common_cpu]{$thread_pid}{inserted}++;
63 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
64}
65
66sub trace_end
67{
68 print "workqueue work stats:\n\n";
69 my $cpu = 0;
70 printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name");
71 printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
72 foreach my $pidhash (@cpus) {
73 while ((my $pid, my $wqhash) = each %$pidhash) {
74 my $ins = $$wqhash{'inserted'} || 0;
75 my $exe = $$wqhash{'executed'} || 0;
76 my $comm = $$wqhash{'comm'} || "";
77 if ($ins || $exe) {
78 printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
79 }
80 }
81 $cpu++;
82 }
83
84 $cpu = 0;
85 print "\nworkqueue lifecycle stats:\n\n";
86 printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name");
87 printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
88 foreach my $pidhash (@cpus) {
89 while ((my $pid, my $wqhash) = each %$pidhash) {
90 my $created = $$wqhash{'created'} || 0;
91 my $destroyed = $$wqhash{'destroyed'} || 0;
92 my $comm = $$wqhash{'comm'} || "";
93 if ($created || $destroyed) {
94 printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
95 $comm);
96 }
97 }
98 $cpu++;
99 }
100
101 print_unhandled();
102}
103
104my %unhandled;
105
106sub print_unhandled
107{
108 if ((scalar keys %unhandled) == 0) {
109 return;
110 }
111
112 print "\nunhandled events:\n\n";
113
114 printf("%-40s %10s\n", "event", "count");
115 printf("%-40s %10s\n", "----------------------------------------",
116 "-----------");
117
118 foreach my $event_name (keys %unhandled) {
119 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
120 }
121}
122
123sub trace_unhandled
124{
125 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
126 $common_pid, $common_comm) = @_;
127
128 $unhandled{$event_name}++;
129}
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py
index a4ffc9500023..b5740599aabd 100755
--- a/tools/perf/scripts/python/net_dropmonitor.py
+++ b/tools/perf/scripts/python/net_dropmonitor.py
@@ -15,35 +15,38 @@ kallsyms = []
15 15
16def get_kallsyms_table(): 16def get_kallsyms_table():
17 global kallsyms 17 global kallsyms
18
18 try: 19 try:
19 f = open("/proc/kallsyms", "r") 20 f = open("/proc/kallsyms", "r")
20 linecount = 0
21 for line in f:
22 linecount = linecount+1
23 f.seek(0)
24 except: 21 except:
25 return 22 return
26 23
27
28 j = 0
29 for line in f: 24 for line in f:
30 loc = int(line.split()[0], 16) 25 loc = int(line.split()[0], 16)
31 name = line.split()[2] 26 name = line.split()[2]
32 j = j +1 27 kallsyms.append((loc, name))
33 if ((j % 100) == 0):
34 print "\r" + str(j) + "/" + str(linecount),
35 kallsyms.append({ 'loc': loc, 'name' : name})
36
37 print "\r" + str(j) + "/" + str(linecount)
38 kallsyms.sort() 28 kallsyms.sort()
39 return
40 29
41def get_sym(sloc): 30def get_sym(sloc):
42 loc = int(sloc) 31 loc = int(sloc)
43 for i in kallsyms: 32
44 if (i['loc'] >= loc): 33 # Invariant: kallsyms[i][0] <= loc for all 0 <= i <= start
45 return (i['name'], i['loc']-loc) 34 # kallsyms[i][0] > loc for all end <= i < len(kallsyms)
46 return (None, 0) 35 start, end = -1, len(kallsyms)
36 while end != start + 1:
37 pivot = (start + end) // 2
38 if loc < kallsyms[pivot][0]:
39 end = pivot
40 else:
41 start = pivot
42
43 # Now (start == -1 or kallsyms[start][0] <= loc)
44 # and (start == len(kallsyms) - 1 or loc < kallsyms[start + 1][0])
45 if start >= 0:
46 symloc, name = kallsyms[start]
47 return (name, loc - symloc)
48 else:
49 return (None, 0)
47 50
48def print_drop_table(): 51def print_drop_table():
49 print "%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT") 52 print "%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT")
@@ -64,7 +67,7 @@ def trace_end():
64 67
65# called from perf, when it finds a correspoinding event 68# called from perf, when it finds a correspoinding event
66def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, 69def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm,
67 skbaddr, protocol, location): 70 skbaddr, location, protocol):
68 slocation = str(location) 71 slocation = str(location)
69 try: 72 try:
70 drop_log[slocation] = drop_log[slocation] + 1 73 drop_log[slocation] = drop_log[slocation] + 1
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index 25638a986257..00218f503b2e 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -19,6 +19,11 @@
19 * permissions. All the event text files are stored there. 19 * permissions. All the event text files are stored there.
20 */ 20 */
21 21
22/*
23 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
24 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
25 */
26#define __SANE_USERSPACE_TYPES__
22#include <stdlib.h> 27#include <stdlib.h>
23#include <stdio.h> 28#include <stdio.h>
24#include <inttypes.h> 29#include <inttypes.h>
@@ -33,8 +38,6 @@
33 38
34extern int verbose; 39extern int verbose;
35 40
36bool test_attr__enabled;
37
38static char *dir; 41static char *dir;
39 42
40void test_attr__init(void) 43void test_attr__init(void)
@@ -144,10 +147,15 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
144 147
145static int run_dir(const char *d, const char *perf) 148static int run_dir(const char *d, const char *perf)
146{ 149{
150 char v[] = "-vvvvv";
151 int vcnt = min(verbose, (int) sizeof(v) - 1);
147 char cmd[3*PATH_MAX]; 152 char cmd[3*PATH_MAX];
148 153
149 snprintf(cmd, 3*PATH_MAX, "python %s/attr.py -d %s/attr/ -p %s %s", 154 if (verbose)
150 d, d, perf, verbose ? "-v" : ""); 155 vcnt++;
156
157 snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s",
158 d, d, perf, vcnt, v);
151 159
152 return system(cmd); 160 return system(cmd);
153} 161}
@@ -170,6 +178,6 @@ int test__attr(void)
170 !lstat(path_perf, &st)) 178 !lstat(path_perf, &st))
171 return run_dir(path_dir, path_perf); 179 return run_dir(path_dir, path_perf);
172 180
173 fprintf(stderr, " (ommitted)"); 181 fprintf(stderr, " (omitted)");
174 return 0; 182 return 0;
175} 183}
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py
index e702b82dcb86..c9b4b6269b51 100644
--- a/tools/perf/tests/attr.py
+++ b/tools/perf/tests/attr.py
@@ -24,6 +24,7 @@ class Unsup(Exception):
24 24
25class Event(dict): 25class Event(dict):
26 terms = [ 26 terms = [
27 'cpu',
27 'flags', 28 'flags',
28 'type', 29 'type',
29 'size', 30 'size',
@@ -68,7 +69,7 @@ class Event(dict):
68 self[key] = val 69 self[key] = val
69 70
70 def __init__(self, name, data, base): 71 def __init__(self, name, data, base):
71 log.info(" Event %s" % name); 72 log.debug(" Event %s" % name);
72 self.name = name; 73 self.name = name;
73 self.group = '' 74 self.group = ''
74 self.add(base) 75 self.add(base)
@@ -97,6 +98,14 @@ class Event(dict):
97 return False 98 return False
98 return True 99 return True
99 100
101 def diff(self, other):
102 for t in Event.terms:
103 if not self.has_key(t) or not other.has_key(t):
104 continue
105 if not self.compare_data(self[t], other[t]):
106 log.warning("expected %s=%s, got %s" % (t, self[t], other[t]))
107
108
100# Test file description needs to have following sections: 109# Test file description needs to have following sections:
101# [config] 110# [config]
102# - just single instance in file 111# - just single instance in file
@@ -128,7 +137,7 @@ class Test(object):
128 137
129 self.expect = {} 138 self.expect = {}
130 self.result = {} 139 self.result = {}
131 log.info(" loading expected events"); 140 log.debug(" loading expected events");
132 self.load_events(path, self.expect) 141 self.load_events(path, self.expect)
133 142
134 def is_event(self, name): 143 def is_event(self, name):
@@ -164,7 +173,7 @@ class Test(object):
164 self.perf, self.command, tempdir, self.args) 173 self.perf, self.command, tempdir, self.args)
165 ret = os.WEXITSTATUS(os.system(cmd)) 174 ret = os.WEXITSTATUS(os.system(cmd))
166 175
167 log.info(" running '%s' ret %d " % (cmd, ret)) 176 log.info(" '%s' ret %d " % (cmd, ret))
168 177
169 if ret != int(self.ret): 178 if ret != int(self.ret):
170 raise Unsup(self) 179 raise Unsup(self)
@@ -172,7 +181,7 @@ class Test(object):
172 def compare(self, expect, result): 181 def compare(self, expect, result):
173 match = {} 182 match = {}
174 183
175 log.info(" compare"); 184 log.debug(" compare");
176 185
177 # For each expected event find all matching 186 # For each expected event find all matching
178 # events in result. Fail if there's not any. 187 # events in result. Fail if there's not any.
@@ -187,10 +196,11 @@ class Test(object):
187 else: 196 else:
188 log.debug(" ->FAIL"); 197 log.debug(" ->FAIL");
189 198
190 log.info(" match: [%s] matches %s" % (exp_name, str(exp_list))) 199 log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list)))
191 200
192 # we did not any matching event - fail 201 # we did not any matching event - fail
193 if (not exp_list): 202 if (not exp_list):
203 exp_event.diff(res_event)
194 raise Fail(self, 'match failure'); 204 raise Fail(self, 'match failure');
195 205
196 match[exp_name] = exp_list 206 match[exp_name] = exp_list
@@ -208,10 +218,10 @@ class Test(object):
208 if res_group not in match[group]: 218 if res_group not in match[group]:
209 raise Fail(self, 'group failure') 219 raise Fail(self, 'group failure')
210 220
211 log.info(" group: [%s] matches group leader %s" % 221 log.debug(" group: [%s] matches group leader %s" %
212 (exp_name, str(match[group]))) 222 (exp_name, str(match[group])))
213 223
214 log.info(" matched") 224 log.debug(" matched")
215 225
216 def resolve_groups(self, events): 226 def resolve_groups(self, events):
217 for name, event in events.items(): 227 for name, event in events.items():
@@ -233,7 +243,7 @@ class Test(object):
233 self.run_cmd(tempdir); 243 self.run_cmd(tempdir);
234 244
235 # load events expectation for the test 245 # load events expectation for the test
236 log.info(" loading result events"); 246 log.debug(" loading result events");
237 for f in glob.glob(tempdir + '/event*'): 247 for f in glob.glob(tempdir + '/event*'):
238 self.load_events(f, self.result); 248 self.load_events(f, self.result);
239 249
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
index f1485d8e6a0b..e9bd6391f2ae 100644
--- a/tools/perf/tests/attr/base-record
+++ b/tools/perf/tests/attr/base-record
@@ -2,12 +2,13 @@
2fd=1 2fd=1
3group_fd=-1 3group_fd=-1
4flags=0 4flags=0
5cpu=*
5type=0|1 6type=0|1
6size=96 7size=96
7config=0 8config=0
8sample_period=4000 9sample_period=4000
9sample_type=263 10sample_type=263
10read_format=7 11read_format=0
11disabled=1 12disabled=1
12inherit=1 13inherit=1
13pinned=0 14pinned=0
@@ -26,8 +27,8 @@ watermark=0
26precise_ip=0 27precise_ip=0
27mmap_data=0 28mmap_data=0
28sample_id_all=1 29sample_id_all=1
29exclude_host=0 30exclude_host=0|1
30exclude_guest=1 31exclude_guest=0|1
31exclude_callchain_kernel=0 32exclude_callchain_kernel=0
32exclude_callchain_user=0 33exclude_callchain_user=0
33wakeup_events=0 34wakeup_events=0
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat
index 4bd79a82784f..91cd48b399f3 100644
--- a/tools/perf/tests/attr/base-stat
+++ b/tools/perf/tests/attr/base-stat
@@ -2,6 +2,7 @@
2fd=1 2fd=1
3group_fd=-1 3group_fd=-1
4flags=0 4flags=0
5cpu=*
5type=0 6type=0
6size=96 7size=96
7config=0 8config=0
@@ -26,8 +27,8 @@ watermark=0
26precise_ip=0 27precise_ip=0
27mmap_data=0 28mmap_data=0
28sample_id_all=0 29sample_id_all=0
29exclude_host=0 30exclude_host=0|1
30exclude_guest=1 31exclude_guest=0|1
31exclude_callchain_kernel=0 32exclude_callchain_kernel=0
32exclude_callchain_user=0 33exclude_callchain_user=0
33wakeup_events=0 34wakeup_events=0
diff --git a/tools/perf/tests/attr/test-record-C0 b/tools/perf/tests/attr/test-record-C0
new file mode 100644
index 000000000000..d6a7e43f61b3
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-C0
@@ -0,0 +1,13 @@
1[config]
2command = record
3args = -C 0 kill >/dev/null 2>&1
4
5[event:base-record]
6cpu=0
7
8# no enable on exec for CPU attached
9enable_on_exec=0
10
11# PERF_SAMPLE_IP | PERF_SAMPLE_TID PERF_SAMPLE_TIME | # PERF_SAMPLE_PERIOD
12# + PERF_SAMPLE_CPU added by -C 0
13sample_type=391
diff --git a/tools/perf/tests/attr/test-record-data b/tools/perf/tests/attr/test-record-data
index 6627c3e7534a..716e143b5291 100644
--- a/tools/perf/tests/attr/test-record-data
+++ b/tools/perf/tests/attr/test-record-data
@@ -4,5 +4,8 @@ args = -d kill >/dev/null 2>&1
4 4
5[event:base-record] 5[event:base-record]
6sample_period=4000 6sample_period=4000
7sample_type=271 7
8# sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
9# PERF_SAMPLE_ADDR | PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC
10sample_type=33039
8mmap_data=1 11mmap_data=1
diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group
index a6599e9a19d3..57739cacdb2a 100644
--- a/tools/perf/tests/attr/test-record-group
+++ b/tools/perf/tests/attr/test-record-group
@@ -6,12 +6,14 @@ args = --group -e cycles,instructions kill >/dev/null 2>&1
6fd=1 6fd=1
7group_fd=-1 7group_fd=-1
8sample_type=327 8sample_type=327
9read_format=4
9 10
10[event-2:base-record] 11[event-2:base-record]
11fd=2 12fd=2
12group_fd=1 13group_fd=1
13config=1 14config=1
14sample_type=327 15sample_type=327
16read_format=4
15mmap=0 17mmap=0
16comm=0 18comm=0
17enable_on_exec=0 19enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1
index 5a8359da38af..c5548d054aff 100644
--- a/tools/perf/tests/attr/test-record-group1
+++ b/tools/perf/tests/attr/test-record-group1
@@ -1,11 +1,12 @@
1[config] 1[config]
2command = record 2command = record
3args = -e '{cycles,instructions}' kill >/tmp/krava 2>&1 3args = -e '{cycles,instructions}' kill >/dev/null 2>&1
4 4
5[event-1:base-record] 5[event-1:base-record]
6fd=1 6fd=1
7group_fd=-1 7group_fd=-1
8sample_type=327 8sample_type=327
9read_format=4
9 10
10[event-2:base-record] 11[event-2:base-record]
11fd=2 12fd=2
@@ -13,6 +14,7 @@ group_fd=1
13type=0 14type=0
14config=1 15config=1
15sample_type=327 16sample_type=327
17read_format=4
16mmap=0 18mmap=0
17comm=0 19comm=0
18enable_on_exec=0 20enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-stat-C0 b/tools/perf/tests/attr/test-stat-C0
new file mode 100644
index 000000000000..aa835950751f
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-C0
@@ -0,0 +1,9 @@
1[config]
2command = stat
3args = -e cycles -C 0 kill >/dev/null 2>&1
4ret = 1
5
6[event:base-stat]
7# events are enabled by default when attached to cpu
8disabled=0
9enable_on_exec=0
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
new file mode 100644
index 000000000000..aba095489193
--- /dev/null
+++ b/tools/perf/tests/bp_signal.c
@@ -0,0 +1,192 @@
1/*
2 * Inspired by breakpoint overflow test done by
3 * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests
4 * (git://github.com/deater/perf_event_tests)
5 */
6
7/*
8 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
9 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
10 */
11#define __SANE_USERSPACE_TYPES__
12
13#include <stdlib.h>
14#include <stdio.h>
15#include <unistd.h>
16#include <string.h>
17#include <sys/ioctl.h>
18#include <time.h>
19#include <fcntl.h>
20#include <signal.h>
21#include <sys/mman.h>
22#include <linux/compiler.h>
23#include <linux/hw_breakpoint.h>
24
25#include "tests.h"
26#include "debug.h"
27#include "perf.h"
28
29static int fd1;
30static int fd2;
31static int overflows;
32
33__attribute__ ((noinline))
34static int test_function(void)
35{
36 return time(NULL);
37}
38
39static void sig_handler(int signum __maybe_unused,
40 siginfo_t *oh __maybe_unused,
41 void *uc __maybe_unused)
42{
43 overflows++;
44
45 if (overflows > 10) {
46 /*
47 * This should be executed only once during
48 * this test, if we are here for the 10th
49 * time, consider this the recursive issue.
50 *
51 * We can get out of here by disable events,
52 * so no new SIGIO is delivered.
53 */
54 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
55 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
56 }
57}
58
59static int bp_event(void *fn, int setup_signal)
60{
61 struct perf_event_attr pe;
62 int fd;
63
64 memset(&pe, 0, sizeof(struct perf_event_attr));
65 pe.type = PERF_TYPE_BREAKPOINT;
66 pe.size = sizeof(struct perf_event_attr);
67
68 pe.config = 0;
69 pe.bp_type = HW_BREAKPOINT_X;
70 pe.bp_addr = (unsigned long) fn;
71 pe.bp_len = sizeof(long);
72
73 pe.sample_period = 1;
74 pe.sample_type = PERF_SAMPLE_IP;
75 pe.wakeup_events = 1;
76
77 pe.disabled = 1;
78 pe.exclude_kernel = 1;
79 pe.exclude_hv = 1;
80
81 fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
82 if (fd < 0) {
83 pr_debug("failed opening event %llx\n", pe.config);
84 return TEST_FAIL;
85 }
86
87 if (setup_signal) {
88 fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
89 fcntl(fd, F_SETSIG, SIGIO);
90 fcntl(fd, F_SETOWN, getpid());
91 }
92
93 ioctl(fd, PERF_EVENT_IOC_RESET, 0);
94
95 return fd;
96}
97
98static long long bp_count(int fd)
99{
100 long long count;
101 int ret;
102
103 ret = read(fd, &count, sizeof(long long));
104 if (ret != sizeof(long long)) {
105 pr_debug("failed to read: %d\n", ret);
106 return TEST_FAIL;
107 }
108
109 return count;
110}
111
112int test__bp_signal(void)
113{
114 struct sigaction sa;
115 long long count1, count2;
116
117 /* setup SIGIO signal handler */
118 memset(&sa, 0, sizeof(struct sigaction));
119 sa.sa_sigaction = (void *) sig_handler;
120 sa.sa_flags = SA_SIGINFO;
121
122 if (sigaction(SIGIO, &sa, NULL) < 0) {
123 pr_debug("failed setting up signal handler\n");
124 return TEST_FAIL;
125 }
126
127 /*
128 * We create following events:
129 *
130 * fd1 - breakpoint event on test_function with SIGIO
131 * signal configured. We should get signal
132 * notification each time the breakpoint is hit
133 *
134 * fd2 - breakpoint event on sig_handler without SIGIO
135 * configured.
136 *
137 * Following processing should happen:
138 * - execute test_function
139 * - fd1 event breakpoint hit -> count1 == 1
140 * - SIGIO is delivered -> overflows == 1
141 * - fd2 event breakpoint hit -> count2 == 1
142 *
143 * The test case check following error conditions:
144 * - we get stuck in signal handler because of debug
145 * exception being triggered receursively due to
146 * the wrong RF EFLAG management
147 *
148 * - we never trigger the sig_handler breakpoint due
149 * to the rong RF EFLAG management
150 *
151 */
152
153 fd1 = bp_event(test_function, 1);
154 fd2 = bp_event(sig_handler, 0);
155
156 ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
157 ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
158
159 /*
160 * Kick off the test by trigering 'fd1'
161 * breakpoint.
162 */
163 test_function();
164
165 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
166 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
167
168 count1 = bp_count(fd1);
169 count2 = bp_count(fd2);
170
171 close(fd1);
172 close(fd2);
173
174 pr_debug("count1 %lld, count2 %lld, overflow %d\n",
175 count1, count2, overflows);
176
177 if (count1 != 1) {
178 if (count1 == 11)
179 pr_debug("failed: RF EFLAG recursion issue detected\n");
180 else
181 pr_debug("failed: wrong count for bp1%lld\n", count1);
182 }
183
184 if (overflows != 1)
185 pr_debug("failed: wrong overflow hit\n");
186
187 if (count2 != 1)
188 pr_debug("failed: wrong count for bp2\n");
189
190 return count1 == 1 && overflows == 1 && count2 == 1 ?
191 TEST_OK : TEST_FAIL;
192}
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
new file mode 100644
index 000000000000..44ac82179708
--- /dev/null
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -0,0 +1,132 @@
1/*
2 * Originally done by Vince Weaver <vincent.weaver@maine.edu> for
3 * perf_event_tests (git://github.com/deater/perf_event_tests)
4 */
5
6/*
7 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
8 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
9 */
10#define __SANE_USERSPACE_TYPES__
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <unistd.h>
15#include <string.h>
16#include <sys/ioctl.h>
17#include <time.h>
18#include <fcntl.h>
19#include <signal.h>
20#include <sys/mman.h>
21#include <linux/compiler.h>
22#include <linux/hw_breakpoint.h>
23
24#include "tests.h"
25#include "debug.h"
26#include "perf.h"
27
28static int overflows;
29
30__attribute__ ((noinline))
31static int test_function(void)
32{
33 return time(NULL);
34}
35
36static void sig_handler(int signum __maybe_unused,
37 siginfo_t *oh __maybe_unused,
38 void *uc __maybe_unused)
39{
40 overflows++;
41}
42
43static long long bp_count(int fd)
44{
45 long long count;
46 int ret;
47
48 ret = read(fd, &count, sizeof(long long));
49 if (ret != sizeof(long long)) {
50 pr_debug("failed to read: %d\n", ret);
51 return TEST_FAIL;
52 }
53
54 return count;
55}
56
57#define EXECUTIONS 10000
58#define THRESHOLD 100
59
60int test__bp_signal_overflow(void)
61{
62 struct perf_event_attr pe;
63 struct sigaction sa;
64 long long count;
65 int fd, i, fails = 0;
66
67 /* setup SIGIO signal handler */
68 memset(&sa, 0, sizeof(struct sigaction));
69 sa.sa_sigaction = (void *) sig_handler;
70 sa.sa_flags = SA_SIGINFO;
71
72 if (sigaction(SIGIO, &sa, NULL) < 0) {
73 pr_debug("failed setting up signal handler\n");
74 return TEST_FAIL;
75 }
76
77 memset(&pe, 0, sizeof(struct perf_event_attr));
78 pe.type = PERF_TYPE_BREAKPOINT;
79 pe.size = sizeof(struct perf_event_attr);
80
81 pe.config = 0;
82 pe.bp_type = HW_BREAKPOINT_X;
83 pe.bp_addr = (unsigned long) test_function;
84 pe.bp_len = sizeof(long);
85
86 pe.sample_period = THRESHOLD;
87 pe.sample_type = PERF_SAMPLE_IP;
88 pe.wakeup_events = 1;
89
90 pe.disabled = 1;
91 pe.exclude_kernel = 1;
92 pe.exclude_hv = 1;
93
94 fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
95 if (fd < 0) {
96 pr_debug("failed opening event %llx\n", pe.config);
97 return TEST_FAIL;
98 }
99
100 fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
101 fcntl(fd, F_SETSIG, SIGIO);
102 fcntl(fd, F_SETOWN, getpid());
103
104 ioctl(fd, PERF_EVENT_IOC_RESET, 0);
105 ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
106
107 for (i = 0; i < EXECUTIONS; i++)
108 test_function();
109
110 ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
111
112 count = bp_count(fd);
113
114 close(fd);
115
116 pr_debug("count %lld, overflow %d\n",
117 count, overflows);
118
119 if (count != EXECUTIONS) {
120 pr_debug("\tWrong number of executions %lld != %d\n",
121 count, EXECUTIONS);
122 fails++;
123 }
124
125 if (overflows != EXECUTIONS / THRESHOLD) {
126 pr_debug("\tWrong number of overflows %d != %d\n",
127 overflows, EXECUTIONS / THRESHOLD);
128 fails++;
129 }
130
131 return fails ? TEST_FAIL : TEST_OK;
132}
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 186f67535494..35b45f1466b5 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -4,6 +4,7 @@
4 * Builtin regression testing command: ever growing number of sanity tests 4 * Builtin regression testing command: ever growing number of sanity tests
5 */ 5 */
6#include "builtin.h" 6#include "builtin.h"
7#include "intlist.h"
7#include "tests.h" 8#include "tests.h"
8#include "debug.h" 9#include "debug.h"
9#include "color.h" 10#include "color.h"
@@ -69,6 +70,30 @@ static struct test {
69 .func = test__attr, 70 .func = test__attr,
70 }, 71 },
71 { 72 {
73 .desc = "Test matching and linking multiple hists",
74 .func = test__hists_link,
75 },
76 {
77 .desc = "Try 'use perf' in python, checking link problems",
78 .func = test__python_use,
79 },
80 {
81 .desc = "Test breakpoint overflow signal handler",
82 .func = test__bp_signal,
83 },
84 {
85 .desc = "Test breakpoint overflow sampling",
86 .func = test__bp_signal_overflow,
87 },
88 {
89 .desc = "Test number of exit event of a simple workload",
90 .func = test__task_exit,
91 },
92 {
93 .desc = "Test software clock events have valid period values",
94 .func = test__sw_clock_freq,
95 },
96 {
72 .func = NULL, 97 .func = NULL,
73 }, 98 },
74}; 99};
@@ -97,7 +122,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
97 return false; 122 return false;
98} 123}
99 124
100static int __cmd_test(int argc, const char *argv[]) 125static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
101{ 126{
102 int i = 0; 127 int i = 0;
103 int width = 0; 128 int width = 0;
@@ -118,13 +143,28 @@ static int __cmd_test(int argc, const char *argv[])
118 continue; 143 continue;
119 144
120 pr_info("%2d: %-*s:", i, width, tests[curr].desc); 145 pr_info("%2d: %-*s:", i, width, tests[curr].desc);
146
147 if (intlist__find(skiplist, i)) {
148 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
149 continue;
150 }
151
121 pr_debug("\n--- start ---\n"); 152 pr_debug("\n--- start ---\n");
122 err = tests[curr].func(); 153 err = tests[curr].func();
123 pr_debug("---- end ----\n%s:", tests[curr].desc); 154 pr_debug("---- end ----\n%s:", tests[curr].desc);
124 if (err) 155
125 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); 156 switch (err) {
126 else 157 case TEST_OK:
127 pr_info(" Ok\n"); 158 pr_info(" Ok\n");
159 break;
160 case TEST_SKIP:
161 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
162 break;
163 case TEST_FAIL:
164 default:
165 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
166 break;
167 }
128 } 168 }
129 169
130 return 0; 170 return 0;
@@ -152,11 +192,14 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
152 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", 192 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
153 NULL, 193 NULL,
154 }; 194 };
195 const char *skip = NULL;
155 const struct option test_options[] = { 196 const struct option test_options[] = {
197 OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
156 OPT_INCR('v', "verbose", &verbose, 198 OPT_INCR('v', "verbose", &verbose,
157 "be more verbose (show symbol address, etc)"), 199 "be more verbose (show symbol address, etc)"),
158 OPT_END() 200 OPT_END()
159 }; 201 };
202 struct intlist *skiplist = NULL;
160 203
161 argc = parse_options(argc, argv, test_options, test_usage, 0); 204 argc = parse_options(argc, argv, test_options, test_usage, 0);
162 if (argc >= 1 && !strcmp(argv[0], "list")) 205 if (argc >= 1 && !strcmp(argv[0], "list"))
@@ -169,5 +212,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
169 if (symbol__init() < 0) 212 if (symbol__init() < 0)
170 return -1; 213 return -1;
171 214
172 return __cmd_test(argc, argv); 215 if (skip != NULL)
216 skiplist = intlist__new(skip);
217
218 return __cmd_test(argc, argv, skiplist);
173} 219}
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index e61fc828a158..0197bda9c461 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -8,7 +8,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
8 char name[128]; 8 char name[128];
9 int type, op, err = 0, ret = 0, i, idx; 9 int type, op, err = 0, ret = 0, i, idx;
10 struct perf_evsel *evsel; 10 struct perf_evsel *evsel;
11 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 11 struct perf_evlist *evlist = perf_evlist__new();
12 12
13 if (evlist == NULL) 13 if (evlist == NULL)
14 return -ENOMEM; 14 return -ENOMEM;
@@ -22,7 +22,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
22 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 22 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
23 __perf_evsel__hw_cache_type_op_res_name(type, op, i, 23 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
24 name, sizeof(name)); 24 name, sizeof(name));
25 err = parse_events(evlist, name, 0); 25 err = parse_events(evlist, name);
26 if (err) 26 if (err)
27 ret = err; 27 ret = err;
28 } 28 }
@@ -64,13 +64,13 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
64{ 64{
65 int i, err; 65 int i, err;
66 struct perf_evsel *evsel; 66 struct perf_evsel *evsel;
67 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 67 struct perf_evlist *evlist = perf_evlist__new();
68 68
69 if (evlist == NULL) 69 if (evlist == NULL)
70 return -ENOMEM; 70 return -ENOMEM;
71 71
72 for (i = 0; i < nr_names; ++i) { 72 for (i = 0; i < nr_names; ++i) {
73 err = parse_events(evlist, names[i], 0); 73 err = parse_events(evlist, names[i]);
74 if (err) { 74 if (err) {
75 pr_debug("failed to parse event '%s', err %d\n", 75 pr_debug("failed to parse event '%s', err %d\n",
76 names[i], err); 76 names[i], err);
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
new file mode 100644
index 000000000000..89085a9615e2
--- /dev/null
+++ b/tools/perf/tests/hists_link.c
@@ -0,0 +1,500 @@
1#include "perf.h"
2#include "tests.h"
3#include "debug.h"
4#include "symbol.h"
5#include "sort.h"
6#include "evsel.h"
7#include "evlist.h"
8#include "machine.h"
9#include "thread.h"
10#include "parse-events.h"
11
12static struct {
13 u32 pid;
14 const char *comm;
15} fake_threads[] = {
16 { 100, "perf" },
17 { 200, "perf" },
18 { 300, "bash" },
19};
20
21static struct {
22 u32 pid;
23 u64 start;
24 const char *filename;
25} fake_mmap_info[] = {
26 { 100, 0x40000, "perf" },
27 { 100, 0x50000, "libc" },
28 { 100, 0xf0000, "[kernel]" },
29 { 200, 0x40000, "perf" },
30 { 200, 0x50000, "libc" },
31 { 200, 0xf0000, "[kernel]" },
32 { 300, 0x40000, "bash" },
33 { 300, 0x50000, "libc" },
34 { 300, 0xf0000, "[kernel]" },
35};
36
37struct fake_sym {
38 u64 start;
39 u64 length;
40 const char *name;
41};
42
43static struct fake_sym perf_syms[] = {
44 { 700, 100, "main" },
45 { 800, 100, "run_command" },
46 { 900, 100, "cmd_record" },
47};
48
49static struct fake_sym bash_syms[] = {
50 { 700, 100, "main" },
51 { 800, 100, "xmalloc" },
52 { 900, 100, "xfree" },
53};
54
55static struct fake_sym libc_syms[] = {
56 { 700, 100, "malloc" },
57 { 800, 100, "free" },
58 { 900, 100, "realloc" },
59};
60
61static struct fake_sym kernel_syms[] = {
62 { 700, 100, "schedule" },
63 { 800, 100, "page_fault" },
64 { 900, 100, "sys_perf_event_open" },
65};
66
67static struct {
68 const char *dso_name;
69 struct fake_sym *syms;
70 size_t nr_syms;
71} fake_symbols[] = {
72 { "perf", perf_syms, ARRAY_SIZE(perf_syms) },
73 { "bash", bash_syms, ARRAY_SIZE(bash_syms) },
74 { "libc", libc_syms, ARRAY_SIZE(libc_syms) },
75 { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) },
76};
77
78static struct machine *setup_fake_machine(struct machines *machines)
79{
80 struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
81 size_t i;
82
83 if (machine == NULL) {
84 pr_debug("Not enough memory for machine setup\n");
85 return NULL;
86 }
87
88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
89 struct thread *thread;
90
91 thread = machine__findnew_thread(machine, fake_threads[i].pid);
92 if (thread == NULL)
93 goto out;
94
95 thread__set_comm(thread, fake_threads[i].comm);
96 }
97
98 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
99 union perf_event fake_mmap_event = {
100 .mmap = {
101 .header = { .misc = PERF_RECORD_MISC_USER, },
102 .pid = fake_mmap_info[i].pid,
103 .start = fake_mmap_info[i].start,
104 .len = 0x1000ULL,
105 .pgoff = 0ULL,
106 },
107 };
108
109 strcpy(fake_mmap_event.mmap.filename,
110 fake_mmap_info[i].filename);
111
112 machine__process_mmap_event(machine, &fake_mmap_event);
113 }
114
115 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
116 size_t k;
117 struct dso *dso;
118
119 dso = __dsos__findnew(&machine->user_dsos,
120 fake_symbols[i].dso_name);
121 if (dso == NULL)
122 goto out;
123
124 /* emulate dso__load() */
125 dso__set_loaded(dso, MAP__FUNCTION);
126
127 for (k = 0; k < fake_symbols[i].nr_syms; k++) {
128 struct symbol *sym;
129 struct fake_sym *fsym = &fake_symbols[i].syms[k];
130
131 sym = symbol__new(fsym->start, fsym->length,
132 STB_GLOBAL, fsym->name);
133 if (sym == NULL)
134 goto out;
135
136 symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
137 }
138 }
139
140 return machine;
141
142out:
143 pr_debug("Not enough memory for machine setup\n");
144 machine__delete_threads(machine);
145 machine__delete(machine);
146 return NULL;
147}
148
149struct sample {
150 u32 pid;
151 u64 ip;
152 struct thread *thread;
153 struct map *map;
154 struct symbol *sym;
155};
156
157static struct sample fake_common_samples[] = {
158 /* perf [kernel] schedule() */
159 { .pid = 100, .ip = 0xf0000 + 700, },
160 /* perf [perf] main() */
161 { .pid = 200, .ip = 0x40000 + 700, },
162 /* perf [perf] cmd_record() */
163 { .pid = 200, .ip = 0x40000 + 900, },
164 /* bash [bash] xmalloc() */
165 { .pid = 300, .ip = 0x40000 + 800, },
166 /* bash [libc] malloc() */
167 { .pid = 300, .ip = 0x50000 + 700, },
168};
169
170static struct sample fake_samples[][5] = {
171 {
172 /* perf [perf] run_command() */
173 { .pid = 100, .ip = 0x40000 + 800, },
174 /* perf [libc] malloc() */
175 { .pid = 100, .ip = 0x50000 + 700, },
176 /* perf [kernel] page_fault() */
177 { .pid = 100, .ip = 0xf0000 + 800, },
178 /* perf [kernel] sys_perf_event_open() */
179 { .pid = 200, .ip = 0xf0000 + 900, },
180 /* bash [libc] free() */
181 { .pid = 300, .ip = 0x50000 + 800, },
182 },
183 {
184 /* perf [libc] free() */
185 { .pid = 200, .ip = 0x50000 + 800, },
186 /* bash [libc] malloc() */
187 { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */
188 /* bash [bash] xfee() */
189 { .pid = 300, .ip = 0x40000 + 900, },
190 /* bash [libc] realloc() */
191 { .pid = 300, .ip = 0x50000 + 900, },
192 /* bash [kernel] page_fault() */
193 { .pid = 300, .ip = 0xf0000 + 800, },
194 },
195};
196
197static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
198{
199 struct perf_evsel *evsel;
200 struct addr_location al;
201 struct hist_entry *he;
202 struct perf_sample sample = { .cpu = 0, };
203 size_t i = 0, k;
204
205 /*
206 * each evsel will have 10 samples - 5 common and 5 distinct.
207 * However the second evsel also has a collapsed entry for
208 * "bash [libc] malloc" so total 9 entries will be in the tree.
209 */
210 list_for_each_entry(evsel, &evlist->entries, node) {
211 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
212 const union perf_event event = {
213 .ip = {
214 .header = {
215 .misc = PERF_RECORD_MISC_USER,
216 },
217 .pid = fake_common_samples[k].pid,
218 .ip = fake_common_samples[k].ip,
219 },
220 };
221
222 if (perf_event__preprocess_sample(&event, machine, &al,
223 &sample, 0) < 0)
224 goto out;
225
226 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
227 if (he == NULL)
228 goto out;
229
230 fake_common_samples[k].thread = al.thread;
231 fake_common_samples[k].map = al.map;
232 fake_common_samples[k].sym = al.sym;
233 }
234
235 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
236 const union perf_event event = {
237 .ip = {
238 .header = {
239 .misc = PERF_RECORD_MISC_USER,
240 },
241 .pid = fake_samples[i][k].pid,
242 .ip = fake_samples[i][k].ip,
243 },
244 };
245
246 if (perf_event__preprocess_sample(&event, machine, &al,
247 &sample, 0) < 0)
248 goto out;
249
250 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
251 if (he == NULL)
252 goto out;
253
254 fake_samples[i][k].thread = al.thread;
255 fake_samples[i][k].map = al.map;
256 fake_samples[i][k].sym = al.sym;
257 }
258 i++;
259 }
260
261 return 0;
262
263out:
264 pr_debug("Not enough memory for adding a hist entry\n");
265 return -1;
266}
267
268static int find_sample(struct sample *samples, size_t nr_samples,
269 struct thread *t, struct map *m, struct symbol *s)
270{
271 while (nr_samples--) {
272 if (samples->thread == t && samples->map == m &&
273 samples->sym == s)
274 return 1;
275 samples++;
276 }
277 return 0;
278}
279
280static int __validate_match(struct hists *hists)
281{
282 size_t count = 0;
283 struct rb_root *root;
284 struct rb_node *node;
285
286 /*
287 * Only entries from fake_common_samples should have a pair.
288 */
289 if (sort__need_collapse)
290 root = &hists->entries_collapsed;
291 else
292 root = hists->entries_in;
293
294 node = rb_first(root);
295 while (node) {
296 struct hist_entry *he;
297
298 he = rb_entry(node, struct hist_entry, rb_node_in);
299
300 if (hist_entry__has_pairs(he)) {
301 if (find_sample(fake_common_samples,
302 ARRAY_SIZE(fake_common_samples),
303 he->thread, he->ms.map, he->ms.sym)) {
304 count++;
305 } else {
306 pr_debug("Can't find the matched entry\n");
307 return -1;
308 }
309 }
310
311 node = rb_next(node);
312 }
313
314 if (count != ARRAY_SIZE(fake_common_samples)) {
315 pr_debug("Invalid count for matched entries: %zd of %zd\n",
316 count, ARRAY_SIZE(fake_common_samples));
317 return -1;
318 }
319
320 return 0;
321}
322
323static int validate_match(struct hists *leader, struct hists *other)
324{
325 return __validate_match(leader) || __validate_match(other);
326}
327
328static int __validate_link(struct hists *hists, int idx)
329{
330 size_t count = 0;
331 size_t count_pair = 0;
332 size_t count_dummy = 0;
333 struct rb_root *root;
334 struct rb_node *node;
335
336 /*
337 * Leader hists (idx = 0) will have dummy entries from other,
338 * and some entries will have no pair. However every entry
339 * in other hists should have (dummy) pair.
340 */
341 if (sort__need_collapse)
342 root = &hists->entries_collapsed;
343 else
344 root = hists->entries_in;
345
346 node = rb_first(root);
347 while (node) {
348 struct hist_entry *he;
349
350 he = rb_entry(node, struct hist_entry, rb_node_in);
351
352 if (hist_entry__has_pairs(he)) {
353 if (!find_sample(fake_common_samples,
354 ARRAY_SIZE(fake_common_samples),
355 he->thread, he->ms.map, he->ms.sym) &&
356 !find_sample(fake_samples[idx],
357 ARRAY_SIZE(fake_samples[idx]),
358 he->thread, he->ms.map, he->ms.sym)) {
359 count_dummy++;
360 }
361 count_pair++;
362 } else if (idx) {
363 pr_debug("A entry from the other hists should have pair\n");
364 return -1;
365 }
366
367 count++;
368 node = rb_next(node);
369 }
370
371 /*
372 * Note that we have a entry collapsed in the other (idx = 1) hists.
373 */
374 if (idx == 0) {
375 if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) {
376 pr_debug("Invalid count of dummy entries: %zd of %zd\n",
377 count_dummy, ARRAY_SIZE(fake_samples[1]) - 1);
378 return -1;
379 }
380 if (count != count_pair + ARRAY_SIZE(fake_samples[0])) {
381 pr_debug("Invalid count of total leader entries: %zd of %zd\n",
382 count, count_pair + ARRAY_SIZE(fake_samples[0]));
383 return -1;
384 }
385 } else {
386 if (count != count_pair) {
387 pr_debug("Invalid count of total other entries: %zd of %zd\n",
388 count, count_pair);
389 return -1;
390 }
391 if (count_dummy > 0) {
392 pr_debug("Other hists should not have dummy entries: %zd\n",
393 count_dummy);
394 return -1;
395 }
396 }
397
398 return 0;
399}
400
401static int validate_link(struct hists *leader, struct hists *other)
402{
403 return __validate_link(leader, 0) || __validate_link(other, 1);
404}
405
406static void print_hists(struct hists *hists)
407{
408 int i = 0;
409 struct rb_root *root;
410 struct rb_node *node;
411
412 if (sort__need_collapse)
413 root = &hists->entries_collapsed;
414 else
415 root = hists->entries_in;
416
417 pr_info("----- %s --------\n", __func__);
418 node = rb_first(root);
419 while (node) {
420 struct hist_entry *he;
421
422 he = rb_entry(node, struct hist_entry, rb_node_in);
423
424 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
425 i, he->thread->comm, he->ms.map->dso->short_name,
426 he->ms.sym->name, he->stat.period);
427
428 i++;
429 node = rb_next(node);
430 }
431}
432
433int test__hists_link(void)
434{
435 int err = -1;
436 struct machines machines;
437 struct machine *machine = NULL;
438 struct perf_evsel *evsel, *first;
439 struct perf_evlist *evlist = perf_evlist__new();
440
441 if (evlist == NULL)
442 return -ENOMEM;
443
444 err = parse_events(evlist, "cpu-clock");
445 if (err)
446 goto out;
447 err = parse_events(evlist, "task-clock");
448 if (err)
449 goto out;
450
451 /* default sort order (comm,dso,sym) will be used */
452 if (setup_sorting() < 0)
453 goto out;
454
455 machines__init(&machines);
456
457 /* setup threads/dso/map/symbols also */
458 machine = setup_fake_machine(&machines);
459 if (!machine)
460 goto out;
461
462 if (verbose > 1)
463 machine__fprintf(machine, stderr);
464
465 /* process sample events */
466 err = add_hist_entries(evlist, machine);
467 if (err < 0)
468 goto out;
469
470 list_for_each_entry(evsel, &evlist->entries, node) {
471 hists__collapse_resort(&evsel->hists);
472
473 if (verbose > 2)
474 print_hists(&evsel->hists);
475 }
476
477 first = perf_evlist__first(evlist);
478 evsel = perf_evlist__last(evlist);
479
480 /* match common entries */
481 hists__match(&first->hists, &evsel->hists);
482 err = validate_match(&first->hists, &evsel->hists);
483 if (err)
484 goto out;
485
486 /* link common and/or dummy entries */
487 hists__link(&first->hists, &evsel->hists);
488 err = validate_link(&first->hists, &evsel->hists);
489 if (err)
490 goto out;
491
492 err = 0;
493
494out:
495 /* tear down everything */
496 perf_evlist__delete(evlist);
497 machines__exit(&machines);
498
499 return err;
500}
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
new file mode 100644
index 000000000000..c441a2875128
--- /dev/null
+++ b/tools/perf/tests/make
@@ -0,0 +1,138 @@
1PERF := .
2MK := Makefile
3
4# standard single make variable specified
5make_clean_all := clean all
6make_python_perf_so := python/perf.so
7make_debug := DEBUG=1
8make_no_libperl := NO_LIBPERL=1
9make_no_libpython := NO_LIBPYTHON=1
10make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1
11make_no_newt := NO_NEWT=1
12make_no_slang := NO_SLANG=1
13make_no_gtk2 := NO_GTK2=1
14make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
15make_no_demangle := NO_DEMANGLE=1
16make_no_libelf := NO_LIBELF=1
17make_no_libunwind := NO_LIBUNWIND=1
18make_no_backtrace := NO_BACKTRACE=1
19make_no_libnuma := NO_LIBNUMA=1
20make_no_libaudit := NO_LIBAUDIT=1
21make_no_libbionic := NO_LIBBIONIC=1
22make_tags := tags
23make_cscope := cscope
24make_help := help
25make_doc := doc
26make_perf_o := perf.o
27make_util_map_o := util/map.o
28
29# all the NO_* variable combined
30make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
31make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
32make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
33
34# $(run) contains all available tests
35run := make_pure
36run += make_clean_all
37run += make_python_perf_so
38run += make_debug
39run += make_no_libperl
40run += make_no_libpython
41run += make_no_scripts
42run += make_no_newt
43run += make_no_slang
44run += make_no_gtk2
45run += make_no_ui
46run += make_no_demangle
47run += make_no_libelf
48run += make_no_libunwind
49run += make_no_backtrace
50run += make_no_libnuma
51run += make_no_libaudit
52run += make_no_libbionic
53run += make_tags
54run += make_cscope
55run += make_help
56run += make_doc
57run += make_perf_o
58run += make_util_map_o
59run += make_minimal
60
61# $(run_O) contains same portion of $(run) tests with '_O' attached
62# to distinguish O=... tests
63run_O := $(addsuffix _O,$(run))
64
65# disable some tests for O=...
66run_O := $(filter-out make_python_perf_so_O,$(run_O))
67
68# define test for each compile as 'test_NAME' variable
69# with the test itself as a value
70test_make_tags = test -f tags
71test_make_cscope = test -f cscope.out
72
73test_make_tags_O := $(test_make_tags)
74test_make_cscope_O := $(test_make_cscope)
75
76test_ok := true
77test_make_help := $(test_ok)
78test_make_doc := $(test_ok)
79test_make_help_O := $(test_ok)
80test_make_doc_O := $(test_ok)
81
82test_make_python_perf_so := test -f $(PERF)/python/perf.so
83
84test_make_perf_o := test -f $(PERF)/perf.o
85test_make_util_map_o := test -f $(PERF)/util/map.o
86
87# Kbuild tests only
88#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
89#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o
90#test_make_util_map_o_O := test -f $$TMP/tools/perf/util/map.o
91
92test_make_perf_o_O := true
93test_make_util_map_o_O := true
94
95test_default = test -x $(PERF)/perf
96test = $(if $(test_$1),$(test_$1),$(test_default))
97
98test_default_O = test -x $$TMP/perf
99test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
100
101all:
102
103ifdef DEBUG
104d := $(info run $(run))
105d := $(info run_O $(run_O))
106endif
107
108MAKEFLAGS := --no-print-directory
109
110clean := @(cd $(PERF); make -s -f $(MK) clean >/dev/null)
111
112$(run):
113 $(call clean)
114 @cmd="cd $(PERF) && make -f $(MK) $($@)"; \
115 echo "- $@: $$cmd" && echo $$cmd > $@ && \
116 ( eval $$cmd ) >> $@ 2>&1; \
117 echo " test: $(call test,$@)"; \
118 $(call test,$@) && \
119 rm -f $@
120
121$(run_O):
122 $(call clean)
123 @TMP=$$(mktemp -d); \
124 cmd="cd $(PERF) && make -f $(MK) $($(patsubst %_O,%,$@)) O=$$TMP"; \
125 echo "- $@: $$cmd" && echo $$cmd > $@ && \
126 ( eval $$cmd ) >> $@ 2>&1 && \
127 echo " test: $(call test_O,$@)"; \
128 $(call test_O,$@) && \
129 rm -f $@ && \
130 rm -rf $$TMP
131
132all: $(run) $(run_O)
133 @echo OK
134
135out: $(run_O)
136 @echo OK
137
138.PHONY: all $(run) $(run_O) clean
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index e1746811e14b..5b1b5aba722b 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -22,36 +22,16 @@ int test__basic_mmap(void)
22 struct thread_map *threads; 22 struct thread_map *threads;
23 struct cpu_map *cpus; 23 struct cpu_map *cpus;
24 struct perf_evlist *evlist; 24 struct perf_evlist *evlist;
25 struct perf_event_attr attr = {
26 .type = PERF_TYPE_TRACEPOINT,
27 .read_format = PERF_FORMAT_ID,
28 .sample_type = PERF_SAMPLE_ID,
29 .watermark = 0,
30 };
31 cpu_set_t cpu_set; 25 cpu_set_t cpu_set;
32 const char *syscall_names[] = { "getsid", "getppid", "getpgrp", 26 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
33 "getpgid", }; 27 "getpgid", };
34 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp, 28 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
35 (void*)getpgid }; 29 (void*)getpgid };
36#define nsyscalls ARRAY_SIZE(syscall_names) 30#define nsyscalls ARRAY_SIZE(syscall_names)
37 int ids[nsyscalls];
38 unsigned int nr_events[nsyscalls], 31 unsigned int nr_events[nsyscalls],
39 expected_nr_events[nsyscalls], i, j; 32 expected_nr_events[nsyscalls], i, j;
40 struct perf_evsel *evsels[nsyscalls], *evsel; 33 struct perf_evsel *evsels[nsyscalls], *evsel;
41 34
42 for (i = 0; i < nsyscalls; ++i) {
43 char name[64];
44
45 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
46 ids[i] = trace_event__id(name);
47 if (ids[i] < 0) {
48 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
49 return -1;
50 }
51 nr_events[i] = 0;
52 expected_nr_events[i] = random() % 257;
53 }
54
55 threads = thread_map__new(-1, getpid(), UINT_MAX); 35 threads = thread_map__new(-1, getpid(), UINT_MAX);
56 if (threads == NULL) { 36 if (threads == NULL) {
57 pr_debug("thread_map__new\n"); 37 pr_debug("thread_map__new\n");
@@ -73,24 +53,27 @@ int test__basic_mmap(void)
73 goto out_free_cpus; 53 goto out_free_cpus;
74 } 54 }
75 55
76 evlist = perf_evlist__new(cpus, threads); 56 evlist = perf_evlist__new();
77 if (evlist == NULL) { 57 if (evlist == NULL) {
78 pr_debug("perf_evlist__new\n"); 58 pr_debug("perf_evlist__new\n");
79 goto out_free_cpus; 59 goto out_free_cpus;
80 } 60 }
81 61
82 /* anonymous union fields, can't be initialized above */ 62 perf_evlist__set_maps(evlist, cpus, threads);
83 attr.wakeup_events = 1;
84 attr.sample_period = 1;
85 63
86 for (i = 0; i < nsyscalls; ++i) { 64 for (i = 0; i < nsyscalls; ++i) {
87 attr.config = ids[i]; 65 char name[64];
88 evsels[i] = perf_evsel__new(&attr, i); 66
67 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
68 evsels[i] = perf_evsel__newtp("syscalls", name, i);
89 if (evsels[i] == NULL) { 69 if (evsels[i] == NULL) {
90 pr_debug("perf_evsel__new\n"); 70 pr_debug("perf_evsel__new\n");
91 goto out_free_evlist; 71 goto out_free_evlist;
92 } 72 }
93 73
74 evsels[i]->attr.wakeup_events = 1;
75 perf_evsel__set_sample_id(evsels[i]);
76
94 perf_evlist__add(evlist, evsels[i]); 77 perf_evlist__add(evlist, evsels[i]);
95 78
96 if (perf_evsel__open(evsels[i], cpus, threads) < 0) { 79 if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
@@ -99,6 +82,9 @@ int test__basic_mmap(void)
99 strerror(errno)); 82 strerror(errno));
100 goto out_close_fd; 83 goto out_close_fd;
101 } 84 }
85
86 nr_events[i] = 0;
87 expected_nr_events[i] = 1 + rand() % 127;
102 } 88 }
103 89
104 if (perf_evlist__mmap(evlist, 128, true) < 0) { 90 if (perf_evlist__mmap(evlist, 128, true) < 0) {
@@ -128,6 +114,7 @@ int test__basic_mmap(void)
128 goto out_munmap; 114 goto out_munmap;
129 } 115 }
130 116
117 err = -1;
131 evsel = perf_evlist__id2evsel(evlist, sample.id); 118 evsel = perf_evlist__id2evsel(evlist, sample.id);
132 if (evsel == NULL) { 119 if (evsel == NULL) {
133 pr_debug("event with id %" PRIu64 120 pr_debug("event with id %" PRIu64
@@ -137,16 +124,17 @@ int test__basic_mmap(void)
137 nr_events[evsel->idx]++; 124 nr_events[evsel->idx]++;
138 } 125 }
139 126
127 err = 0;
140 list_for_each_entry(evsel, &evlist->entries, node) { 128 list_for_each_entry(evsel, &evlist->entries, node) {
141 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { 129 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
142 pr_debug("expected %d %s events, got %d\n", 130 pr_debug("expected %d %s events, got %d\n",
143 expected_nr_events[evsel->idx], 131 expected_nr_events[evsel->idx],
144 perf_evsel__name(evsel), nr_events[evsel->idx]); 132 perf_evsel__name(evsel), nr_events[evsel->idx]);
133 err = -1;
145 goto out_munmap; 134 goto out_munmap;
146 } 135 }
147 } 136 }
148 137
149 err = 0;
150out_munmap: 138out_munmap:
151 perf_evlist__munmap(evlist); 139 perf_evlist__munmap(evlist);
152out_close_fd: 140out_close_fd:
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c
index 31072aba0d54..b0657a9ccda6 100644
--- a/tools/perf/tests/open-syscall-all-cpus.c
+++ b/tools/perf/tests/open-syscall-all-cpus.c
@@ -7,20 +7,12 @@
7int test__open_syscall_event_on_all_cpus(void) 7int test__open_syscall_event_on_all_cpus(void)
8{ 8{
9 int err = -1, fd, cpu; 9 int err = -1, fd, cpu;
10 struct thread_map *threads;
11 struct cpu_map *cpus; 10 struct cpu_map *cpus;
12 struct perf_evsel *evsel; 11 struct perf_evsel *evsel;
13 struct perf_event_attr attr;
14 unsigned int nr_open_calls = 111, i; 12 unsigned int nr_open_calls = 111, i;
15 cpu_set_t cpu_set; 13 cpu_set_t cpu_set;
16 int id = trace_event__id("sys_enter_open"); 14 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
17 15
18 if (id < 0) {
19 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
20 return -1;
21 }
22
23 threads = thread_map__new(-1, getpid(), UINT_MAX);
24 if (threads == NULL) { 16 if (threads == NULL) {
25 pr_debug("thread_map__new\n"); 17 pr_debug("thread_map__new\n");
26 return -1; 18 return -1;
@@ -32,15 +24,11 @@ int test__open_syscall_event_on_all_cpus(void)
32 goto out_thread_map_delete; 24 goto out_thread_map_delete;
33 } 25 }
34 26
35
36 CPU_ZERO(&cpu_set); 27 CPU_ZERO(&cpu_set);
37 28
38 memset(&attr, 0, sizeof(attr)); 29 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
39 attr.type = PERF_TYPE_TRACEPOINT;
40 attr.config = id;
41 evsel = perf_evsel__new(&attr, 0);
42 if (evsel == NULL) { 30 if (evsel == NULL) {
43 pr_debug("perf_evsel__new\n"); 31 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
44 goto out_thread_map_delete; 32 goto out_thread_map_delete;
45 } 33 }
46 34
@@ -110,6 +98,7 @@ int test__open_syscall_event_on_all_cpus(void)
110 } 98 }
111 } 99 }
112 100
101 perf_evsel__free_counts(evsel);
113out_close_fd: 102out_close_fd:
114 perf_evsel__close_fd(evsel, 1, threads->nr); 103 perf_evsel__close_fd(evsel, 1, threads->nr);
115out_evsel_delete: 104out_evsel_delete:
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
index 1c52fdc1164e..fc5b9fca8b47 100644
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -18,7 +18,7 @@ int test__syscall_open_tp_fields(void)
18 }; 18 };
19 const char *filename = "/etc/passwd"; 19 const char *filename = "/etc/passwd";
20 int flags = O_RDONLY | O_DIRECTORY; 20 int flags = O_RDONLY | O_DIRECTORY;
21 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 21 struct perf_evlist *evlist = perf_evlist__new();
22 struct perf_evsel *evsel; 22 struct perf_evsel *evsel;
23 int err = -1, i, nr_events = 0, nr_polls = 0; 23 int err = -1, i, nr_events = 0, nr_polls = 0;
24 24
@@ -48,13 +48,13 @@ int test__syscall_open_tp_fields(void)
48 err = perf_evlist__open(evlist); 48 err = perf_evlist__open(evlist);
49 if (err < 0) { 49 if (err < 0) {
50 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 50 pr_debug("perf_evlist__open: %s\n", strerror(errno));
51 goto out_delete_evlist; 51 goto out_delete_maps;
52 } 52 }
53 53
54 err = perf_evlist__mmap(evlist, UINT_MAX, false); 54 err = perf_evlist__mmap(evlist, UINT_MAX, false);
55 if (err < 0) { 55 if (err < 0) {
56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
57 goto out_delete_evlist; 57 goto out_close_evlist;
58 } 58 }
59 59
60 perf_evlist__enable(evlist); 60 perf_evlist__enable(evlist);
@@ -110,6 +110,10 @@ out_ok:
110 err = 0; 110 err = 0;
111out_munmap: 111out_munmap:
112 perf_evlist__munmap(evlist); 112 perf_evlist__munmap(evlist);
113out_close_evlist:
114 perf_evlist__close(evlist);
115out_delete_maps:
116 perf_evlist__delete_maps(evlist);
113out_delete_evlist: 117out_delete_evlist:
114 perf_evlist__delete(evlist); 118 perf_evlist__delete(evlist);
115out: 119out:
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c
index 98be8b518b4f..befc0671f95d 100644
--- a/tools/perf/tests/open-syscall.c
+++ b/tools/perf/tests/open-syscall.c
@@ -6,29 +6,18 @@
6int test__open_syscall_event(void) 6int test__open_syscall_event(void)
7{ 7{
8 int err = -1, fd; 8 int err = -1, fd;
9 struct thread_map *threads;
10 struct perf_evsel *evsel; 9 struct perf_evsel *evsel;
11 struct perf_event_attr attr;
12 unsigned int nr_open_calls = 111, i; 10 unsigned int nr_open_calls = 111, i;
13 int id = trace_event__id("sys_enter_open"); 11 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
14 12
15 if (id < 0) {
16 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
17 return -1;
18 }
19
20 threads = thread_map__new(-1, getpid(), UINT_MAX);
21 if (threads == NULL) { 13 if (threads == NULL) {
22 pr_debug("thread_map__new\n"); 14 pr_debug("thread_map__new\n");
23 return -1; 15 return -1;
24 } 16 }
25 17
26 memset(&attr, 0, sizeof(attr)); 18 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
27 attr.type = PERF_TYPE_TRACEPOINT;
28 attr.config = id;
29 evsel = perf_evsel__new(&attr, 0);
30 if (evsel == NULL) { 19 if (evsel == NULL) {
31 pr_debug("perf_evsel__new\n"); 20 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
32 goto out_thread_map_delete; 21 goto out_thread_map_delete;
33 } 22 }
34 23
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 32ee478905eb..0275bab4ea9e 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -3,6 +3,7 @@
3#include "evsel.h" 3#include "evsel.h"
4#include "evlist.h" 4#include "evlist.h"
5#include "sysfs.h" 5#include "sysfs.h"
6#include <lk/debugfs.h>
6#include "tests.h" 7#include "tests.h"
7#include <linux/hw_breakpoint.h> 8#include <linux/hw_breakpoint.h>
8 9
@@ -22,6 +23,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist)
22 struct perf_evsel *evsel = perf_evlist__first(evlist); 23 struct perf_evsel *evsel = perf_evlist__first(evlist);
23 24
24 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 25 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
26 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
25 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); 27 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
26 TEST_ASSERT_VAL("wrong sample_type", 28 TEST_ASSERT_VAL("wrong sample_type",
27 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); 29 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
@@ -34,6 +36,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
34 struct perf_evsel *evsel; 36 struct perf_evsel *evsel;
35 37
36 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); 38 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
39 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
37 40
38 list_for_each_entry(evsel, &evlist->entries, node) { 41 list_for_each_entry(evsel, &evlist->entries, node) {
39 TEST_ASSERT_VAL("wrong type", 42 TEST_ASSERT_VAL("wrong type",
@@ -463,10 +466,10 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist)
463 466
464static int test__checkterms_simple(struct list_head *terms) 467static int test__checkterms_simple(struct list_head *terms)
465{ 468{
466 struct parse_events__term *term; 469 struct parse_events_term *term;
467 470
468 /* config=10 */ 471 /* config=10 */
469 term = list_entry(terms->next, struct parse_events__term, list); 472 term = list_entry(terms->next, struct parse_events_term, list);
470 TEST_ASSERT_VAL("wrong type term", 473 TEST_ASSERT_VAL("wrong type term",
471 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); 474 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
472 TEST_ASSERT_VAL("wrong type val", 475 TEST_ASSERT_VAL("wrong type val",
@@ -475,7 +478,7 @@ static int test__checkterms_simple(struct list_head *terms)
475 TEST_ASSERT_VAL("wrong config", !term->config); 478 TEST_ASSERT_VAL("wrong config", !term->config);
476 479
477 /* config1 */ 480 /* config1 */
478 term = list_entry(term->list.next, struct parse_events__term, list); 481 term = list_entry(term->list.next, struct parse_events_term, list);
479 TEST_ASSERT_VAL("wrong type term", 482 TEST_ASSERT_VAL("wrong type term",
480 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); 483 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
481 TEST_ASSERT_VAL("wrong type val", 484 TEST_ASSERT_VAL("wrong type val",
@@ -484,7 +487,7 @@ static int test__checkterms_simple(struct list_head *terms)
484 TEST_ASSERT_VAL("wrong config", !term->config); 487 TEST_ASSERT_VAL("wrong config", !term->config);
485 488
486 /* config2=3 */ 489 /* config2=3 */
487 term = list_entry(term->list.next, struct parse_events__term, list); 490 term = list_entry(term->list.next, struct parse_events_term, list);
488 TEST_ASSERT_VAL("wrong type term", 491 TEST_ASSERT_VAL("wrong type term",
489 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); 492 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
490 TEST_ASSERT_VAL("wrong type val", 493 TEST_ASSERT_VAL("wrong type val",
@@ -493,7 +496,7 @@ static int test__checkterms_simple(struct list_head *terms)
493 TEST_ASSERT_VAL("wrong config", !term->config); 496 TEST_ASSERT_VAL("wrong config", !term->config);
494 497
495 /* umask=1*/ 498 /* umask=1*/
496 term = list_entry(term->list.next, struct parse_events__term, list); 499 term = list_entry(term->list.next, struct parse_events_term, list);
497 TEST_ASSERT_VAL("wrong type term", 500 TEST_ASSERT_VAL("wrong type term",
498 term->type_term == PARSE_EVENTS__TERM_TYPE_USER); 501 term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
499 TEST_ASSERT_VAL("wrong type val", 502 TEST_ASSERT_VAL("wrong type val",
@@ -509,6 +512,7 @@ static int test__group1(struct perf_evlist *evlist)
509 struct perf_evsel *evsel, *leader; 512 struct perf_evsel *evsel, *leader;
510 513
511 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); 514 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
515 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
512 516
513 /* instructions:k */ 517 /* instructions:k */
514 evsel = leader = perf_evlist__first(evlist); 518 evsel = leader = perf_evlist__first(evlist);
@@ -521,7 +525,9 @@ static int test__group1(struct perf_evlist *evlist)
521 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 525 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
522 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 526 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
523 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 527 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
524 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 528 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
529 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
530 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
525 531
526 /* cycles:upp */ 532 /* cycles:upp */
527 evsel = perf_evsel__next(evsel); 533 evsel = perf_evsel__next(evsel);
@@ -536,6 +542,7 @@ static int test__group1(struct perf_evlist *evlist)
536 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 542 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
537 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 543 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
538 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 544 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
545 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
539 546
540 return 0; 547 return 0;
541} 548}
@@ -545,6 +552,7 @@ static int test__group2(struct perf_evlist *evlist)
545 struct perf_evsel *evsel, *leader; 552 struct perf_evsel *evsel, *leader;
546 553
547 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); 554 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
555 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
548 556
549 /* faults + :ku modifier */ 557 /* faults + :ku modifier */
550 evsel = leader = perf_evlist__first(evlist); 558 evsel = leader = perf_evlist__first(evlist);
@@ -557,7 +565,9 @@ static int test__group2(struct perf_evlist *evlist)
557 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 565 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
558 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 566 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
559 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 567 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
560 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 568 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
569 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
570 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
561 571
562 /* cache-references + :u modifier */ 572 /* cache-references + :u modifier */
563 evsel = perf_evsel__next(evsel); 573 evsel = perf_evsel__next(evsel);
@@ -567,10 +577,11 @@ static int test__group2(struct perf_evlist *evlist)
567 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); 577 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
568 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); 578 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
569 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); 579 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
570 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 580 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
571 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 581 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
572 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 582 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
573 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 583 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
584 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
574 585
575 /* cycles:k */ 586 /* cycles:k */
576 evsel = perf_evsel__next(evsel); 587 evsel = perf_evsel__next(evsel);
@@ -583,7 +594,7 @@ static int test__group2(struct perf_evlist *evlist)
583 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 594 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
584 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 595 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
585 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 596 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
586 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 597 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
587 598
588 return 0; 599 return 0;
589} 600}
@@ -593,6 +604,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
593 struct perf_evsel *evsel, *leader; 604 struct perf_evsel *evsel, *leader;
594 605
595 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); 606 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
607 TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups);
596 608
597 /* group1 syscalls:sys_enter_open:H */ 609 /* group1 syscalls:sys_enter_open:H */
598 evsel = leader = perf_evlist__first(evlist); 610 evsel = leader = perf_evlist__first(evlist);
@@ -606,9 +618,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
606 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); 618 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
607 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 619 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
608 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 620 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
609 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 621 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
610 TEST_ASSERT_VAL("wrong group name", 622 TEST_ASSERT_VAL("wrong group name",
611 !strcmp(leader->group_name, "group1")); 623 !strcmp(leader->group_name, "group1"));
624 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
625 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
612 626
613 /* group1 cycles:kppp */ 627 /* group1 cycles:kppp */
614 evsel = perf_evsel__next(evsel); 628 evsel = perf_evsel__next(evsel);
@@ -624,6 +638,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
624 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); 638 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3);
625 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 639 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
626 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 640 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
641 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
627 642
628 /* group2 cycles + G modifier */ 643 /* group2 cycles + G modifier */
629 evsel = leader = perf_evsel__next(evsel); 644 evsel = leader = perf_evsel__next(evsel);
@@ -636,9 +651,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
636 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 651 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
637 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 652 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
638 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 653 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
639 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 654 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
640 TEST_ASSERT_VAL("wrong group name", 655 TEST_ASSERT_VAL("wrong group name",
641 !strcmp(leader->group_name, "group2")); 656 !strcmp(leader->group_name, "group2"));
657 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
658 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
642 659
643 /* group2 1:3 + G modifier */ 660 /* group2 1:3 + G modifier */
644 evsel = perf_evsel__next(evsel); 661 evsel = perf_evsel__next(evsel);
@@ -651,6 +668,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
651 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 668 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
652 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 669 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
653 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 670 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
671 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
654 672
655 /* instructions:u */ 673 /* instructions:u */
656 evsel = perf_evsel__next(evsel); 674 evsel = perf_evsel__next(evsel);
@@ -663,7 +681,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
663 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 681 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
664 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 682 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
665 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 683 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
666 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 684 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
667 685
668 return 0; 686 return 0;
669} 687}
@@ -673,6 +691,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
673 struct perf_evsel *evsel, *leader; 691 struct perf_evsel *evsel, *leader;
674 692
675 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); 693 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
694 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
676 695
677 /* cycles:u + p */ 696 /* cycles:u + p */
678 evsel = leader = perf_evlist__first(evlist); 697 evsel = leader = perf_evlist__first(evlist);
@@ -687,7 +706,9 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
687 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 706 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
688 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); 707 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1);
689 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 708 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
690 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 709 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
710 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
711 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
691 712
692 /* instructions:kp + p */ 713 /* instructions:kp + p */
693 evsel = perf_evsel__next(evsel); 714 evsel = perf_evsel__next(evsel);
@@ -702,6 +723,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
702 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 723 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
703 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 724 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
704 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 725 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
726 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
705 727
706 return 0; 728 return 0;
707} 729}
@@ -711,6 +733,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
711 struct perf_evsel *evsel, *leader; 733 struct perf_evsel *evsel, *leader;
712 734
713 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); 735 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
736 TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups);
714 737
715 /* cycles + G */ 738 /* cycles + G */
716 evsel = leader = perf_evlist__first(evlist); 739 evsel = leader = perf_evlist__first(evlist);
@@ -724,7 +747,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
724 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 747 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
725 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 748 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
726 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 749 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
727 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 750 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
751 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
752 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
728 753
729 /* instructions + G */ 754 /* instructions + G */
730 evsel = perf_evsel__next(evsel); 755 evsel = perf_evsel__next(evsel);
@@ -738,6 +763,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
738 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 763 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
739 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 764 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
740 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 765 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
766 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
741 767
742 /* cycles:G */ 768 /* cycles:G */
743 evsel = leader = perf_evsel__next(evsel); 769 evsel = leader = perf_evsel__next(evsel);
@@ -751,7 +777,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
751 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 777 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
752 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 778 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
753 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 779 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
754 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 780 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
781 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
782 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
755 783
756 /* instructions:G */ 784 /* instructions:G */
757 evsel = perf_evsel__next(evsel); 785 evsel = perf_evsel__next(evsel);
@@ -765,6 +793,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
765 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 793 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
766 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 794 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
767 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 795 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
796 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
768 797
769 /* cycles */ 798 /* cycles */
770 evsel = perf_evsel__next(evsel); 799 evsel = perf_evsel__next(evsel);
@@ -777,18 +806,235 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
777 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); 806 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
778 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 807 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
779 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 808 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
780 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 809 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
810
811 return 0;
812}
813
814static int test__group_gh1(struct perf_evlist *evlist)
815{
816 struct perf_evsel *evsel, *leader;
817
818 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
819 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
820
821 /* cycles + :H group modifier */
822 evsel = leader = perf_evlist__first(evlist);
823 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
824 TEST_ASSERT_VAL("wrong config",
825 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
826 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
827 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
828 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
829 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
830 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
831 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
832 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
833 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
834 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
835 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
836
837 /* cache-misses:G + :H group modifier */
838 evsel = perf_evsel__next(evsel);
839 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
840 TEST_ASSERT_VAL("wrong config",
841 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
842 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
843 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
844 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
845 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
846 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
847 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
848 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
849 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
850
851 return 0;
852}
853
854static int test__group_gh2(struct perf_evlist *evlist)
855{
856 struct perf_evsel *evsel, *leader;
857
858 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
859 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
860
861 /* cycles + :G group modifier */
862 evsel = leader = perf_evlist__first(evlist);
863 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
864 TEST_ASSERT_VAL("wrong config",
865 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
866 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
867 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
868 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
869 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
870 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
871 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
872 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
873 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
874 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
875 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
876
877 /* cache-misses:H + :G group modifier */
878 evsel = perf_evsel__next(evsel);
879 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
880 TEST_ASSERT_VAL("wrong config",
881 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
882 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
883 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
884 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
885 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
886 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
887 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
888 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
889 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
890
891 return 0;
892}
893
894static int test__group_gh3(struct perf_evlist *evlist)
895{
896 struct perf_evsel *evsel, *leader;
897
898 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
899 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
900
901 /* cycles:G + :u group modifier */
902 evsel = leader = perf_evlist__first(evlist);
903 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
904 TEST_ASSERT_VAL("wrong config",
905 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
906 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
907 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
908 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
909 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
910 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
911 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
912 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
913 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
914 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
915 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
916
917 /* cache-misses:H + :u group modifier */
918 evsel = perf_evsel__next(evsel);
919 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
920 TEST_ASSERT_VAL("wrong config",
921 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
922 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
923 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
924 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
925 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
926 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
927 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
928 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
929 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
930
931 return 0;
932}
933
934static int test__group_gh4(struct perf_evlist *evlist)
935{
936 struct perf_evsel *evsel, *leader;
937
938 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
939 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
940
941 /* cycles:G + :uG group modifier */
942 evsel = leader = perf_evlist__first(evlist);
943 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
944 TEST_ASSERT_VAL("wrong config",
945 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
946 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
947 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
948 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
949 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
950 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
951 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
952 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
953 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
954 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
955 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
956
957 /* cache-misses:H + :uG group modifier */
958 evsel = perf_evsel__next(evsel);
959 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
960 TEST_ASSERT_VAL("wrong config",
961 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
962 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
963 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
964 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
965 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
966 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
967 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
968 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
969 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
781 970
782 return 0; 971 return 0;
783} 972}
784 973
785struct test__event_st { 974static int count_tracepoints(void)
975{
976 char events_path[PATH_MAX];
977 struct dirent *events_ent;
978 DIR *events_dir;
979 int cnt = 0;
980
981 scnprintf(events_path, PATH_MAX, "%s/tracing/events",
982 debugfs_find_mountpoint());
983
984 events_dir = opendir(events_path);
985
986 TEST_ASSERT_VAL("Can't open events dir", events_dir);
987
988 while ((events_ent = readdir(events_dir))) {
989 char sys_path[PATH_MAX];
990 struct dirent *sys_ent;
991 DIR *sys_dir;
992
993 if (!strcmp(events_ent->d_name, ".")
994 || !strcmp(events_ent->d_name, "..")
995 || !strcmp(events_ent->d_name, "enable")
996 || !strcmp(events_ent->d_name, "header_event")
997 || !strcmp(events_ent->d_name, "header_page"))
998 continue;
999
1000 scnprintf(sys_path, PATH_MAX, "%s/%s",
1001 events_path, events_ent->d_name);
1002
1003 sys_dir = opendir(sys_path);
1004 TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
1005
1006 while ((sys_ent = readdir(sys_dir))) {
1007 if (!strcmp(sys_ent->d_name, ".")
1008 || !strcmp(sys_ent->d_name, "..")
1009 || !strcmp(sys_ent->d_name, "enable")
1010 || !strcmp(sys_ent->d_name, "filter"))
1011 continue;
1012
1013 cnt++;
1014 }
1015
1016 closedir(sys_dir);
1017 }
1018
1019 closedir(events_dir);
1020 return cnt;
1021}
1022
1023static int test__all_tracepoints(struct perf_evlist *evlist)
1024{
1025 TEST_ASSERT_VAL("wrong events count",
1026 count_tracepoints() == evlist->nr_entries);
1027
1028 return test__checkevent_tracepoint_multi(evlist);
1029}
1030
1031struct evlist_test {
786 const char *name; 1032 const char *name;
787 __u32 type; 1033 __u32 type;
788 int (*check)(struct perf_evlist *evlist); 1034 int (*check)(struct perf_evlist *evlist);
789}; 1035};
790 1036
791static struct test__event_st test__events[] = { 1037static struct evlist_test test__events[] = {
792 [0] = { 1038 [0] = {
793 .name = "syscalls:sys_enter_open", 1039 .name = "syscalls:sys_enter_open",
794 .check = test__checkevent_tracepoint, 1040 .check = test__checkevent_tracepoint,
@@ -921,9 +1167,29 @@ static struct test__event_st test__events[] = {
921 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", 1167 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
922 .check = test__group5, 1168 .check = test__group5,
923 }, 1169 },
1170 [33] = {
1171 .name = "*:*",
1172 .check = test__all_tracepoints,
1173 },
1174 [34] = {
1175 .name = "{cycles,cache-misses:G}:H",
1176 .check = test__group_gh1,
1177 },
1178 [35] = {
1179 .name = "{cycles,cache-misses:H}:G",
1180 .check = test__group_gh2,
1181 },
1182 [36] = {
1183 .name = "{cycles:G,cache-misses:H}:u",
1184 .check = test__group_gh3,
1185 },
1186 [37] = {
1187 .name = "{cycles:G,cache-misses:H}:uG",
1188 .check = test__group_gh4,
1189 },
924}; 1190};
925 1191
926static struct test__event_st test__events_pmu[] = { 1192static struct evlist_test test__events_pmu[] = {
927 [0] = { 1193 [0] = {
928 .name = "cpu/config=10,config1,config2=3,period=1000/u", 1194 .name = "cpu/config=10,config1,config2=3,period=1000/u",
929 .check = test__checkevent_pmu, 1195 .check = test__checkevent_pmu,
@@ -934,29 +1200,29 @@ static struct test__event_st test__events_pmu[] = {
934 }, 1200 },
935}; 1201};
936 1202
937struct test__term { 1203struct terms_test {
938 const char *str; 1204 const char *str;
939 __u32 type; 1205 __u32 type;
940 int (*check)(struct list_head *terms); 1206 int (*check)(struct list_head *terms);
941}; 1207};
942 1208
943static struct test__term test__terms[] = { 1209static struct terms_test test__terms[] = {
944 [0] = { 1210 [0] = {
945 .str = "config=10,config1,config2=3,umask=1", 1211 .str = "config=10,config1,config2=3,umask=1",
946 .check = test__checkterms_simple, 1212 .check = test__checkterms_simple,
947 }, 1213 },
948}; 1214};
949 1215
950static int test_event(struct test__event_st *e) 1216static int test_event(struct evlist_test *e)
951{ 1217{
952 struct perf_evlist *evlist; 1218 struct perf_evlist *evlist;
953 int ret; 1219 int ret;
954 1220
955 evlist = perf_evlist__new(NULL, NULL); 1221 evlist = perf_evlist__new();
956 if (evlist == NULL) 1222 if (evlist == NULL)
957 return -ENOMEM; 1223 return -ENOMEM;
958 1224
959 ret = parse_events(evlist, e->name, 0); 1225 ret = parse_events(evlist, e->name);
960 if (ret) { 1226 if (ret) {
961 pr_debug("failed to parse event '%s', err %d\n", 1227 pr_debug("failed to parse event '%s', err %d\n",
962 e->name, ret); 1228 e->name, ret);
@@ -969,13 +1235,13 @@ static int test_event(struct test__event_st *e)
969 return ret; 1235 return ret;
970} 1236}
971 1237
972static int test_events(struct test__event_st *events, unsigned cnt) 1238static int test_events(struct evlist_test *events, unsigned cnt)
973{ 1239{
974 int ret1, ret2 = 0; 1240 int ret1, ret2 = 0;
975 unsigned i; 1241 unsigned i;
976 1242
977 for (i = 0; i < cnt; i++) { 1243 for (i = 0; i < cnt; i++) {
978 struct test__event_st *e = &events[i]; 1244 struct evlist_test *e = &events[i];
979 1245
980 pr_debug("running test %d '%s'\n", i, e->name); 1246 pr_debug("running test %d '%s'\n", i, e->name);
981 ret1 = test_event(e); 1247 ret1 = test_event(e);
@@ -986,7 +1252,7 @@ static int test_events(struct test__event_st *events, unsigned cnt)
986 return ret2; 1252 return ret2;
987} 1253}
988 1254
989static int test_term(struct test__term *t) 1255static int test_term(struct terms_test *t)
990{ 1256{
991 struct list_head *terms; 1257 struct list_head *terms;
992 int ret; 1258 int ret;
@@ -1010,13 +1276,13 @@ static int test_term(struct test__term *t)
1010 return ret; 1276 return ret;
1011} 1277}
1012 1278
1013static int test_terms(struct test__term *terms, unsigned cnt) 1279static int test_terms(struct terms_test *terms, unsigned cnt)
1014{ 1280{
1015 int ret = 0; 1281 int ret = 0;
1016 unsigned i; 1282 unsigned i;
1017 1283
1018 for (i = 0; i < cnt; i++) { 1284 for (i = 0; i < cnt; i++) {
1019 struct test__term *t = &terms[i]; 1285 struct terms_test *t = &terms[i];
1020 1286
1021 pr_debug("running test %d '%s'\n", i, t->str); 1287 pr_debug("running test %d '%s'\n", i, t->str);
1022 ret = test_term(t); 1288 ret = test_term(t);
@@ -1055,7 +1321,7 @@ static int test_pmu_events(void)
1055 1321
1056 ret = stat(path, &st); 1322 ret = stat(path, &st);
1057 if (ret) { 1323 if (ret) {
1058 pr_debug("ommiting PMU cpu events tests\n"); 1324 pr_debug("omitting PMU cpu events tests\n");
1059 return 0; 1325 return 0;
1060 } 1326 }
1061 1327
@@ -1067,7 +1333,7 @@ static int test_pmu_events(void)
1067 1333
1068 while (!ret && (ent = readdir(dir))) { 1334 while (!ret && (ent = readdir(dir))) {
1069#define MAX_NAME 100 1335#define MAX_NAME 100
1070 struct test__event_st e; 1336 struct evlist_test e;
1071 char name[MAX_NAME]; 1337 char name[MAX_NAME];
1072 1338
1073 if (!strcmp(ent->d_name, ".") || 1339 if (!strcmp(ent->d_name, ".") ||
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 70e0d4421df8..72d8881873b0 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -45,7 +45,7 @@ int test__PERF_RECORD(void)
45 }; 45 };
46 cpu_set_t cpu_mask; 46 cpu_set_t cpu_mask;
47 size_t cpu_mask_size = sizeof(cpu_mask); 47 size_t cpu_mask_size = sizeof(cpu_mask);
48 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 48 struct perf_evlist *evlist = perf_evlist__new();
49 struct perf_evsel *evsel; 49 struct perf_evsel *evsel;
50 struct perf_sample sample; 50 struct perf_sample sample;
51 const char *cmd = "sleep"; 51 const char *cmd = "sleep";
@@ -93,25 +93,26 @@ int test__PERF_RECORD(void)
93 * so that we have time to open the evlist (calling sys_perf_event_open 93 * so that we have time to open the evlist (calling sys_perf_event_open
94 * on all the fds) and then mmap them. 94 * on all the fds) and then mmap them.
95 */ 95 */
96 err = perf_evlist__prepare_workload(evlist, &opts, argv); 96 err = perf_evlist__prepare_workload(evlist, &opts.target, argv,
97 false, false);
97 if (err < 0) { 98 if (err < 0) {
98 pr_debug("Couldn't run the workload!\n"); 99 pr_debug("Couldn't run the workload!\n");
99 goto out_delete_evlist; 100 goto out_delete_maps;
100 } 101 }
101 102
102 /* 103 /*
103 * Config the evsels, setting attr->comm on the first one, etc. 104 * Config the evsels, setting attr->comm on the first one, etc.
104 */ 105 */
105 evsel = perf_evlist__first(evlist); 106 evsel = perf_evlist__first(evlist);
106 evsel->attr.sample_type |= PERF_SAMPLE_CPU; 107 perf_evsel__set_sample_bit(evsel, CPU);
107 evsel->attr.sample_type |= PERF_SAMPLE_TID; 108 perf_evsel__set_sample_bit(evsel, TID);
108 evsel->attr.sample_type |= PERF_SAMPLE_TIME; 109 perf_evsel__set_sample_bit(evsel, TIME);
109 perf_evlist__config_attrs(evlist, &opts); 110 perf_evlist__config(evlist, &opts);
110 111
111 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); 112 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
112 if (err < 0) { 113 if (err < 0) {
113 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); 114 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
114 goto out_delete_evlist; 115 goto out_delete_maps;
115 } 116 }
116 117
117 cpu = err; 118 cpu = err;
@@ -121,7 +122,7 @@ int test__PERF_RECORD(void)
121 */ 122 */
122 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { 123 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
123 pr_debug("sched_setaffinity: %s\n", strerror(errno)); 124 pr_debug("sched_setaffinity: %s\n", strerror(errno));
124 goto out_delete_evlist; 125 goto out_delete_maps;
125 } 126 }
126 127
127 /* 128 /*
@@ -131,7 +132,7 @@ int test__PERF_RECORD(void)
131 err = perf_evlist__open(evlist); 132 err = perf_evlist__open(evlist);
132 if (err < 0) { 133 if (err < 0) {
133 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 134 pr_debug("perf_evlist__open: %s\n", strerror(errno));
134 goto out_delete_evlist; 135 goto out_delete_maps;
135 } 136 }
136 137
137 /* 138 /*
@@ -142,7 +143,7 @@ int test__PERF_RECORD(void)
142 err = perf_evlist__mmap(evlist, opts.mmap_pages, false); 143 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
143 if (err < 0) { 144 if (err < 0) {
144 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 145 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
145 goto out_delete_evlist; 146 goto out_close_evlist;
146 } 147 }
147 148
148 /* 149 /*
@@ -305,6 +306,10 @@ found_exit:
305 } 306 }
306out_err: 307out_err:
307 perf_evlist__munmap(evlist); 308 perf_evlist__munmap(evlist);
309out_close_evlist:
310 perf_evlist__close(evlist);
311out_delete_maps:
312 perf_evlist__delete_maps(evlist);
308out_delete_evlist: 313out_delete_evlist:
309 perf_evlist__delete(evlist); 314 perf_evlist__delete(evlist);
310out: 315out:
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index a5f379863b8f..12b322fa3475 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -19,10 +19,8 @@ static struct test_format {
19 { "krava23", "config2:28-29,38\n", }, 19 { "krava23", "config2:28-29,38\n", },
20}; 20};
21 21
22#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
23
24/* Simulated users input. */ 22/* Simulated users input. */
25static struct parse_events__term test_terms[] = { 23static struct parse_events_term test_terms[] = {
26 { 24 {
27 .config = (char *) "krava01", 25 .config = (char *) "krava01",
28 .val.num = 15, 26 .val.num = 15,
@@ -78,7 +76,6 @@ static struct parse_events__term test_terms[] = {
78 .type_term = PARSE_EVENTS__TERM_TYPE_USER, 76 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
79 }, 77 },
80}; 78};
81#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
82 79
83/* 80/*
84 * Prepare format directory data, exported by kernel 81 * Prepare format directory data, exported by kernel
@@ -93,7 +90,7 @@ static char *test_format_dir_get(void)
93 if (!mkdtemp(dir)) 90 if (!mkdtemp(dir))
94 return NULL; 91 return NULL;
95 92
96 for (i = 0; i < TEST_FORMATS_CNT; i++) { 93 for (i = 0; i < ARRAY_SIZE(test_formats); i++) {
97 static char name[PATH_MAX]; 94 static char name[PATH_MAX];
98 struct test_format *format = &test_formats[i]; 95 struct test_format *format = &test_formats[i];
99 FILE *file; 96 FILE *file;
@@ -130,14 +127,12 @@ static struct list_head *test_terms_list(void)
130 static LIST_HEAD(terms); 127 static LIST_HEAD(terms);
131 unsigned int i; 128 unsigned int i;
132 129
133 for (i = 0; i < TERMS_CNT; i++) 130 for (i = 0; i < ARRAY_SIZE(test_terms); i++)
134 list_add_tail(&test_terms[i].list, &terms); 131 list_add_tail(&test_terms[i].list, &terms);
135 132
136 return &terms; 133 return &terms;
137} 134}
138 135
139#undef TERMS_CNT
140
141int test__pmu(void) 136int test__pmu(void)
142{ 137{
143 char *format = test_format_dir_get(); 138 char *format = test_format_dir_get();
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c
new file mode 100644
index 000000000000..7760277c6def
--- /dev/null
+++ b/tools/perf/tests/python-use.c
@@ -0,0 +1,23 @@
1/*
2 * Just test if we can load the python binding.
3 */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include "tests.h"
8
9extern int verbose;
10
11int test__python_use(void)
12{
13 char *cmd;
14 int ret;
15
16 if (asprintf(&cmd, "echo \"import sys ; sys.path.append('%s'); import perf\" | %s %s",
17 PYTHONPATH, PYTHON, verbose ? "" : "2> /dev/null") < 0)
18 return -1;
19
20 ret = system(cmd) ? -1 : 0;
21 free(cmd);
22 return ret;
23}
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
new file mode 100644
index 000000000000..2e41e2d32ccc
--- /dev/null
+++ b/tools/perf/tests/sw-clock.c
@@ -0,0 +1,119 @@
1#include <unistd.h>
2#include <stdlib.h>
3#include <signal.h>
4#include <sys/mman.h>
5
6#include "tests.h"
7#include "util/evsel.h"
8#include "util/evlist.h"
9#include "util/cpumap.h"
10#include "util/thread_map.h"
11
12#define NR_LOOPS 1000000
13
14/*
15 * This test will open software clock events (cpu-clock, task-clock)
16 * then check their frequency -> period conversion has no artifact of
17 * setting period to 1 forcefully.
18 */
19static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
20{
21 int i, err = -1;
22 volatile int tmp = 0;
23 u64 total_periods = 0;
24 int nr_samples = 0;
25 union perf_event *event;
26 struct perf_evsel *evsel;
27 struct perf_evlist *evlist;
28 struct perf_event_attr attr = {
29 .type = PERF_TYPE_SOFTWARE,
30 .config = clock_id,
31 .sample_type = PERF_SAMPLE_PERIOD,
32 .exclude_kernel = 1,
33 .disabled = 1,
34 .freq = 1,
35 };
36
37 attr.sample_freq = 10000;
38
39 evlist = perf_evlist__new();
40 if (evlist == NULL) {
41 pr_debug("perf_evlist__new\n");
42 return -1;
43 }
44
45 evsel = perf_evsel__new(&attr, 0);
46 if (evsel == NULL) {
47 pr_debug("perf_evsel__new\n");
48 goto out_free_evlist;
49 }
50 perf_evlist__add(evlist, evsel);
51
52 evlist->cpus = cpu_map__dummy_new();
53 evlist->threads = thread_map__new_by_tid(getpid());
54 if (!evlist->cpus || !evlist->threads) {
55 err = -ENOMEM;
56 pr_debug("Not enough memory to create thread/cpu maps\n");
57 goto out_delete_maps;
58 }
59
60 perf_evlist__open(evlist);
61
62 err = perf_evlist__mmap(evlist, 128, true);
63 if (err < 0) {
64 pr_debug("failed to mmap event: %d (%s)\n", errno,
65 strerror(errno));
66 goto out_close_evlist;
67 }
68
69 perf_evlist__enable(evlist);
70
71 /* collect samples */
72 for (i = 0; i < NR_LOOPS; i++)
73 tmp++;
74
75 perf_evlist__disable(evlist);
76
77 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
78 struct perf_sample sample;
79
80 if (event->header.type != PERF_RECORD_SAMPLE)
81 continue;
82
83 err = perf_evlist__parse_sample(evlist, event, &sample);
84 if (err < 0) {
85 pr_debug("Error during parse sample\n");
86 goto out_unmap_evlist;
87 }
88
89 total_periods += sample.period;
90 nr_samples++;
91 }
92
93 if ((u64) nr_samples == total_periods) {
94 pr_debug("All (%d) samples have period value of 1!\n",
95 nr_samples);
96 err = -1;
97 }
98
99out_unmap_evlist:
100 perf_evlist__munmap(evlist);
101out_close_evlist:
102 perf_evlist__close(evlist);
103out_delete_maps:
104 perf_evlist__delete_maps(evlist);
105out_free_evlist:
106 perf_evlist__delete(evlist);
107 return err;
108}
109
110int test__sw_clock_freq(void)
111{
112 int ret;
113
114 ret = __test__sw_clock_freq(PERF_COUNT_SW_CPU_CLOCK);
115 if (!ret)
116 ret = __test__sw_clock_freq(PERF_COUNT_SW_TASK_CLOCK);
117
118 return ret;
119}
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
new file mode 100644
index 000000000000..28fe5894b061
--- /dev/null
+++ b/tools/perf/tests/task-exit.c
@@ -0,0 +1,123 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "thread_map.h"
4#include "cpumap.h"
5#include "tests.h"
6
7#include <signal.h>
8
9static int exited;
10static int nr_exit;
11
12static void sig_handler(int sig)
13{
14 exited = 1;
15
16 if (sig == SIGUSR1)
17 nr_exit = -1;
18}
19
20/*
21 * This test will start a workload that does nothing then it checks
22 * if the number of exit event reported by the kernel is 1 or not
23 * in order to check the kernel returns correct number of event.
24 */
25int test__task_exit(void)
26{
27 int err = -1;
28 union perf_event *event;
29 struct perf_evsel *evsel;
30 struct perf_evlist *evlist;
31 struct perf_target target = {
32 .uid = UINT_MAX,
33 .uses_mmap = true,
34 };
35 const char *argv[] = { "true", NULL };
36
37 signal(SIGCHLD, sig_handler);
38 signal(SIGUSR1, sig_handler);
39
40 evlist = perf_evlist__new();
41 if (evlist == NULL) {
42 pr_debug("perf_evlist__new\n");
43 return -1;
44 }
45 /*
46 * We need at least one evsel in the evlist, use the default
47 * one: "cycles".
48 */
49 err = perf_evlist__add_default(evlist);
50 if (err < 0) {
51 pr_debug("Not enough memory to create evsel\n");
52 goto out_free_evlist;
53 }
54
55 /*
56 * Create maps of threads and cpus to monitor. In this case
57 * we start with all threads and cpus (-1, -1) but then in
58 * perf_evlist__prepare_workload we'll fill in the only thread
59 * we're monitoring, the one forked there.
60 */
61 evlist->cpus = cpu_map__dummy_new();
62 evlist->threads = thread_map__new_by_tid(-1);
63 if (!evlist->cpus || !evlist->threads) {
64 err = -ENOMEM;
65 pr_debug("Not enough memory to create thread/cpu maps\n");
66 goto out_delete_maps;
67 }
68
69 err = perf_evlist__prepare_workload(evlist, &target, argv, false, true);
70 if (err < 0) {
71 pr_debug("Couldn't run the workload!\n");
72 goto out_delete_maps;
73 }
74
75 evsel = perf_evlist__first(evlist);
76 evsel->attr.task = 1;
77 evsel->attr.sample_freq = 0;
78 evsel->attr.inherit = 0;
79 evsel->attr.watermark = 0;
80 evsel->attr.wakeup_events = 1;
81 evsel->attr.exclude_kernel = 1;
82
83 err = perf_evlist__open(evlist);
84 if (err < 0) {
85 pr_debug("Couldn't open the evlist: %s\n", strerror(-err));
86 goto out_delete_maps;
87 }
88
89 if (perf_evlist__mmap(evlist, 128, true) < 0) {
90 pr_debug("failed to mmap events: %d (%s)\n", errno,
91 strerror(errno));
92 goto out_close_evlist;
93 }
94
95 perf_evlist__start_workload(evlist);
96
97retry:
98 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
99 if (event->header.type != PERF_RECORD_EXIT)
100 continue;
101
102 nr_exit++;
103 }
104
105 if (!exited || !nr_exit) {
106 poll(evlist->pollfd, evlist->nr_fds, -1);
107 goto retry;
108 }
109
110 if (nr_exit != 1) {
111 pr_debug("received %d EXIT records\n", nr_exit);
112 err = -1;
113 }
114
115 perf_evlist__munmap(evlist);
116out_close_evlist:
117 perf_evlist__close(evlist);
118out_delete_maps:
119 perf_evlist__delete_maps(evlist);
120out_free_evlist:
121 perf_evlist__delete(evlist);
122 return err;
123}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index fc121edab016..dd7feae2d37b 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -1,6 +1,12 @@
1#ifndef TESTS_H 1#ifndef TESTS_H
2#define TESTS_H 2#define TESTS_H
3 3
4enum {
5 TEST_OK = 0,
6 TEST_FAIL = -1,
7 TEST_SKIP = -2,
8};
9
4/* Tests */ 10/* Tests */
5int test__vmlinux_matches_kallsyms(void); 11int test__vmlinux_matches_kallsyms(void);
6int test__open_syscall_event(void); 12int test__open_syscall_event(void);
@@ -15,8 +21,11 @@ int test__pmu(void);
15int test__attr(void); 21int test__attr(void);
16int test__dso_data(void); 22int test__dso_data(void);
17int test__parse_events(void); 23int test__parse_events(void);
18 24int test__hists_link(void);
19/* Util */ 25int test__python_use(void);
20int trace_event__id(const char *evname); 26int test__bp_signal(void);
27int test__bp_signal_overflow(void);
28int test__task_exit(void);
29int test__sw_clock_freq(void);
21 30
22#endif /* TESTS_H */ 31#endif /* TESTS_H */
diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c
deleted file mode 100644
index 748f2e8f6961..000000000000
--- a/tools/perf/tests/util.c
+++ /dev/null
@@ -1,30 +0,0 @@
1#include <stdio.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include "tests.h"
8#include "debugfs.h"
9
10int trace_event__id(const char *evname)
11{
12 char *filename;
13 int err = -1, fd;
14
15 if (asprintf(&filename,
16 "%s/syscalls/%s/id",
17 tracing_events_path, evname) < 0)
18 return -1;
19
20 fd = open(filename, O_RDONLY);
21 if (fd >= 0) {
22 char id[16];
23 if (read(fd, id, sizeof(id)) > 0)
24 err = atoi(id);
25 close(fd);
26 }
27
28 free(filename);
29 return err;
30}
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 0d1cdbee2f59..7b4c4d26d1ba 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -44,7 +44,7 @@ int test__vmlinux_matches_kallsyms(void)
44 */ 44 */
45 if (machine__create_kernel_maps(&kallsyms) < 0) { 45 if (machine__create_kernel_maps(&kallsyms) < 0) {
46 pr_debug("machine__create_kernel_maps "); 46 pr_debug("machine__create_kernel_maps ");
47 return -1; 47 goto out;
48 } 48 }
49 49
50 /* 50 /*
@@ -101,7 +101,8 @@ int test__vmlinux_matches_kallsyms(void)
101 */ 101 */
102 if (machine__load_vmlinux_path(&vmlinux, type, 102 if (machine__load_vmlinux_path(&vmlinux, type,
103 vmlinux_matches_kallsyms_filter) <= 0) { 103 vmlinux_matches_kallsyms_filter) <= 0) {
104 pr_debug("machine__load_vmlinux_path "); 104 pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n");
105 err = TEST_SKIP;
105 goto out; 106 goto out;
106 } 107 }
107 108
@@ -226,5 +227,7 @@ detour:
226 map__fprintf(pos, stderr); 227 map__fprintf(pos, stderr);
227 } 228 }
228out: 229out:
230 machine__exit(&kallsyms);
231 machine__exit(&vmlinux);
229 return err; 232 return err;
230} 233}
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 4aeb7d5df939..bbc782e364b0 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -2,7 +2,6 @@
2#include "../cache.h" 2#include "../cache.h"
3#include "../../perf.h" 3#include "../../perf.h"
4#include "libslang.h" 4#include "libslang.h"
5#include <newt.h>
6#include "ui.h" 5#include "ui.h"
7#include "util.h" 6#include "util.h"
8#include <linux/compiler.h> 7#include <linux/compiler.h>
@@ -234,7 +233,7 @@ void ui_browser__reset_index(struct ui_browser *browser)
234void __ui_browser__show_title(struct ui_browser *browser, const char *title) 233void __ui_browser__show_title(struct ui_browser *browser, const char *title)
235{ 234{
236 SLsmg_gotorc(0, 0); 235 SLsmg_gotorc(0, 0);
237 ui_browser__set_color(browser, NEWT_COLORSET_ROOT); 236 ui_browser__set_color(browser, HE_COLORSET_ROOT);
238 slsmg_write_nstring(title, browser->width + 1); 237 slsmg_write_nstring(title, browser->width + 1);
239} 238}
240 239
@@ -273,6 +272,8 @@ void ui_browser__hide(struct ui_browser *browser __maybe_unused)
273{ 272{
274 pthread_mutex_lock(&ui__lock); 273 pthread_mutex_lock(&ui__lock);
275 ui_helpline__pop(); 274 ui_helpline__pop();
275 free(browser->helpline);
276 browser->helpline = NULL;
276 pthread_mutex_unlock(&ui__lock); 277 pthread_mutex_unlock(&ui__lock);
277} 278}
278 279
@@ -471,7 +472,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
471 return row; 472 return row;
472} 473}
473 474
474static struct ui_browser__colorset { 475static struct ui_browser_colorset {
475 const char *name, *fg, *bg; 476 const char *name, *fg, *bg;
476 int colorset; 477 int colorset;
477} ui_browser__colorsets[] = { 478} ui_browser__colorsets[] = {
@@ -512,6 +513,12 @@ static struct ui_browser__colorset {
512 .bg = "default", 513 .bg = "default",
513 }, 514 },
514 { 515 {
516 .colorset = HE_COLORSET_ROOT,
517 .name = "root",
518 .fg = "white",
519 .bg = "blue",
520 },
521 {
515 .name = NULL, 522 .name = NULL,
516 } 523 }
517}; 524};
@@ -706,7 +713,7 @@ void ui_browser__init(void)
706 perf_config(ui_browser__color_config, NULL); 713 perf_config(ui_browser__color_config, NULL);
707 714
708 while (ui_browser__colorsets[i].name) { 715 while (ui_browser__colorsets[i].name) {
709 struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; 716 struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
710 sltt_set_color(c->colorset, c->name, c->fg, c->bg); 717 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
711 } 718 }
712 719
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index af70314605e5..404ff66a3e36 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -11,6 +11,7 @@
11#define HE_COLORSET_SELECTED 53 11#define HE_COLORSET_SELECTED 53
12#define HE_COLORSET_CODE 54 12#define HE_COLORSET_CODE 54
13#define HE_COLORSET_ADDR 55 13#define HE_COLORSET_ADDR 55
14#define HE_COLORSET_ROOT 56
14 15
15struct ui_browser { 16struct ui_browser {
16 u64 index, top_idx; 17 u64 index, top_idx;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 5dab3ca96980..cc64d3f7fc36 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -8,15 +8,19 @@
8#include "../../util/hist.h" 8#include "../../util/hist.h"
9#include "../../util/sort.h" 9#include "../../util/sort.h"
10#include "../../util/symbol.h" 10#include "../../util/symbol.h"
11#include "../../util/evsel.h"
11#include <pthread.h> 12#include <pthread.h>
12#include <newt.h>
13 13
14struct browser_disasm_line { 14struct browser_disasm_line {
15 struct rb_node rb_node; 15 struct rb_node rb_node;
16 double percent;
17 u32 idx; 16 u32 idx;
18 int idx_asm; 17 int idx_asm;
19 int jump_sources; 18 int jump_sources;
19 /*
20 * actual length of this array is saved on the nr_events field
21 * of the struct annotate_browser
22 */
23 double percent[1];
20}; 24};
21 25
22static struct annotate_browser_opt { 26static struct annotate_browser_opt {
@@ -33,8 +37,9 @@ struct annotate_browser {
33 struct ui_browser b; 37 struct ui_browser b;
34 struct rb_root entries; 38 struct rb_root entries;
35 struct rb_node *curr_hot; 39 struct rb_node *curr_hot;
36 struct disasm_line *selection; 40 struct disasm_line *selection;
37 struct disasm_line **offsets; 41 struct disasm_line **offsets;
42 int nr_events;
38 u64 start; 43 u64 start;
39 int nr_asm_entries; 44 int nr_asm_entries;
40 int nr_entries; 45 int nr_entries;
@@ -94,14 +99,24 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
94 (!current_entry || (browser->use_navkeypressed && 99 (!current_entry || (browser->use_navkeypressed &&
95 !browser->navkeypressed))); 100 !browser->navkeypressed)));
96 int width = browser->width, printed; 101 int width = browser->width, printed;
102 int i, pcnt_width = 7 * ab->nr_events;
103 double percent_max = 0.0;
97 char bf[256]; 104 char bf[256];
98 105
99 if (dl->offset != -1 && bdl->percent != 0.0) { 106 for (i = 0; i < ab->nr_events; i++) {
100 ui_browser__set_percent_color(browser, bdl->percent, current_entry); 107 if (bdl->percent[i] > percent_max)
101 slsmg_printf("%6.2f ", bdl->percent); 108 percent_max = bdl->percent[i];
109 }
110
111 if (dl->offset != -1 && percent_max != 0.0) {
112 for (i = 0; i < ab->nr_events; i++) {
113 ui_browser__set_percent_color(browser, bdl->percent[i],
114 current_entry);
115 slsmg_printf("%6.2f ", bdl->percent[i]);
116 }
102 } else { 117 } else {
103 ui_browser__set_percent_color(browser, 0, current_entry); 118 ui_browser__set_percent_color(browser, 0, current_entry);
104 slsmg_write_nstring(" ", 7); 119 slsmg_write_nstring(" ", pcnt_width);
105 } 120 }
106 121
107 SLsmg_write_char(' '); 122 SLsmg_write_char(' ');
@@ -111,12 +126,12 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
111 width += 1; 126 width += 1;
112 127
113 if (!*dl->line) 128 if (!*dl->line)
114 slsmg_write_nstring(" ", width - 7); 129 slsmg_write_nstring(" ", width - pcnt_width);
115 else if (dl->offset == -1) { 130 else if (dl->offset == -1) {
116 printed = scnprintf(bf, sizeof(bf), "%*s ", 131 printed = scnprintf(bf, sizeof(bf), "%*s ",
117 ab->addr_width, " "); 132 ab->addr_width, " ");
118 slsmg_write_nstring(bf, printed); 133 slsmg_write_nstring(bf, printed);
119 slsmg_write_nstring(dl->line, width - printed - 6); 134 slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
120 } else { 135 } else {
121 u64 addr = dl->offset; 136 u64 addr = dl->offset;
122 int color = -1; 137 int color = -1;
@@ -175,13 +190,23 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
175 } 190 }
176 191
177 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); 192 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
178 slsmg_write_nstring(bf, width - 10 - printed); 193 slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
179 } 194 }
180 195
181 if (current_entry) 196 if (current_entry)
182 ab->selection = dl; 197 ab->selection = dl;
183} 198}
184 199
200static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
201{
202 if (!dl || !dl->ins || !ins__is_jump(dl->ins)
203 || !disasm_line__has_offset(dl)
204 || dl->ops.target.offset >= symbol__size(sym))
205 return false;
206
207 return true;
208}
209
185static void annotate_browser__draw_current_jump(struct ui_browser *browser) 210static void annotate_browser__draw_current_jump(struct ui_browser *browser)
186{ 211{
187 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 212 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
@@ -190,13 +215,13 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
190 unsigned int from, to; 215 unsigned int from, to;
191 struct map_symbol *ms = ab->b.priv; 216 struct map_symbol *ms = ab->b.priv;
192 struct symbol *sym = ms->sym; 217 struct symbol *sym = ms->sym;
218 u8 pcnt_width = 7;
193 219
194 /* PLT symbols contain external offsets */ 220 /* PLT symbols contain external offsets */
195 if (strstr(sym->name, "@plt")) 221 if (strstr(sym->name, "@plt"))
196 return; 222 return;
197 223
198 if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) || 224 if (!disasm_line__is_valid_jump(cursor, sym))
199 !disasm_line__has_offset(cursor))
200 return; 225 return;
201 226
202 target = ab->offsets[cursor->ops.target.offset]; 227 target = ab->offsets[cursor->ops.target.offset];
@@ -214,57 +239,44 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
214 to = (u64)btarget->idx; 239 to = (u64)btarget->idx;
215 } 240 }
216 241
242 pcnt_width *= ab->nr_events;
243
217 ui_browser__set_color(browser, HE_COLORSET_CODE); 244 ui_browser__set_color(browser, HE_COLORSET_CODE);
218 __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to); 245 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
246 from, to);
219} 247}
220 248
221static unsigned int annotate_browser__refresh(struct ui_browser *browser) 249static unsigned int annotate_browser__refresh(struct ui_browser *browser)
222{ 250{
251 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
223 int ret = ui_browser__list_head_refresh(browser); 252 int ret = ui_browser__list_head_refresh(browser);
253 int pcnt_width;
254
255 pcnt_width = 7 * ab->nr_events;
224 256
225 if (annotate_browser__opts.jump_arrows) 257 if (annotate_browser__opts.jump_arrows)
226 annotate_browser__draw_current_jump(browser); 258 annotate_browser__draw_current_jump(browser);
227 259
228 ui_browser__set_color(browser, HE_COLORSET_NORMAL); 260 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
229 __ui_browser__vline(browser, 7, 0, browser->height - 1); 261 __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
230 return ret; 262 return ret;
231} 263}
232 264
233static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx) 265static int disasm__cmp(struct browser_disasm_line *a,
266 struct browser_disasm_line *b, int nr_pcnt)
234{ 267{
235 double percent = 0.0; 268 int i;
236
237 if (dl->offset != -1) {
238 int len = sym->end - sym->start;
239 unsigned int hits = 0;
240 struct annotation *notes = symbol__annotation(sym);
241 struct source_line *src_line = notes->src->lines;
242 struct sym_hist *h = annotation__histogram(notes, evidx);
243 s64 offset = dl->offset;
244 struct disasm_line *next;
245
246 next = disasm__get_next_ip_line(&notes->src->source, dl);
247 while (offset < (s64)len &&
248 (next == NULL || offset < next->offset)) {
249 if (src_line) {
250 percent += src_line[offset].percent;
251 } else
252 hits += h->addr[offset];
253 269
254 ++offset; 270 for (i = 0; i < nr_pcnt; i++) {
255 } 271 if (a->percent[i] == b->percent[i])
256 /* 272 continue;
257 * If the percentage wasn't already calculated in 273 return a->percent[i] < b->percent[i];
258 * symbol__get_source_line, do it now:
259 */
260 if (src_line == NULL && h->sum)
261 percent = 100.0 * hits / h->sum;
262 } 274 }
263 275 return 0;
264 return percent;
265} 276}
266 277
267static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl) 278static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
279 int nr_events)
268{ 280{
269 struct rb_node **p = &root->rb_node; 281 struct rb_node **p = &root->rb_node;
270 struct rb_node *parent = NULL; 282 struct rb_node *parent = NULL;
@@ -273,7 +285,8 @@ static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_l
273 while (*p != NULL) { 285 while (*p != NULL) {
274 parent = *p; 286 parent = *p;
275 l = rb_entry(parent, struct browser_disasm_line, rb_node); 287 l = rb_entry(parent, struct browser_disasm_line, rb_node);
276 if (bdl->percent < l->percent) 288
289 if (disasm__cmp(bdl, l, nr_events))
277 p = &(*p)->rb_left; 290 p = &(*p)->rb_left;
278 else 291 else
279 p = &(*p)->rb_right; 292 p = &(*p)->rb_right;
@@ -322,12 +335,13 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser,
322} 335}
323 336
324static void annotate_browser__calc_percent(struct annotate_browser *browser, 337static void annotate_browser__calc_percent(struct annotate_browser *browser,
325 int evidx) 338 struct perf_evsel *evsel)
326{ 339{
327 struct map_symbol *ms = browser->b.priv; 340 struct map_symbol *ms = browser->b.priv;
328 struct symbol *sym = ms->sym; 341 struct symbol *sym = ms->sym;
329 struct annotation *notes = symbol__annotation(sym); 342 struct annotation *notes = symbol__annotation(sym);
330 struct disasm_line *pos; 343 struct disasm_line *pos, *next;
344 s64 len = symbol__size(sym);
331 345
332 browser->entries = RB_ROOT; 346 browser->entries = RB_ROOT;
333 347
@@ -335,12 +349,34 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
335 349
336 list_for_each_entry(pos, &notes->src->source, node) { 350 list_for_each_entry(pos, &notes->src->source, node) {
337 struct browser_disasm_line *bpos = disasm_line__browser(pos); 351 struct browser_disasm_line *bpos = disasm_line__browser(pos);
338 bpos->percent = disasm_line__calc_percent(pos, sym, evidx); 352 const char *path = NULL;
339 if (bpos->percent < 0.01) { 353 double max_percent = 0.0;
354 int i;
355
356 if (pos->offset == -1) {
340 RB_CLEAR_NODE(&bpos->rb_node); 357 RB_CLEAR_NODE(&bpos->rb_node);
341 continue; 358 continue;
342 } 359 }
343 disasm_rb_tree__insert(&browser->entries, bpos); 360
361 next = disasm__get_next_ip_line(&notes->src->source, pos);
362
363 for (i = 0; i < browser->nr_events; i++) {
364 bpos->percent[i] = disasm__calc_percent(notes,
365 evsel->idx + i,
366 pos->offset,
367 next ? next->offset : len,
368 &path);
369
370 if (max_percent < bpos->percent[i])
371 max_percent = bpos->percent[i];
372 }
373
374 if (max_percent < 0.01) {
375 RB_CLEAR_NODE(&bpos->rb_node);
376 continue;
377 }
378 disasm_rb_tree__insert(&browser->entries, bpos,
379 browser->nr_events);
344 } 380 }
345 pthread_mutex_unlock(&notes->lock); 381 pthread_mutex_unlock(&notes->lock);
346 382
@@ -392,7 +428,8 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
392 browser->b.nr_entries = browser->nr_asm_entries; 428 browser->b.nr_entries = browser->nr_asm_entries;
393} 429}
394 430
395static bool annotate_browser__callq(struct annotate_browser *browser, int evidx, 431static bool annotate_browser__callq(struct annotate_browser *browser,
432 struct perf_evsel *evsel,
396 struct hist_browser_timer *hbt) 433 struct hist_browser_timer *hbt)
397{ 434{
398 struct map_symbol *ms = browser->b.priv; 435 struct map_symbol *ms = browser->b.priv;
@@ -423,7 +460,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
423 } 460 }
424 461
425 pthread_mutex_unlock(&notes->lock); 462 pthread_mutex_unlock(&notes->lock);
426 symbol__tui_annotate(target, ms->map, evidx, hbt); 463 symbol__tui_annotate(target, ms->map, evsel, hbt);
427 ui_browser__show_title(&browser->b, sym->name); 464 ui_browser__show_title(&browser->b, sym->name);
428 return true; 465 return true;
429} 466}
@@ -606,7 +643,8 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser
606 browser->addr_width += browser->jumps_width + 1; 643 browser->addr_width += browser->jumps_width + 1;
607} 644}
608 645
609static int annotate_browser__run(struct annotate_browser *browser, int evidx, 646static int annotate_browser__run(struct annotate_browser *browser,
647 struct perf_evsel *evsel,
610 struct hist_browser_timer *hbt) 648 struct hist_browser_timer *hbt)
611{ 649{
612 struct rb_node *nd = NULL; 650 struct rb_node *nd = NULL;
@@ -619,7 +657,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
619 if (ui_browser__show(&browser->b, sym->name, help) < 0) 657 if (ui_browser__show(&browser->b, sym->name, help) < 0)
620 return -1; 658 return -1;
621 659
622 annotate_browser__calc_percent(browser, evidx); 660 annotate_browser__calc_percent(browser, evsel);
623 661
624 if (browser->curr_hot) { 662 if (browser->curr_hot) {
625 annotate_browser__set_rb_top(browser, browser->curr_hot); 663 annotate_browser__set_rb_top(browser, browser->curr_hot);
@@ -632,7 +670,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
632 key = ui_browser__run(&browser->b, delay_secs); 670 key = ui_browser__run(&browser->b, delay_secs);
633 671
634 if (delay_secs != 0) { 672 if (delay_secs != 0) {
635 annotate_browser__calc_percent(browser, evidx); 673 annotate_browser__calc_percent(browser, evsel);
636 /* 674 /*
637 * Current line focus got out of the list of most active 675 * Current line focus got out of the list of most active
638 * lines, NULL it so that if TAB|UNTAB is pressed, we 676 * lines, NULL it so that if TAB|UNTAB is pressed, we
@@ -648,7 +686,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
648 hbt->timer(hbt->arg); 686 hbt->timer(hbt->arg);
649 687
650 if (delay_secs != 0) 688 if (delay_secs != 0)
651 symbol__annotate_decay_histogram(sym, evidx); 689 symbol__annotate_decay_histogram(sym, evsel->idx);
652 continue; 690 continue;
653 case K_TAB: 691 case K_TAB:
654 if (nd != NULL) { 692 if (nd != NULL) {
@@ -745,7 +783,7 @@ show_help:
745 goto show_sup_ins; 783 goto show_sup_ins;
746 goto out; 784 goto out;
747 } else if (!(annotate_browser__jump(browser) || 785 } else if (!(annotate_browser__jump(browser) ||
748 annotate_browser__callq(browser, evidx, hbt))) { 786 annotate_browser__callq(browser, evsel, hbt))) {
749show_sup_ins: 787show_sup_ins:
750 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); 788 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
751 } 789 }
@@ -767,10 +805,10 @@ out:
767 return key; 805 return key;
768} 806}
769 807
770int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 808int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
771 struct hist_browser_timer *hbt) 809 struct hist_browser_timer *hbt)
772{ 810{
773 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt); 811 return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt);
774} 812}
775 813
776static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, 814static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
@@ -788,17 +826,9 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser
788 struct disasm_line *dl = browser->offsets[offset], *dlt; 826 struct disasm_line *dl = browser->offsets[offset], *dlt;
789 struct browser_disasm_line *bdlt; 827 struct browser_disasm_line *bdlt;
790 828
791 if (!dl || !dl->ins || !ins__is_jump(dl->ins) || 829 if (!disasm_line__is_valid_jump(dl, sym))
792 !disasm_line__has_offset(dl))
793 continue; 830 continue;
794 831
795 if (dl->ops.target.offset >= size) {
796 ui__error("jump to after symbol!\n"
797 "size: %zx, jump target: %" PRIx64,
798 size, dl->ops.target.offset);
799 continue;
800 }
801
802 dlt = browser->offsets[dl->ops.target.offset]; 832 dlt = browser->offsets[dl->ops.target.offset];
803 /* 833 /*
804 * FIXME: Oops, no jump target? Buggy disassembler? Or do we 834 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
@@ -825,7 +855,8 @@ static inline int width_jumps(int n)
825 return 1; 855 return 1;
826} 856}
827 857
828int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 858int symbol__tui_annotate(struct symbol *sym, struct map *map,
859 struct perf_evsel *evsel,
829 struct hist_browser_timer *hbt) 860 struct hist_browser_timer *hbt)
830{ 861{
831 struct disasm_line *pos, *n; 862 struct disasm_line *pos, *n;
@@ -846,6 +877,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
846 }, 877 },
847 }; 878 };
848 int ret = -1; 879 int ret = -1;
880 int nr_pcnt = 1;
881 size_t sizeof_bdl = sizeof(struct browser_disasm_line);
849 882
850 if (sym == NULL) 883 if (sym == NULL)
851 return -1; 884 return -1;
@@ -861,7 +894,12 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
861 return -1; 894 return -1;
862 } 895 }
863 896
864 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) { 897 if (perf_evsel__is_group_event(evsel)) {
898 nr_pcnt = evsel->nr_members;
899 sizeof_bdl += sizeof(double) * (nr_pcnt - 1);
900 }
901
902 if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
865 ui__error("%s", ui_helpline__last_msg); 903 ui__error("%s", ui_helpline__last_msg);
866 goto out_free_offsets; 904 goto out_free_offsets;
867 } 905 }
@@ -899,6 +937,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
899 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); 937 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
900 browser.max_addr_width = hex_width(sym->end); 938 browser.max_addr_width = hex_width(sym->end);
901 browser.jumps_width = width_jumps(browser.max_jump_sources); 939 browser.jumps_width = width_jumps(browser.max_jump_sources);
940 browser.nr_events = nr_pcnt;
902 browser.b.nr_entries = browser.nr_entries; 941 browser.b.nr_entries = browser.nr_entries;
903 browser.b.entries = &notes->src->source, 942 browser.b.entries = &notes->src->source,
904 browser.b.width += 18; /* Percentage */ 943 browser.b.width += 18; /* Percentage */
@@ -908,7 +947,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
908 947
909 annotate_browser__update_addr_width(&browser); 948 annotate_browser__update_addr_width(&browser);
910 949
911 ret = annotate_browser__run(&browser, evidx, hbt); 950 ret = annotate_browser__run(&browser, evsel, hbt);
912 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 951 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
913 list_del(&pos->node); 952 list_del(&pos->node);
914 disasm_line__free(pos); 953 disasm_line__free(pos);
@@ -921,11 +960,11 @@ out_free_offsets:
921 960
922#define ANNOTATE_CFG(n) \ 961#define ANNOTATE_CFG(n) \
923 { .name = #n, .value = &annotate_browser__opts.n, } 962 { .name = #n, .value = &annotate_browser__opts.n, }
924 963
925/* 964/*
926 * Keep the entries sorted, they are bsearch'ed 965 * Keep the entries sorted, they are bsearch'ed
927 */ 966 */
928static struct annotate__config { 967static struct annotate_config {
929 const char *name; 968 const char *name;
930 bool *value; 969 bool *value;
931} annotate__configs[] = { 970} annotate__configs[] = {
@@ -939,7 +978,7 @@ static struct annotate__config {
939 978
940static int annotate_config__cmp(const void *name, const void *cfgp) 979static int annotate_config__cmp(const void *name, const void *cfgp)
941{ 980{
942 const struct annotate__config *cfg = cfgp; 981 const struct annotate_config *cfg = cfgp;
943 982
944 return strcmp(name, cfg->name); 983 return strcmp(name, cfg->name);
945} 984}
@@ -947,7 +986,7 @@ static int annotate_config__cmp(const void *name, const void *cfgp)
947static int annotate__config(const char *var, const char *value, 986static int annotate__config(const char *var, const char *value,
948 void *data __maybe_unused) 987 void *data __maybe_unused)
949{ 988{
950 struct annotate__config *cfg; 989 struct annotate_config *cfg;
951 const char *name; 990 const char *name;
952 991
953 if (prefixcmp(var, "annotate.") != 0) 992 if (prefixcmp(var, "annotate.") != 0)
@@ -955,7 +994,7 @@ static int annotate__config(const char *var, const char *value,
955 994
956 name = var + 9; 995 name = var + 9;
957 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), 996 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
958 sizeof(struct annotate__config), annotate_config__cmp); 997 sizeof(struct annotate_config), annotate_config__cmp);
959 998
960 if (cfg == NULL) 999 if (cfg == NULL)
961 return -1; 1000 return -1;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index ccc4bd161420..fc0bd3843d34 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2,7 +2,6 @@
2#include "../libslang.h" 2#include "../libslang.h"
3#include <stdlib.h> 3#include <stdlib.h>
4#include <string.h> 4#include <string.h>
5#include <newt.h>
6#include <linux/rbtree.h> 5#include <linux/rbtree.h>
7 6
8#include "../../util/evsel.h" 7#include "../../util/evsel.h"
@@ -26,7 +25,8 @@ struct hist_browser {
26 struct map_symbol *selection; 25 struct map_symbol *selection;
27 int print_seq; 26 int print_seq;
28 bool show_dso; 27 bool show_dso;
29 bool has_symbols; 28 float min_pcnt;
29 u64 nr_pcnt_entries;
30}; 30};
31 31
32extern void hist_browser__init_hpp(void); 32extern void hist_browser__init_hpp(void);
@@ -310,6 +310,8 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
310 "Or reduce the sampling frequency."); 310 "Or reduce the sampling frequency.");
311} 311}
312 312
313static void hist_browser__update_pcnt_entries(struct hist_browser *hb);
314
313static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 315static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
314 struct hist_browser_timer *hbt) 316 struct hist_browser_timer *hbt)
315{ 317{
@@ -319,6 +321,8 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
319 321
320 browser->b.entries = &browser->hists->entries; 322 browser->b.entries = &browser->hists->entries;
321 browser->b.nr_entries = browser->hists->nr_entries; 323 browser->b.nr_entries = browser->hists->nr_entries;
324 if (browser->min_pcnt)
325 browser->b.nr_entries = browser->nr_pcnt_entries;
322 326
323 hist_browser__refresh_dimensions(browser); 327 hist_browser__refresh_dimensions(browser);
324 hists__browser_title(browser->hists, title, sizeof(title), ev_name); 328 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
@@ -331,9 +335,18 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
331 key = ui_browser__run(&browser->b, delay_secs); 335 key = ui_browser__run(&browser->b, delay_secs);
332 336
333 switch (key) { 337 switch (key) {
334 case K_TIMER: 338 case K_TIMER: {
339 u64 nr_entries;
335 hbt->timer(hbt->arg); 340 hbt->timer(hbt->arg);
336 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 341
342 if (browser->min_pcnt) {
343 hist_browser__update_pcnt_entries(browser);
344 nr_entries = browser->nr_pcnt_entries;
345 } else {
346 nr_entries = browser->hists->nr_entries;
347 }
348
349 ui_browser__update_nr_entries(&browser->b, nr_entries);
337 350
338 if (browser->hists->stats.nr_lost_warned != 351 if (browser->hists->stats.nr_lost_warned !=
339 browser->hists->stats.nr_events[PERF_RECORD_LOST]) { 352 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
@@ -345,6 +358,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
345 hists__browser_title(browser->hists, title, sizeof(title), ev_name); 358 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
346 ui_browser__show_title(&browser->b, title); 359 ui_browser__show_title(&browser->b, title);
347 continue; 360 continue;
361 }
348 case 'D': { /* Debug */ 362 case 'D': { /* Debug */
349 static int seq; 363 static int seq;
350 struct hist_entry *h = rb_entry(browser->b.top, 364 struct hist_entry *h = rb_entry(browser->b.top,
@@ -567,26 +581,128 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
567 return row - first_row; 581 return row - first_row;
568} 582}
569 583
570#define HPP__COLOR_FN(_name, _field) \ 584struct hpp_arg {
571static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ 585 struct ui_browser *b;
572 struct hist_entry *he) \ 586 char folded_sign;
587 bool current_entry;
588};
589
590static int __hpp__color_callchain(struct hpp_arg *arg)
591{
592 if (!symbol_conf.use_callchain)
593 return 0;
594
595 slsmg_printf("%c ", arg->folded_sign);
596 return 2;
597}
598
599static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
600 u64 (*get_field)(struct hist_entry *),
601 int (*callchain_cb)(struct hpp_arg *))
602{
603 int ret = 0;
604 double percent = 0.0;
605 struct hists *hists = he->hists;
606 struct hpp_arg *arg = hpp->ptr;
607
608 if (hists->stats.total_period)
609 percent = 100.0 * get_field(he) / hists->stats.total_period;
610
611 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
612
613 if (callchain_cb)
614 ret += callchain_cb(arg);
615
616 ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
617 slsmg_printf("%s", hpp->buf);
618
619 if (symbol_conf.event_group) {
620 int prev_idx, idx_delta;
621 struct perf_evsel *evsel = hists_to_evsel(hists);
622 struct hist_entry *pair;
623 int nr_members = evsel->nr_members;
624
625 if (nr_members <= 1)
626 goto out;
627
628 prev_idx = perf_evsel__group_idx(evsel);
629
630 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
631 u64 period = get_field(pair);
632 u64 total = pair->hists->stats.total_period;
633
634 if (!total)
635 continue;
636
637 evsel = hists_to_evsel(pair->hists);
638 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
639
640 while (idx_delta--) {
641 /*
642 * zero-fill group members in the middle which
643 * have no sample
644 */
645 ui_browser__set_percent_color(arg->b, 0.0,
646 arg->current_entry);
647 ret += scnprintf(hpp->buf, hpp->size,
648 " %6.2f%%", 0.0);
649 slsmg_printf("%s", hpp->buf);
650 }
651
652 percent = 100.0 * period / total;
653 ui_browser__set_percent_color(arg->b, percent,
654 arg->current_entry);
655 ret += scnprintf(hpp->buf, hpp->size,
656 " %6.2f%%", percent);
657 slsmg_printf("%s", hpp->buf);
658
659 prev_idx = perf_evsel__group_idx(evsel);
660 }
661
662 idx_delta = nr_members - prev_idx - 1;
663
664 while (idx_delta--) {
665 /*
666 * zero-fill group members at last which have no sample
667 */
668 ui_browser__set_percent_color(arg->b, 0.0,
669 arg->current_entry);
670 ret += scnprintf(hpp->buf, hpp->size,
671 " %6.2f%%", 0.0);
672 slsmg_printf("%s", hpp->buf);
673 }
674 }
675out:
676 if (!arg->current_entry || !arg->b->navkeypressed)
677 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
678
679 return ret;
680}
681
682#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \
683static u64 __hpp_get_##_field(struct hist_entry *he) \
684{ \
685 return he->stat._field; \
686} \
687 \
688static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \
689 struct hist_entry *he) \
573{ \ 690{ \
574 struct hists *hists = he->hists; \ 691 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
575 double percent = 100.0 * he->stat._field / hists->stats.total_period; \
576 *(double *)hpp->ptr = percent; \
577 return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
578} 692}
579 693
580HPP__COLOR_FN(overhead, period) 694__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
581HPP__COLOR_FN(overhead_sys, period_sys) 695__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
582HPP__COLOR_FN(overhead_us, period_us) 696__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
583HPP__COLOR_FN(overhead_guest_sys, period_guest_sys) 697__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
584HPP__COLOR_FN(overhead_guest_us, period_guest_us) 698__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
585 699
586#undef HPP__COLOR_FN 700#undef __HPP_COLOR_PERCENT_FN
587 701
588void hist_browser__init_hpp(void) 702void hist_browser__init_hpp(void)
589{ 703{
704 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
705
590 perf_hpp__init(); 706 perf_hpp__init();
591 707
592 perf_hpp__format[PERF_HPP__OVERHEAD].color = 708 perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -606,13 +722,13 @@ static int hist_browser__show_entry(struct hist_browser *browser,
606 unsigned short row) 722 unsigned short row)
607{ 723{
608 char s[256]; 724 char s[256];
609 double percent; 725 int printed = 0;
610 int i, printed = 0;
611 int width = browser->b.width; 726 int width = browser->b.width;
612 char folded_sign = ' '; 727 char folded_sign = ' ';
613 bool current_entry = ui_browser__is_current_entry(&browser->b, row); 728 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
614 off_t row_offset = entry->row_offset; 729 off_t row_offset = entry->row_offset;
615 bool first = true; 730 bool first = true;
731 struct perf_hpp_fmt *fmt;
616 732
617 if (current_entry) { 733 if (current_entry) {
618 browser->he_selection = entry; 734 browser->he_selection = entry;
@@ -625,41 +741,30 @@ static int hist_browser__show_entry(struct hist_browser *browser,
625 } 741 }
626 742
627 if (row_offset == 0) { 743 if (row_offset == 0) {
744 struct hpp_arg arg = {
745 .b = &browser->b,
746 .folded_sign = folded_sign,
747 .current_entry = current_entry,
748 };
628 struct perf_hpp hpp = { 749 struct perf_hpp hpp = {
629 .buf = s, 750 .buf = s,
630 .size = sizeof(s), 751 .size = sizeof(s),
752 .ptr = &arg,
631 }; 753 };
632 754
633 ui_browser__gotorc(&browser->b, row, 0); 755 ui_browser__gotorc(&browser->b, row, 0);
634 756
635 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 757 perf_hpp__for_each_format(fmt) {
636 if (!perf_hpp__format[i].cond)
637 continue;
638
639 if (!first) { 758 if (!first) {
640 slsmg_printf(" "); 759 slsmg_printf(" ");
641 width -= 2; 760 width -= 2;
642 } 761 }
643 first = false; 762 first = false;
644 763
645 if (perf_hpp__format[i].color) { 764 if (fmt->color) {
646 hpp.ptr = &percent; 765 width -= fmt->color(&hpp, entry);
647 /* It will set percent for us. See HPP__COLOR_FN above. */
648 width -= perf_hpp__format[i].color(&hpp, entry);
649
650 ui_browser__set_percent_color(&browser->b, percent, current_entry);
651
652 if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) {
653 slsmg_printf("%c ", folded_sign);
654 width -= 2;
655 }
656
657 slsmg_printf("%s", s);
658
659 if (!current_entry || !browser->b.navkeypressed)
660 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
661 } else { 766 } else {
662 width -= perf_hpp__format[i].entry(&hpp, entry); 767 width -= fmt->entry(&hpp, entry);
663 slsmg_printf("%s", s); 768 slsmg_printf("%s", s);
664 } 769 }
665 } 770 }
@@ -706,10 +811,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
706 811
707 for (nd = browser->top; nd; nd = rb_next(nd)) { 812 for (nd = browser->top; nd; nd = rb_next(nd)) {
708 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 813 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
814 float percent = h->stat.period * 100.0 /
815 hb->hists->stats.total_period;
709 816
710 if (h->filtered) 817 if (h->filtered)
711 continue; 818 continue;
712 819
820 if (percent < hb->min_pcnt)
821 continue;
822
713 row += hist_browser__show_entry(hb, h, row); 823 row += hist_browser__show_entry(hb, h, row);
714 if (row == browser->height) 824 if (row == browser->height)
715 break; 825 break;
@@ -718,10 +828,18 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
718 return row; 828 return row;
719} 829}
720 830
721static struct rb_node *hists__filter_entries(struct rb_node *nd) 831static struct rb_node *hists__filter_entries(struct rb_node *nd,
832 struct hists *hists,
833 float min_pcnt)
722{ 834{
723 while (nd != NULL) { 835 while (nd != NULL) {
724 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 836 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
837 float percent = h->stat.period * 100.0 /
838 hists->stats.total_period;
839
840 if (percent < min_pcnt)
841 return NULL;
842
725 if (!h->filtered) 843 if (!h->filtered)
726 return nd; 844 return nd;
727 845
@@ -731,11 +849,16 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd)
731 return NULL; 849 return NULL;
732} 850}
733 851
734static struct rb_node *hists__filter_prev_entries(struct rb_node *nd) 852static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
853 struct hists *hists,
854 float min_pcnt)
735{ 855{
736 while (nd != NULL) { 856 while (nd != NULL) {
737 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 857 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
738 if (!h->filtered) 858 float percent = h->stat.period * 100.0 /
859 hists->stats.total_period;
860
861 if (!h->filtered && percent >= min_pcnt)
739 return nd; 862 return nd;
740 863
741 nd = rb_prev(nd); 864 nd = rb_prev(nd);
@@ -750,6 +873,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
750 struct hist_entry *h; 873 struct hist_entry *h;
751 struct rb_node *nd; 874 struct rb_node *nd;
752 bool first = true; 875 bool first = true;
876 struct hist_browser *hb;
877
878 hb = container_of(browser, struct hist_browser, b);
753 879
754 if (browser->nr_entries == 0) 880 if (browser->nr_entries == 0)
755 return; 881 return;
@@ -758,13 +884,15 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
758 884
759 switch (whence) { 885 switch (whence) {
760 case SEEK_SET: 886 case SEEK_SET:
761 nd = hists__filter_entries(rb_first(browser->entries)); 887 nd = hists__filter_entries(rb_first(browser->entries),
888 hb->hists, hb->min_pcnt);
762 break; 889 break;
763 case SEEK_CUR: 890 case SEEK_CUR:
764 nd = browser->top; 891 nd = browser->top;
765 goto do_offset; 892 goto do_offset;
766 case SEEK_END: 893 case SEEK_END:
767 nd = hists__filter_prev_entries(rb_last(browser->entries)); 894 nd = hists__filter_prev_entries(rb_last(browser->entries),
895 hb->hists, hb->min_pcnt);
768 first = false; 896 first = false;
769 break; 897 break;
770 default: 898 default:
@@ -807,7 +935,8 @@ do_offset:
807 break; 935 break;
808 } 936 }
809 } 937 }
810 nd = hists__filter_entries(rb_next(nd)); 938 nd = hists__filter_entries(rb_next(nd), hb->hists,
939 hb->min_pcnt);
811 if (nd == NULL) 940 if (nd == NULL)
812 break; 941 break;
813 --offset; 942 --offset;
@@ -840,7 +969,8 @@ do_offset:
840 } 969 }
841 } 970 }
842 971
843 nd = hists__filter_prev_entries(rb_prev(nd)); 972 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
973 hb->min_pcnt);
844 if (nd == NULL) 974 if (nd == NULL)
845 break; 975 break;
846 ++offset; 976 ++offset;
@@ -1009,14 +1139,17 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1009 1139
1010static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1140static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1011{ 1141{
1012 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries)); 1142 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1143 browser->hists,
1144 browser->min_pcnt);
1013 int printed = 0; 1145 int printed = 0;
1014 1146
1015 while (nd) { 1147 while (nd) {
1016 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1148 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1017 1149
1018 printed += hist_browser__fprintf_entry(browser, h, fp); 1150 printed += hist_browser__fprintf_entry(browser, h, fp);
1019 nd = hists__filter_entries(rb_next(nd)); 1151 nd = hists__filter_entries(rb_next(nd), browser->hists,
1152 browser->min_pcnt);
1020 } 1153 }
1021 1154
1022 return printed; 1155 return printed;
@@ -1065,10 +1198,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
1065 browser->b.refresh = hist_browser__refresh; 1198 browser->b.refresh = hist_browser__refresh;
1066 browser->b.seek = ui_browser__hists_seek; 1199 browser->b.seek = ui_browser__hists_seek;
1067 browser->b.use_navkeypressed = true; 1200 browser->b.use_navkeypressed = true;
1068 if (sort__branch_mode == 1)
1069 browser->has_symbols = sort_sym_from.list.next != NULL;
1070 else
1071 browser->has_symbols = sort_sym.list.next != NULL;
1072 } 1201 }
1073 1202
1074 return browser; 1203 return browser;
@@ -1098,6 +1227,21 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1098 const struct thread *thread = hists->thread_filter; 1227 const struct thread *thread = hists->thread_filter;
1099 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 1228 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1100 u64 nr_events = hists->stats.total_period; 1229 u64 nr_events = hists->stats.total_period;
1230 struct perf_evsel *evsel = hists_to_evsel(hists);
1231 char buf[512];
1232 size_t buflen = sizeof(buf);
1233
1234 if (perf_evsel__is_group_event(evsel)) {
1235 struct perf_evsel *pos;
1236
1237 perf_evsel__group_desc(evsel, buf, buflen);
1238 ev_name = buf;
1239
1240 for_each_group_member(pos, evsel) {
1241 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1242 nr_events += pos->hists.stats.total_period;
1243 }
1244 }
1101 1245
1102 nr_samples = convert_unit(nr_samples, &unit); 1246 nr_samples = convert_unit(nr_samples, &unit);
1103 printed = scnprintf(bf, size, 1247 printed = scnprintf(bf, size,
@@ -1135,10 +1279,114 @@ static inline bool is_report_browser(void *timer)
1135 return timer == NULL; 1279 return timer == NULL;
1136} 1280}
1137 1281
1282/*
1283 * Only runtime switching of perf data file will make "input_name" point
1284 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1285 * whether we need to call free() for current "input_name" during the switch.
1286 */
1287static bool is_input_name_malloced = false;
1288
1289static int switch_data_file(void)
1290{
1291 char *pwd, *options[32], *abs_path[32], *tmp;
1292 DIR *pwd_dir;
1293 int nr_options = 0, choice = -1, ret = -1;
1294 struct dirent *dent;
1295
1296 pwd = getenv("PWD");
1297 if (!pwd)
1298 return ret;
1299
1300 pwd_dir = opendir(pwd);
1301 if (!pwd_dir)
1302 return ret;
1303
1304 memset(options, 0, sizeof(options));
1305 memset(options, 0, sizeof(abs_path));
1306
1307 while ((dent = readdir(pwd_dir))) {
1308 char path[PATH_MAX];
1309 u64 magic;
1310 char *name = dent->d_name;
1311 FILE *file;
1312
1313 if (!(dent->d_type == DT_REG))
1314 continue;
1315
1316 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1317
1318 file = fopen(path, "r");
1319 if (!file)
1320 continue;
1321
1322 if (fread(&magic, 1, 8, file) < 8)
1323 goto close_file_and_continue;
1324
1325 if (is_perf_magic(magic)) {
1326 options[nr_options] = strdup(name);
1327 if (!options[nr_options])
1328 goto close_file_and_continue;
1329
1330 abs_path[nr_options] = strdup(path);
1331 if (!abs_path[nr_options]) {
1332 free(options[nr_options]);
1333 ui__warning("Can't search all data files due to memory shortage.\n");
1334 fclose(file);
1335 break;
1336 }
1337
1338 nr_options++;
1339 }
1340
1341close_file_and_continue:
1342 fclose(file);
1343 if (nr_options >= 32) {
1344 ui__warning("Too many perf data files in PWD!\n"
1345 "Only the first 32 files will be listed.\n");
1346 break;
1347 }
1348 }
1349 closedir(pwd_dir);
1350
1351 if (nr_options) {
1352 choice = ui__popup_menu(nr_options, options);
1353 if (choice < nr_options && choice >= 0) {
1354 tmp = strdup(abs_path[choice]);
1355 if (tmp) {
1356 if (is_input_name_malloced)
1357 free((void *)input_name);
1358 input_name = tmp;
1359 is_input_name_malloced = true;
1360 ret = 0;
1361 } else
1362 ui__warning("Data switch failed due to memory shortage!\n");
1363 }
1364 }
1365
1366 free_popup_options(options, nr_options);
1367 free_popup_options(abs_path, nr_options);
1368 return ret;
1369}
1370
1371static void hist_browser__update_pcnt_entries(struct hist_browser *hb)
1372{
1373 u64 nr_entries = 0;
1374 struct rb_node *nd = rb_first(&hb->hists->entries);
1375
1376 while (nd) {
1377 nr_entries++;
1378 nd = hists__filter_entries(rb_next(nd), hb->hists,
1379 hb->min_pcnt);
1380 }
1381
1382 hb->nr_pcnt_entries = nr_entries;
1383}
1384
1138static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1385static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1139 const char *helpline, const char *ev_name, 1386 const char *helpline, const char *ev_name,
1140 bool left_exits, 1387 bool left_exits,
1141 struct hist_browser_timer *hbt, 1388 struct hist_browser_timer *hbt,
1389 float min_pcnt,
1142 struct perf_session_env *env) 1390 struct perf_session_env *env)
1143{ 1391{
1144 struct hists *hists = &evsel->hists; 1392 struct hists *hists = &evsel->hists;
@@ -1155,6 +1403,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1155 if (browser == NULL) 1403 if (browser == NULL)
1156 return -1; 1404 return -1;
1157 1405
1406 if (min_pcnt) {
1407 browser->min_pcnt = min_pcnt;
1408 hist_browser__update_pcnt_entries(browser);
1409 }
1410
1158 fstack = pstack__new(2); 1411 fstack = pstack__new(2);
1159 if (fstack == NULL) 1412 if (fstack == NULL)
1160 goto out; 1413 goto out;
@@ -1169,7 +1422,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1169 int choice = 0, 1422 int choice = 0,
1170 annotate = -2, zoom_dso = -2, zoom_thread = -2, 1423 annotate = -2, zoom_dso = -2, zoom_thread = -2,
1171 annotate_f = -2, annotate_t = -2, browse_map = -2; 1424 annotate_f = -2, annotate_t = -2, browse_map = -2;
1172 int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2; 1425 int scripts_comm = -2, scripts_symbol = -2,
1426 scripts_all = -2, switch_data = -2;
1173 1427
1174 nr_options = 0; 1428 nr_options = 0;
1175 1429
@@ -1190,7 +1444,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1190 */ 1444 */
1191 goto out_free_stack; 1445 goto out_free_stack;
1192 case 'a': 1446 case 'a':
1193 if (!browser->has_symbols) { 1447 if (!sort__has_sym) {
1194 ui_browser__warning(&browser->b, delay_secs * 2, 1448 ui_browser__warning(&browser->b, delay_secs * 2,
1195 "Annotation is only available for symbolic views, " 1449 "Annotation is only available for symbolic views, "
1196 "include \"sym*\" in --sort to use it."); 1450 "include \"sym*\" in --sort to use it.");
@@ -1226,6 +1480,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1226 if (is_report_browser(hbt)) 1480 if (is_report_browser(hbt))
1227 goto do_scripts; 1481 goto do_scripts;
1228 continue; 1482 continue;
1483 case 's':
1484 if (is_report_browser(hbt))
1485 goto do_data_switch;
1486 continue;
1229 case K_F1: 1487 case K_F1:
1230 case 'h': 1488 case 'h':
1231 case '?': 1489 case '?':
@@ -1245,6 +1503,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1245 "d Zoom into current DSO\n" 1503 "d Zoom into current DSO\n"
1246 "t Zoom into current Thread\n" 1504 "t Zoom into current Thread\n"
1247 "r Run available scripts('perf report' only)\n" 1505 "r Run available scripts('perf report' only)\n"
1506 "s Switch to another data file in PWD ('perf report' only)\n"
1248 "P Print histograms to perf.hist.N\n" 1507 "P Print histograms to perf.hist.N\n"
1249 "V Verbose (DSO names in callchains, etc)\n" 1508 "V Verbose (DSO names in callchains, etc)\n"
1250 "/ Filter symbol by name"); 1509 "/ Filter symbol by name");
@@ -1284,10 +1543,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1284 continue; 1543 continue;
1285 } 1544 }
1286 1545
1287 if (!browser->has_symbols) 1546 if (!sort__has_sym)
1288 goto add_exit_option; 1547 goto add_exit_option;
1289 1548
1290 if (sort__branch_mode == 1) { 1549 if (sort__mode == SORT_MODE__BRANCH) {
1291 bi = browser->he_selection->branch_info; 1550 bi = browser->he_selection->branch_info;
1292 if (browser->selection != NULL && 1551 if (browser->selection != NULL &&
1293 bi && 1552 bi &&
@@ -1352,6 +1611,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1352 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) 1611 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1353 scripts_all = nr_options++; 1612 scripts_all = nr_options++;
1354 1613
1614 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1615 "Switch to another data file in PWD") > 0)
1616 switch_data = nr_options++;
1355add_exit_option: 1617add_exit_option:
1356 options[nr_options++] = (char *)"Exit"; 1618 options[nr_options++] = (char *)"Exit";
1357retry_popup_menu: 1619retry_popup_menu:
@@ -1394,7 +1656,7 @@ do_annotate:
1394 * Don't let this be freed, say, by hists__decay_entry. 1656 * Don't let this be freed, say, by hists__decay_entry.
1395 */ 1657 */
1396 he->used = true; 1658 he->used = true;
1397 err = hist_entry__tui_annotate(he, evsel->idx, hbt); 1659 err = hist_entry__tui_annotate(he, evsel, hbt);
1398 he->used = false; 1660 he->used = false;
1399 /* 1661 /*
1400 * offer option to annotate the other branch source or target 1662 * offer option to annotate the other branch source or target
@@ -1462,6 +1724,16 @@ do_scripts:
1462 1724
1463 script_browse(script_opt); 1725 script_browse(script_opt);
1464 } 1726 }
1727 /* Switch to another data file */
1728 else if (choice == switch_data) {
1729do_data_switch:
1730 if (!switch_data_file()) {
1731 key = K_SWITCH_INPUT_DATA;
1732 break;
1733 } else
1734 ui__warning("Won't switch the data files due to\n"
1735 "no valid data file get selected!\n");
1736 }
1465 } 1737 }
1466out_free_stack: 1738out_free_stack:
1467 pstack__delete(fstack); 1739 pstack__delete(fstack);
@@ -1475,6 +1747,7 @@ struct perf_evsel_menu {
1475 struct ui_browser b; 1747 struct ui_browser b;
1476 struct perf_evsel *selection; 1748 struct perf_evsel *selection;
1477 bool lost_events, lost_events_warned; 1749 bool lost_events, lost_events_warned;
1750 float min_pcnt;
1478 struct perf_session_env *env; 1751 struct perf_session_env *env;
1479}; 1752};
1480 1753
@@ -1494,6 +1767,16 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1494 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1767 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1495 HE_COLORSET_NORMAL); 1768 HE_COLORSET_NORMAL);
1496 1769
1770 if (perf_evsel__is_group_event(evsel)) {
1771 struct perf_evsel *pos;
1772
1773 ev_name = perf_evsel__group_name(evsel);
1774
1775 for_each_group_member(pos, evsel) {
1776 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1777 }
1778 }
1779
1497 nr_events = convert_unit(nr_events, &unit); 1780 nr_events = convert_unit(nr_events, &unit);
1498 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1781 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1499 unit, unit == ' ' ? "" : " ", ev_name); 1782 unit, unit == ' ' ? "" : " ", ev_name);
@@ -1558,6 +1841,7 @@ browse_hists:
1558 ev_name = perf_evsel__name(pos); 1841 ev_name = perf_evsel__name(pos);
1559 key = perf_evsel__hists_browse(pos, nr_events, help, 1842 key = perf_evsel__hists_browse(pos, nr_events, help,
1560 ev_name, true, hbt, 1843 ev_name, true, hbt,
1844 menu->min_pcnt,
1561 menu->env); 1845 menu->env);
1562 ui_browser__show_title(&menu->b, title); 1846 ui_browser__show_title(&menu->b, title);
1563 switch (key) { 1847 switch (key) {
@@ -1578,6 +1862,7 @@ browse_hists:
1578 "Do you really want to exit?")) 1862 "Do you really want to exit?"))
1579 continue; 1863 continue;
1580 /* Fall thru */ 1864 /* Fall thru */
1865 case K_SWITCH_INPUT_DATA:
1581 case 'q': 1866 case 'q':
1582 case CTRL('c'): 1867 case CTRL('c'):
1583 goto out; 1868 goto out;
@@ -1604,9 +1889,21 @@ out:
1604 return key; 1889 return key;
1605} 1890}
1606 1891
1892static bool filter_group_entries(struct ui_browser *self __maybe_unused,
1893 void *entry)
1894{
1895 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1896
1897 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1898 return true;
1899
1900 return false;
1901}
1902
1607static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1903static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1608 const char *help, 1904 int nr_entries, const char *help,
1609 struct hist_browser_timer *hbt, 1905 struct hist_browser_timer *hbt,
1906 float min_pcnt,
1610 struct perf_session_env *env) 1907 struct perf_session_env *env)
1611{ 1908{
1612 struct perf_evsel *pos; 1909 struct perf_evsel *pos;
@@ -1616,9 +1913,11 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1616 .refresh = ui_browser__list_head_refresh, 1913 .refresh = ui_browser__list_head_refresh,
1617 .seek = ui_browser__list_head_seek, 1914 .seek = ui_browser__list_head_seek,
1618 .write = perf_evsel_menu__write, 1915 .write = perf_evsel_menu__write,
1619 .nr_entries = evlist->nr_entries, 1916 .filter = filter_group_entries,
1917 .nr_entries = nr_entries,
1620 .priv = evlist, 1918 .priv = evlist,
1621 }, 1919 },
1920 .min_pcnt = min_pcnt,
1622 .env = env, 1921 .env = env,
1623 }; 1922 };
1624 1923
@@ -1632,20 +1931,39 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1632 menu.b.width = line_len; 1931 menu.b.width = line_len;
1633 } 1932 }
1634 1933
1635 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, hbt); 1934 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
1636} 1935}
1637 1936
1638int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 1937int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1639 struct hist_browser_timer *hbt, 1938 struct hist_browser_timer *hbt,
1939 float min_pcnt,
1640 struct perf_session_env *env) 1940 struct perf_session_env *env)
1641{ 1941{
1642 if (evlist->nr_entries == 1) { 1942 int nr_entries = evlist->nr_entries;
1943
1944single_entry:
1945 if (nr_entries == 1) {
1643 struct perf_evsel *first = list_entry(evlist->entries.next, 1946 struct perf_evsel *first = list_entry(evlist->entries.next,
1644 struct perf_evsel, node); 1947 struct perf_evsel, node);
1645 const char *ev_name = perf_evsel__name(first); 1948 const char *ev_name = perf_evsel__name(first);
1646 return perf_evsel__hists_browse(first, evlist->nr_entries, help, 1949
1647 ev_name, false, hbt, env); 1950 return perf_evsel__hists_browse(first, nr_entries, help,
1951 ev_name, false, hbt, min_pcnt,
1952 env);
1953 }
1954
1955 if (symbol_conf.event_group) {
1956 struct perf_evsel *pos;
1957
1958 nr_entries = 0;
1959 list_for_each_entry(pos, &evlist->entries, node)
1960 if (perf_evsel__is_group_leader(pos))
1961 nr_entries++;
1962
1963 if (nr_entries == 1)
1964 goto single_entry;
1648 } 1965 }
1649 1966
1650 return __perf_evlist__tui_browse_hists(evlist, help, hbt, env); 1967 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
1968 hbt, min_pcnt, env);
1651} 1969}
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 98851d55a53e..95c7cfb8f2c6 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -1,6 +1,5 @@
1#include "../libslang.h" 1#include "../libslang.h"
2#include <elf.h> 2#include <elf.h>
3#include <newt.h>
4#include <inttypes.h> 3#include <inttypes.h>
5#include <sys/ttydefaults.h> 4#include <sys/ttydefaults.h>
6#include <string.h> 5#include <string.h>
@@ -10,41 +9,9 @@
10#include "../../util/symbol.h" 9#include "../../util/symbol.h"
11#include "../browser.h" 10#include "../browser.h"
12#include "../helpline.h" 11#include "../helpline.h"
12#include "../keysyms.h"
13#include "map.h" 13#include "map.h"
14 14
15static int ui_entry__read(const char *title, char *bf, size_t size, int width)
16{
17 struct newtExitStruct es;
18 newtComponent form, entry;
19 const char *result;
20 int err = -1;
21
22 newtCenteredWindow(width, 1, title);
23 form = newtForm(NULL, NULL, 0);
24 if (form == NULL)
25 return -1;
26
27 entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
28 if (entry == NULL)
29 goto out_free_form;
30
31 newtFormAddComponent(form, entry);
32 newtFormAddHotKey(form, NEWT_KEY_ENTER);
33 newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
34 newtFormAddHotKey(form, NEWT_KEY_LEFT);
35 newtFormAddHotKey(form, CTRL('c'));
36 newtFormRun(form, &es);
37
38 if (result != NULL) {
39 strncpy(bf, result, size);
40 err = 0;
41 }
42out_free_form:
43 newtPopWindow();
44 newtFormDestroy(form);
45 return err;
46}
47
48struct map_browser { 15struct map_browser {
49 struct ui_browser b; 16 struct ui_browser b;
50 struct map *map; 17 struct map *map;
@@ -78,10 +45,11 @@ static int map_browser__search(struct map_browser *self)
78{ 45{
79 char target[512]; 46 char target[512];
80 struct symbol *sym; 47 struct symbol *sym;
81 int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40); 48 int err = ui_browser__input_window("Search by name/addr",
82 49 "Prefix with 0x to search by address",
83 if (err) 50 target, "ENTER: OK, ESC: Cancel", 0);
84 return err; 51 if (err != K_ENTER)
52 return -1;
85 53
86 if (target[0] == '0' && tolower(target[1]) == 'x') { 54 if (target[0] == '0' && tolower(target[1]) == 'x') {
87 u64 addr = strtoull(target, NULL, 16); 55 u64 addr = strtoull(target, NULL, 16);
@@ -112,12 +80,20 @@ static int map_browser__run(struct map_browser *self)
112 while (1) { 80 while (1) {
113 key = ui_browser__run(&self->b, 0); 81 key = ui_browser__run(&self->b, 0);
114 82
115 if (verbose && key == '/') 83 switch (key) {
116 map_browser__search(self); 84 case '/':
117 else 85 if (verbose)
86 map_browser__search(self);
87 default:
118 break; 88 break;
89 case K_LEFT:
90 case K_ESC:
91 case 'q':
92 case CTRL('c'):
93 goto out;
94 }
119 } 95 }
120 96out:
121 ui_browser__hide(&self->b); 97 ui_browser__hide(&self->b);
122 return key; 98 return key;
123} 99}
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index cbbd44b0d93e..12f009e61e94 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -1,5 +1,4 @@
1#include <elf.h> 1#include <elf.h>
2#include <newt.h>
3#include <inttypes.h> 2#include <inttypes.h>
4#include <sys/ttydefaults.h> 3#include <sys/ttydefaults.h>
5#include <string.h> 4#include <string.h>
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
new file mode 100644
index 000000000000..f538794615db
--- /dev/null
+++ b/tools/perf/ui/gtk/annotate.c
@@ -0,0 +1,245 @@
1#include "gtk.h"
2#include "util/debug.h"
3#include "util/annotate.h"
4#include "util/evsel.h"
5#include "ui/helpline.h"
6
7
8enum {
9 ANN_COL__PERCENT,
10 ANN_COL__OFFSET,
11 ANN_COL__LINE,
12
13 MAX_ANN_COLS
14};
15
16static const char *const col_names[] = {
17 "Overhead",
18 "Offset",
19 "Line"
20};
21
22static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
23 struct disasm_line *dl, int evidx)
24{
25 struct sym_hist *symhist;
26 double percent = 0.0;
27 const char *markup;
28 int ret = 0;
29
30 strcpy(buf, "");
31
32 if (dl->offset == (s64) -1)
33 return 0;
34
35 symhist = annotation__histogram(symbol__annotation(sym), evidx);
36 if (!symbol_conf.event_group && !symhist->addr[dl->offset])
37 return 0;
38
39 percent = 100.0 * symhist->addr[dl->offset] / symhist->sum;
40
41 markup = perf_gtk__get_percent_color(percent);
42 if (markup)
43 ret += scnprintf(buf, size, "%s", markup);
44 ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent);
45 if (markup)
46 ret += scnprintf(buf + ret, size - ret, "</span>");
47
48 return ret;
49}
50
51static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym,
52 struct map *map, struct disasm_line *dl)
53{
54 u64 start = map__rip_2objdump(map, sym->start);
55
56 strcpy(buf, "");
57
58 if (dl->offset == (s64) -1)
59 return 0;
60
61 return scnprintf(buf, size, "%"PRIx64, start + dl->offset);
62}
63
64static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
65{
66 int ret = 0;
67 char *line = g_markup_escape_text(dl->line, -1);
68 const char *markup = "<span fgcolor='gray'>";
69
70 strcpy(buf, "");
71
72 if (!line)
73 return 0;
74
75 if (dl->offset != (s64) -1)
76 markup = NULL;
77
78 if (markup)
79 ret += scnprintf(buf, size, "%s", markup);
80 ret += scnprintf(buf + ret, size - ret, "%s", line);
81 if (markup)
82 ret += scnprintf(buf + ret, size - ret, "</span>");
83
84 g_free(line);
85 return ret;
86}
87
88static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
89 struct map *map, struct perf_evsel *evsel,
90 struct hist_browser_timer *hbt __maybe_unused)
91{
92 struct disasm_line *pos, *n;
93 struct annotation *notes;
94 GType col_types[MAX_ANN_COLS];
95 GtkCellRenderer *renderer;
96 GtkListStore *store;
97 GtkWidget *view;
98 int i;
99 char s[512];
100
101 notes = symbol__annotation(sym);
102
103 for (i = 0; i < MAX_ANN_COLS; i++) {
104 col_types[i] = G_TYPE_STRING;
105 }
106 store = gtk_list_store_newv(MAX_ANN_COLS, col_types);
107
108 view = gtk_tree_view_new();
109 renderer = gtk_cell_renderer_text_new();
110
111 for (i = 0; i < MAX_ANN_COLS; i++) {
112 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
113 -1, col_names[i], renderer, "markup",
114 i, NULL);
115 }
116
117 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
118 g_object_unref(GTK_TREE_MODEL(store));
119
120 list_for_each_entry(pos, &notes->src->source, node) {
121 GtkTreeIter iter;
122 int ret = 0;
123
124 gtk_list_store_append(store, &iter);
125
126 if (perf_evsel__is_group_event(evsel)) {
127 for (i = 0; i < evsel->nr_members; i++) {
128 ret += perf_gtk__get_percent(s + ret,
129 sizeof(s) - ret,
130 sym, pos,
131 evsel->idx + i);
132 ret += scnprintf(s + ret, sizeof(s) - ret, " ");
133 }
134 } else {
135 ret = perf_gtk__get_percent(s, sizeof(s), sym, pos,
136 evsel->idx);
137 }
138
139 if (ret)
140 gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1);
141 if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos))
142 gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1);
143 if (perf_gtk__get_line(s, sizeof(s), pos))
144 gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1);
145 }
146
147 gtk_container_add(GTK_CONTAINER(window), view);
148
149 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
150 list_del(&pos->node);
151 disasm_line__free(pos);
152 }
153
154 return 0;
155}
156
157int symbol__gtk_annotate(struct symbol *sym, struct map *map,
158 struct perf_evsel *evsel,
159 struct hist_browser_timer *hbt)
160{
161 GtkWidget *window;
162 GtkWidget *notebook;
163 GtkWidget *scrolled_window;
164 GtkWidget *tab_label;
165
166 if (map->dso->annotate_warned)
167 return -1;
168
169 if (symbol__annotate(sym, map, 0) < 0) {
170 ui__error("%s", ui_helpline__current);
171 return -1;
172 }
173
174 if (perf_gtk__is_active_context(pgctx)) {
175 window = pgctx->main_window;
176 notebook = pgctx->notebook;
177 } else {
178 GtkWidget *vbox;
179 GtkWidget *infobar;
180 GtkWidget *statbar;
181
182 signal(SIGSEGV, perf_gtk__signal);
183 signal(SIGFPE, perf_gtk__signal);
184 signal(SIGINT, perf_gtk__signal);
185 signal(SIGQUIT, perf_gtk__signal);
186 signal(SIGTERM, perf_gtk__signal);
187
188 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
189 gtk_window_set_title(GTK_WINDOW(window), "perf annotate");
190
191 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
192
193 pgctx = perf_gtk__activate_context(window);
194 if (!pgctx)
195 return -1;
196
197 vbox = gtk_vbox_new(FALSE, 0);
198 notebook = gtk_notebook_new();
199 pgctx->notebook = notebook;
200
201 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
202
203 infobar = perf_gtk__setup_info_bar();
204 if (infobar) {
205 gtk_box_pack_start(GTK_BOX(vbox), infobar,
206 FALSE, FALSE, 0);
207 }
208
209 statbar = perf_gtk__setup_statusbar();
210 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
211
212 gtk_container_add(GTK_CONTAINER(window), vbox);
213 }
214
215 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
216 tab_label = gtk_label_new(sym->name);
217
218 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
219 GTK_POLICY_AUTOMATIC,
220 GTK_POLICY_AUTOMATIC);
221
222 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window,
223 tab_label);
224
225 perf_gtk__annotate_symbol(scrolled_window, sym, map, evsel, hbt);
226 return 0;
227}
228
229void perf_gtk__show_annotations(void)
230{
231 GtkWidget *window;
232
233 if (!perf_gtk__is_active_context(pgctx))
234 return;
235
236 window = pgctx->main_window;
237 gtk_widget_show_all(window);
238
239 perf_gtk__resize_window(window);
240 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
241
242 gtk_main();
243
244 perf_gtk__deactivate_context(&pgctx);
245}
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 253b6219a39e..c95012cdb438 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -8,15 +8,13 @@
8 8
9#include <signal.h> 9#include <signal.h>
10 10
11#define MAX_COLUMNS 32 11void perf_gtk__signal(int sig)
12
13static void perf_gtk__signal(int sig)
14{ 12{
15 perf_gtk__exit(false); 13 perf_gtk__exit(false);
16 psignal(sig, "perf"); 14 psignal(sig, "perf");
17} 15}
18 16
19static void perf_gtk__resize_window(GtkWidget *window) 17void perf_gtk__resize_window(GtkWidget *window)
20{ 18{
21 GdkRectangle rect; 19 GdkRectangle rect;
22 GdkScreen *screen; 20 GdkScreen *screen;
@@ -36,7 +34,7 @@ static void perf_gtk__resize_window(GtkWidget *window)
36 gtk_window_resize(GTK_WINDOW(window), width, height); 34 gtk_window_resize(GTK_WINDOW(window), width, height);
37} 35}
38 36
39static const char *perf_gtk__get_percent_color(double percent) 37const char *perf_gtk__get_percent_color(double percent)
40{ 38{
41 if (percent >= MIN_RED) 39 if (percent >= MIN_RED)
42 return "<span fgcolor='red'>"; 40 return "<span fgcolor='red'>";
@@ -45,155 +43,8 @@ static const char *perf_gtk__get_percent_color(double percent)
45 return NULL; 43 return NULL;
46} 44}
47 45
48#define HPP__COLOR_FN(_name, _field) \
49static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \
50 struct hist_entry *he) \
51{ \
52 struct hists *hists = he->hists; \
53 double percent = 100.0 * he->stat._field / hists->stats.total_period; \
54 const char *markup; \
55 int ret = 0; \
56 \
57 markup = perf_gtk__get_percent_color(percent); \
58 if (markup) \
59 ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \
60 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \
61 if (markup) \
62 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \
63 \
64 return ret; \
65}
66
67HPP__COLOR_FN(overhead, period)
68HPP__COLOR_FN(overhead_sys, period_sys)
69HPP__COLOR_FN(overhead_us, period_us)
70HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
71HPP__COLOR_FN(overhead_guest_us, period_guest_us)
72
73#undef HPP__COLOR_FN
74
75void perf_gtk__init_hpp(void)
76{
77 perf_hpp__init();
78
79 perf_hpp__format[PERF_HPP__OVERHEAD].color =
80 perf_gtk__hpp_color_overhead;
81 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
82 perf_gtk__hpp_color_overhead_sys;
83 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
84 perf_gtk__hpp_color_overhead_us;
85 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
86 perf_gtk__hpp_color_overhead_guest_sys;
87 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
88 perf_gtk__hpp_color_overhead_guest_us;
89}
90
91static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
92{
93 GType col_types[MAX_COLUMNS];
94 GtkCellRenderer *renderer;
95 struct sort_entry *se;
96 GtkListStore *store;
97 struct rb_node *nd;
98 GtkWidget *view;
99 int i, col_idx;
100 int nr_cols;
101 char s[512];
102
103 struct perf_hpp hpp = {
104 .buf = s,
105 .size = sizeof(s),
106 };
107
108 nr_cols = 0;
109
110 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
111 if (!perf_hpp__format[i].cond)
112 continue;
113
114 col_types[nr_cols++] = G_TYPE_STRING;
115 }
116
117 list_for_each_entry(se, &hist_entry__sort_list, list) {
118 if (se->elide)
119 continue;
120
121 col_types[nr_cols++] = G_TYPE_STRING;
122 }
123
124 store = gtk_list_store_newv(nr_cols, col_types);
125
126 view = gtk_tree_view_new();
127
128 renderer = gtk_cell_renderer_text_new();
129
130 col_idx = 0;
131
132 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
133 if (!perf_hpp__format[i].cond)
134 continue;
135
136 perf_hpp__format[i].header(&hpp);
137
138 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
139 -1, s,
140 renderer, "markup",
141 col_idx++, NULL);
142 }
143
144 list_for_each_entry(se, &hist_entry__sort_list, list) {
145 if (se->elide)
146 continue;
147
148 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
149 -1, se->se_header,
150 renderer, "text",
151 col_idx++, NULL);
152 }
153
154 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
155
156 g_object_unref(GTK_TREE_MODEL(store));
157
158 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
159 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
160 GtkTreeIter iter;
161
162 if (h->filtered)
163 continue;
164
165 gtk_list_store_append(store, &iter);
166
167 col_idx = 0;
168
169 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
170 if (!perf_hpp__format[i].cond)
171 continue;
172
173 if (perf_hpp__format[i].color)
174 perf_hpp__format[i].color(&hpp, h);
175 else
176 perf_hpp__format[i].entry(&hpp, h);
177
178 gtk_list_store_set(store, &iter, col_idx++, s, -1);
179 }
180
181 list_for_each_entry(se, &hist_entry__sort_list, list) {
182 if (se->elide)
183 continue;
184
185 se->se_snprintf(h, s, ARRAY_SIZE(s),
186 hists__col_len(hists, se->se_width_idx));
187
188 gtk_list_store_set(store, &iter, col_idx++, s, -1);
189 }
190 }
191
192 gtk_container_add(GTK_CONTAINER(window), view);
193}
194
195#ifdef HAVE_GTK_INFO_BAR 46#ifdef HAVE_GTK_INFO_BAR
196static GtkWidget *perf_gtk__setup_info_bar(void) 47GtkWidget *perf_gtk__setup_info_bar(void)
197{ 48{
198 GtkWidget *info_bar; 49 GtkWidget *info_bar;
199 GtkWidget *label; 50 GtkWidget *label;
@@ -220,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void)
220} 71}
221#endif 72#endif
222 73
223static GtkWidget *perf_gtk__setup_statusbar(void) 74GtkWidget *perf_gtk__setup_statusbar(void)
224{ 75{
225 GtkWidget *stbar; 76 GtkWidget *stbar;
226 unsigned ctxid; 77 unsigned ctxid;
@@ -234,79 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void)
234 85
235 return stbar; 86 return stbar;
236} 87}
237
238int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
239 const char *help,
240 struct hist_browser_timer *hbt __maybe_unused)
241{
242 struct perf_evsel *pos;
243 GtkWidget *vbox;
244 GtkWidget *notebook;
245 GtkWidget *info_bar;
246 GtkWidget *statbar;
247 GtkWidget *window;
248
249 signal(SIGSEGV, perf_gtk__signal);
250 signal(SIGFPE, perf_gtk__signal);
251 signal(SIGINT, perf_gtk__signal);
252 signal(SIGQUIT, perf_gtk__signal);
253 signal(SIGTERM, perf_gtk__signal);
254
255 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
256
257 gtk_window_set_title(GTK_WINDOW(window), "perf report");
258
259 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
260
261 pgctx = perf_gtk__activate_context(window);
262 if (!pgctx)
263 return -1;
264
265 vbox = gtk_vbox_new(FALSE, 0);
266
267 notebook = gtk_notebook_new();
268
269 list_for_each_entry(pos, &evlist->entries, node) {
270 struct hists *hists = &pos->hists;
271 const char *evname = perf_evsel__name(pos);
272 GtkWidget *scrolled_window;
273 GtkWidget *tab_label;
274
275 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
276
277 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
278 GTK_POLICY_AUTOMATIC,
279 GTK_POLICY_AUTOMATIC);
280
281 perf_gtk__show_hists(scrolled_window, hists);
282
283 tab_label = gtk_label_new(evname);
284
285 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
286 }
287
288 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
289
290 info_bar = perf_gtk__setup_info_bar();
291 if (info_bar)
292 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
293
294 statbar = perf_gtk__setup_statusbar();
295 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
296
297 gtk_container_add(GTK_CONTAINER(window), vbox);
298
299 gtk_widget_show_all(window);
300
301 perf_gtk__resize_window(window);
302
303 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
304
305 ui_helpline__push(help);
306
307 gtk_main();
308
309 perf_gtk__deactivate_context(&pgctx);
310
311 return 0;
312}
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 856320e2cc05..3d96785ef155 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -10,6 +10,7 @@
10 10
11struct perf_gtk_context { 11struct perf_gtk_context {
12 GtkWidget *main_window; 12 GtkWidget *main_window;
13 GtkWidget *notebook;
13 14
14#ifdef HAVE_GTK_INFO_BAR 15#ifdef HAVE_GTK_INFO_BAR
15 GtkWidget *info_bar; 16 GtkWidget *info_bar;
@@ -33,7 +34,14 @@ void perf_gtk__init_helpline(void);
33void perf_gtk__init_progress(void); 34void perf_gtk__init_progress(void);
34void perf_gtk__init_hpp(void); 35void perf_gtk__init_hpp(void);
35 36
36#ifndef HAVE_GTK_INFO_BAR 37void perf_gtk__signal(int sig);
38void perf_gtk__resize_window(GtkWidget *window);
39const char *perf_gtk__get_percent_color(double percent);
40GtkWidget *perf_gtk__setup_statusbar(void);
41
42#ifdef HAVE_GTK_INFO_BAR
43GtkWidget *perf_gtk__setup_info_bar(void);
44#else
37static inline GtkWidget *perf_gtk__setup_info_bar(void) 45static inline GtkWidget *perf_gtk__setup_info_bar(void)
38{ 46{
39 return NULL; 47 return NULL;
diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c
index 5db4432ff12a..3388cbd12186 100644
--- a/tools/perf/ui/gtk/helpline.c
+++ b/tools/perf/ui/gtk/helpline.c
@@ -24,17 +24,7 @@ static void gtk_helpline_push(const char *msg)
24 pgctx->statbar_ctx_id, msg); 24 pgctx->statbar_ctx_id, msg);
25} 25}
26 26
27static struct ui_helpline gtk_helpline_fns = { 27static int gtk_helpline_show(const char *fmt, va_list ap)
28 .pop = gtk_helpline_pop,
29 .push = gtk_helpline_push,
30};
31
32void perf_gtk__init_helpline(void)
33{
34 helpline_fns = &gtk_helpline_fns;
35}
36
37int perf_gtk__show_helpline(const char *fmt, va_list ap)
38{ 28{
39 int ret; 29 int ret;
40 char *ptr; 30 char *ptr;
@@ -54,3 +44,14 @@ int perf_gtk__show_helpline(const char *fmt, va_list ap)
54 44
55 return ret; 45 return ret;
56} 46}
47
48static struct ui_helpline gtk_helpline_fns = {
49 .pop = gtk_helpline_pop,
50 .push = gtk_helpline_push,
51 .show = gtk_helpline_show,
52};
53
54void perf_gtk__init_helpline(void)
55{
56 helpline_fns = &gtk_helpline_fns;
57}
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
new file mode 100644
index 000000000000..9708dd5fb8f3
--- /dev/null
+++ b/tools/perf/ui/gtk/hists.c
@@ -0,0 +1,316 @@
1#include "../evlist.h"
2#include "../cache.h"
3#include "../evsel.h"
4#include "../sort.h"
5#include "../hist.h"
6#include "../helpline.h"
7#include "gtk.h"
8
9#define MAX_COLUMNS 32
10
11static int __percent_color_snprintf(char *buf, size_t size, double percent)
12{
13 int ret = 0;
14 const char *markup;
15
16 markup = perf_gtk__get_percent_color(percent);
17 if (markup)
18 ret += scnprintf(buf, size, markup);
19
20 ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent);
21
22 if (markup)
23 ret += scnprintf(buf + ret, size - ret, "</span>");
24
25 return ret;
26}
27
28
29static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
30 u64 (*get_field)(struct hist_entry *))
31{
32 int ret;
33 double percent = 0.0;
34 struct hists *hists = he->hists;
35 struct perf_evsel *evsel = hists_to_evsel(hists);
36
37 if (hists->stats.total_period)
38 percent = 100.0 * get_field(he) / hists->stats.total_period;
39
40 ret = __percent_color_snprintf(hpp->buf, hpp->size, percent);
41
42 if (perf_evsel__is_group_event(evsel)) {
43 int prev_idx, idx_delta;
44 struct hist_entry *pair;
45 int nr_members = evsel->nr_members;
46
47 prev_idx = perf_evsel__group_idx(evsel);
48
49 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
50 u64 period = get_field(pair);
51 u64 total = pair->hists->stats.total_period;
52
53 evsel = hists_to_evsel(pair->hists);
54 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
55
56 while (idx_delta--) {
57 /*
58 * zero-fill group members in the middle which
59 * have no sample
60 */
61 ret += __percent_color_snprintf(hpp->buf + ret,
62 hpp->size - ret,
63 0.0);
64 }
65
66 percent = 100.0 * period / total;
67 ret += __percent_color_snprintf(hpp->buf + ret,
68 hpp->size - ret,
69 percent);
70
71 prev_idx = perf_evsel__group_idx(evsel);
72 }
73
74 idx_delta = nr_members - prev_idx - 1;
75
76 while (idx_delta--) {
77 /*
78 * zero-fill group members at last which have no sample
79 */
80 ret += __percent_color_snprintf(hpp->buf + ret,
81 hpp->size - ret,
82 0.0);
83 }
84 }
85 return ret;
86}
87
88#define __HPP_COLOR_PERCENT_FN(_type, _field) \
89static u64 he_get_##_field(struct hist_entry *he) \
90{ \
91 return he->stat._field; \
92} \
93 \
94static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \
95 struct hist_entry *he) \
96{ \
97 return __hpp__color_fmt(hpp, he, he_get_##_field); \
98}
99
100__HPP_COLOR_PERCENT_FN(overhead, period)
101__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
102__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
103__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
104__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
105
106#undef __HPP_COLOR_PERCENT_FN
107
108
109void perf_gtk__init_hpp(void)
110{
111 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
112
113 perf_hpp__init();
114
115 perf_hpp__format[PERF_HPP__OVERHEAD].color =
116 perf_gtk__hpp_color_overhead;
117 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
118 perf_gtk__hpp_color_overhead_sys;
119 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
120 perf_gtk__hpp_color_overhead_us;
121 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
122 perf_gtk__hpp_color_overhead_guest_sys;
123 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
124 perf_gtk__hpp_color_overhead_guest_us;
125}
126
127static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
128 float min_pcnt)
129{
130 struct perf_hpp_fmt *fmt;
131 GType col_types[MAX_COLUMNS];
132 GtkCellRenderer *renderer;
133 struct sort_entry *se;
134 GtkListStore *store;
135 struct rb_node *nd;
136 GtkWidget *view;
137 int col_idx;
138 int nr_cols;
139 char s[512];
140
141 struct perf_hpp hpp = {
142 .buf = s,
143 .size = sizeof(s),
144 .ptr = hists_to_evsel(hists),
145 };
146
147 nr_cols = 0;
148
149 perf_hpp__for_each_format(fmt)
150 col_types[nr_cols++] = G_TYPE_STRING;
151
152 list_for_each_entry(se, &hist_entry__sort_list, list) {
153 if (se->elide)
154 continue;
155
156 col_types[nr_cols++] = G_TYPE_STRING;
157 }
158
159 store = gtk_list_store_newv(nr_cols, col_types);
160
161 view = gtk_tree_view_new();
162
163 renderer = gtk_cell_renderer_text_new();
164
165 col_idx = 0;
166
167 perf_hpp__for_each_format(fmt) {
168 fmt->header(&hpp);
169
170 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
171 -1, ltrim(s),
172 renderer, "markup",
173 col_idx++, NULL);
174 }
175
176 list_for_each_entry(se, &hist_entry__sort_list, list) {
177 if (se->elide)
178 continue;
179
180 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
181 -1, se->se_header,
182 renderer, "text",
183 col_idx++, NULL);
184 }
185
186 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
187
188 g_object_unref(GTK_TREE_MODEL(store));
189
190 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
191 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
192 GtkTreeIter iter;
193 float percent = h->stat.period * 100.0 /
194 hists->stats.total_period;
195
196 if (h->filtered)
197 continue;
198
199 if (percent < min_pcnt)
200 continue;
201
202 gtk_list_store_append(store, &iter);
203
204 col_idx = 0;
205
206 perf_hpp__for_each_format(fmt) {
207 if (fmt->color)
208 fmt->color(&hpp, h);
209 else
210 fmt->entry(&hpp, h);
211
212 gtk_list_store_set(store, &iter, col_idx++, s, -1);
213 }
214
215 list_for_each_entry(se, &hist_entry__sort_list, list) {
216 if (se->elide)
217 continue;
218
219 se->se_snprintf(h, s, ARRAY_SIZE(s),
220 hists__col_len(hists, se->se_width_idx));
221
222 gtk_list_store_set(store, &iter, col_idx++, s, -1);
223 }
224 }
225
226 gtk_container_add(GTK_CONTAINER(window), view);
227}
228
229int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
230 const char *help,
231 struct hist_browser_timer *hbt __maybe_unused,
232 float min_pcnt)
233{
234 struct perf_evsel *pos;
235 GtkWidget *vbox;
236 GtkWidget *notebook;
237 GtkWidget *info_bar;
238 GtkWidget *statbar;
239 GtkWidget *window;
240
241 signal(SIGSEGV, perf_gtk__signal);
242 signal(SIGFPE, perf_gtk__signal);
243 signal(SIGINT, perf_gtk__signal);
244 signal(SIGQUIT, perf_gtk__signal);
245 signal(SIGTERM, perf_gtk__signal);
246
247 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
248
249 gtk_window_set_title(GTK_WINDOW(window), "perf report");
250
251 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
252
253 pgctx = perf_gtk__activate_context(window);
254 if (!pgctx)
255 return -1;
256
257 vbox = gtk_vbox_new(FALSE, 0);
258
259 notebook = gtk_notebook_new();
260
261 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
262
263 info_bar = perf_gtk__setup_info_bar();
264 if (info_bar)
265 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
266
267 statbar = perf_gtk__setup_statusbar();
268 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
269
270 gtk_container_add(GTK_CONTAINER(window), vbox);
271
272 list_for_each_entry(pos, &evlist->entries, node) {
273 struct hists *hists = &pos->hists;
274 const char *evname = perf_evsel__name(pos);
275 GtkWidget *scrolled_window;
276 GtkWidget *tab_label;
277 char buf[512];
278 size_t size = sizeof(buf);
279
280 if (symbol_conf.event_group) {
281 if (!perf_evsel__is_group_leader(pos))
282 continue;
283
284 if (pos->nr_members > 1) {
285 perf_evsel__group_desc(pos, buf, size);
286 evname = buf;
287 }
288 }
289
290 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
291
292 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
293 GTK_POLICY_AUTOMATIC,
294 GTK_POLICY_AUTOMATIC);
295
296 perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
297
298 tab_label = gtk_label_new(evname);
299
300 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
301 }
302
303 gtk_widget_show_all(window);
304
305 perf_gtk__resize_window(window);
306
307 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
308
309 ui_helpline__push(help);
310
311 gtk_main();
312
313 perf_gtk__deactivate_context(&pgctx);
314
315 return 0;
316}
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c
index a49bcf3c190b..700fb3cfa1c7 100644
--- a/tools/perf/ui/helpline.c
+++ b/tools/perf/ui/helpline.c
@@ -16,9 +16,16 @@ static void nop_helpline__push(const char *msg __maybe_unused)
16{ 16{
17} 17}
18 18
19static int nop_helpline__show(const char *fmt __maybe_unused,
20 va_list ap __maybe_unused)
21{
22 return 0;
23}
24
19static struct ui_helpline default_helpline_fns = { 25static struct ui_helpline default_helpline_fns = {
20 .pop = nop_helpline__pop, 26 .pop = nop_helpline__pop,
21 .push = nop_helpline__push, 27 .push = nop_helpline__push,
28 .show = nop_helpline__show,
22}; 29};
23 30
24struct ui_helpline *helpline_fns = &default_helpline_fns; 31struct ui_helpline *helpline_fns = &default_helpline_fns;
@@ -59,3 +66,8 @@ void ui_helpline__puts(const char *msg)
59 ui_helpline__pop(); 66 ui_helpline__pop();
60 ui_helpline__push(msg); 67 ui_helpline__push(msg);
61} 68}
69
70int ui_helpline__vshow(const char *fmt, va_list ap)
71{
72 return helpline_fns->show(fmt, ap);
73}
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h
index baa28a4d16b9..46181f4fc07e 100644
--- a/tools/perf/ui/helpline.h
+++ b/tools/perf/ui/helpline.h
@@ -9,6 +9,7 @@
9struct ui_helpline { 9struct ui_helpline {
10 void (*pop)(void); 10 void (*pop)(void);
11 void (*push)(const char *msg); 11 void (*push)(const char *msg);
12 int (*show)(const char *fmt, va_list ap);
12}; 13};
13 14
14extern struct ui_helpline *helpline_fns; 15extern struct ui_helpline *helpline_fns;
@@ -20,28 +21,9 @@ void ui_helpline__push(const char *msg);
20void ui_helpline__vpush(const char *fmt, va_list ap); 21void ui_helpline__vpush(const char *fmt, va_list ap);
21void ui_helpline__fpush(const char *fmt, ...); 22void ui_helpline__fpush(const char *fmt, ...);
22void ui_helpline__puts(const char *msg); 23void ui_helpline__puts(const char *msg);
24int ui_helpline__vshow(const char *fmt, va_list ap);
23 25
24extern char ui_helpline__current[512]; 26extern char ui_helpline__current[512];
25
26#ifdef NEWT_SUPPORT
27extern char ui_helpline__last_msg[]; 27extern char ui_helpline__last_msg[];
28int ui_helpline__show_help(const char *format, va_list ap);
29#else
30static inline int ui_helpline__show_help(const char *format __maybe_unused,
31 va_list ap __maybe_unused)
32{
33 return 0;
34}
35#endif /* NEWT_SUPPORT */
36
37#ifdef GTK2_SUPPORT
38int perf_gtk__show_helpline(const char *format, va_list ap);
39#else
40static inline int perf_gtk__show_helpline(const char *format __maybe_unused,
41 va_list ap __maybe_unused)
42{
43 return 0;
44}
45#endif /* GTK2_SUPPORT */
46 28
47#endif /* _PERF_UI_HELPLINE_H_ */ 29#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index aa84130024d5..4bf91b09d62d 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -3,151 +3,160 @@
3#include "../util/hist.h" 3#include "../util/hist.h"
4#include "../util/util.h" 4#include "../util/util.h"
5#include "../util/sort.h" 5#include "../util/sort.h"
6 6#include "../util/evsel.h"
7 7
8/* hist period print (hpp) functions */ 8/* hist period print (hpp) functions */
9static int hpp__header_overhead(struct perf_hpp *hpp)
10{
11 return scnprintf(hpp->buf, hpp->size, "Overhead");
12}
13
14static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
15{
16 return 8;
17}
18
19static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
20{
21 struct hists *hists = he->hists;
22 double percent = 100.0 * he->stat.period / hists->stats.total_period;
23
24 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
25}
26
27static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
28{
29 struct hists *hists = he->hists;
30 double percent = 100.0 * he->stat.period / hists->stats.total_period;
31 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
32
33 return scnprintf(hpp->buf, hpp->size, fmt, percent);
34}
35
36static int hpp__header_overhead_sys(struct perf_hpp *hpp)
37{
38 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
39
40 return scnprintf(hpp->buf, hpp->size, fmt, "sys");
41}
42
43static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
44{
45 return 7;
46}
47
48static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
49{
50 struct hists *hists = he->hists;
51 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
52
53 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
54}
55
56static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
57{
58 struct hists *hists = he->hists;
59 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
60 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
61
62 return scnprintf(hpp->buf, hpp->size, fmt, percent);
63}
64 9
65static int hpp__header_overhead_us(struct perf_hpp *hpp) 10typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
66{
67 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
68
69 return scnprintf(hpp->buf, hpp->size, fmt, "user");
70}
71
72static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
73{
74 return 7;
75}
76 11
77static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) 12static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
13 u64 (*get_field)(struct hist_entry *),
14 const char *fmt, hpp_snprint_fn print_fn,
15 bool fmt_percent)
78{ 16{
17 int ret;
79 struct hists *hists = he->hists; 18 struct hists *hists = he->hists;
80 double percent = 100.0 * he->stat.period_us / hists->stats.total_period; 19 struct perf_evsel *evsel = hists_to_evsel(hists);
81 20
82 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); 21 if (fmt_percent) {
83} 22 double percent = 0.0;
84 23
85static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) 24 if (hists->stats.total_period)
86{ 25 percent = 100.0 * get_field(he) /
87 struct hists *hists = he->hists; 26 hists->stats.total_period;
88 double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
89 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
90 27
91 return scnprintf(hpp->buf, hpp->size, fmt, percent); 28 ret = print_fn(hpp->buf, hpp->size, fmt, percent);
92} 29 } else
30 ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
93 31
94static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp) 32 if (perf_evsel__is_group_event(evsel)) {
95{ 33 int prev_idx, idx_delta;
96 return scnprintf(hpp->buf, hpp->size, "guest sys"); 34 struct hist_entry *pair;
97} 35 int nr_members = evsel->nr_members;
98 36
99static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused) 37 prev_idx = perf_evsel__group_idx(evsel);
100{
101 return 9;
102}
103 38
104static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, 39 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
105 struct hist_entry *he) 40 u64 period = get_field(pair);
106{ 41 u64 total = pair->hists->stats.total_period;
107 struct hists *hists = he->hists;
108 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
109 42
110 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); 43 if (!total)
111} 44 continue;
112 45
113static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, 46 evsel = hists_to_evsel(pair->hists);
114 struct hist_entry *he) 47 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
115{
116 struct hists *hists = he->hists;
117 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
118 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
119 48
120 return scnprintf(hpp->buf, hpp->size, fmt, percent); 49 while (idx_delta--) {
121} 50 /*
51 * zero-fill group members in the middle which
52 * have no sample
53 */
54 ret += print_fn(hpp->buf + ret, hpp->size - ret,
55 fmt, 0);
56 }
122 57
123static int hpp__header_overhead_guest_us(struct perf_hpp *hpp) 58 if (fmt_percent)
124{ 59 ret += print_fn(hpp->buf + ret, hpp->size - ret,
125 return scnprintf(hpp->buf, hpp->size, "guest usr"); 60 fmt, 100.0 * period / total);
126} 61 else
62 ret += print_fn(hpp->buf + ret, hpp->size - ret,
63 fmt, period);
127 64
128static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) 65 prev_idx = perf_evsel__group_idx(evsel);
129{ 66 }
130 return 9;
131}
132 67
133static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, 68 idx_delta = nr_members - prev_idx - 1;
134 struct hist_entry *he)
135{
136 struct hists *hists = he->hists;
137 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
138 69
139 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); 70 while (idx_delta--) {
71 /*
72 * zero-fill group members at last which have no sample
73 */
74 ret += print_fn(hpp->buf + ret, hpp->size - ret,
75 fmt, 0);
76 }
77 }
78 return ret;
140} 79}
141 80
142static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, 81#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
143 struct hist_entry *he) 82static int hpp__header_##_type(struct perf_hpp *hpp) \
144{ 83{ \
145 struct hists *hists = he->hists; 84 int len = _min_width; \
146 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; 85 \
147 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; 86 if (symbol_conf.event_group) { \
87 struct perf_evsel *evsel = hpp->ptr; \
88 \
89 len = max(len, evsel->nr_members * _unit_width); \
90 } \
91 return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \
92}
93
94#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
95static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \
96{ \
97 int len = _min_width; \
98 \
99 if (symbol_conf.event_group) { \
100 struct perf_evsel *evsel = hpp->ptr; \
101 \
102 len = max(len, evsel->nr_members * _unit_width); \
103 } \
104 return len; \
105}
106
107#define __HPP_COLOR_PERCENT_FN(_type, _field) \
108static u64 he_get_##_field(struct hist_entry *he) \
109{ \
110 return he->stat._field; \
111} \
112 \
113static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
114{ \
115 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
116 (hpp_snprint_fn)percent_color_snprintf, true); \
117}
118
119#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
120static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
121{ \
122 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
123 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
124 scnprintf, true); \
125}
126
127#define __HPP_ENTRY_RAW_FN(_type, _field) \
128static u64 he_get_raw_##_field(struct hist_entry *he) \
129{ \
130 return he->stat._field; \
131} \
132 \
133static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
134{ \
135 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
136 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
137}
138
139#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
140__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
141__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
142__HPP_COLOR_PERCENT_FN(_type, _field) \
143__HPP_ENTRY_PERCENT_FN(_type, _field)
144
145#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
146__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
147__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
148__HPP_ENTRY_RAW_FN(_type, _field)
149
150
151HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
152HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
153HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
154HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
155HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
156
157HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
158HPP_RAW_FNS(period, "Period", period, 12, 12)
148 159
149 return scnprintf(hpp->buf, hpp->size, fmt, percent);
150}
151 160
152static int hpp__header_baseline(struct perf_hpp *hpp) 161static int hpp__header_baseline(struct perf_hpp *hpp)
153{ 162{
@@ -179,7 +188,7 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
179{ 188{
180 double percent = baseline_percent(he); 189 double percent = baseline_percent(he);
181 190
182 if (hist_entry__has_pairs(he)) 191 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
183 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); 192 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
184 else 193 else
185 return scnprintf(hpp->buf, hpp->size, " "); 194 return scnprintf(hpp->buf, hpp->size, " ");
@@ -196,44 +205,6 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
196 return scnprintf(hpp->buf, hpp->size, " "); 205 return scnprintf(hpp->buf, hpp->size, " ");
197} 206}
198 207
199static int hpp__header_samples(struct perf_hpp *hpp)
200{
201 const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
202
203 return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
204}
205
206static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
207{
208 return 11;
209}
210
211static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
212{
213 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
214
215 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
216}
217
218static int hpp__header_period(struct perf_hpp *hpp)
219{
220 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
221
222 return scnprintf(hpp->buf, hpp->size, fmt, "Period");
223}
224
225static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
226{
227 return 12;
228}
229
230static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
231{
232 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
233
234 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
235}
236
237static int hpp__header_period_baseline(struct perf_hpp *hpp) 208static int hpp__header_period_baseline(struct perf_hpp *hpp)
238{ 209{
239 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; 210 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
@@ -254,6 +225,7 @@ static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *h
254 225
255 return scnprintf(hpp->buf, hpp->size, fmt, period); 226 return scnprintf(hpp->buf, hpp->size, fmt, period);
256} 227}
228
257static int hpp__header_delta(struct perf_hpp *hpp) 229static int hpp__header_delta(struct perf_hpp *hpp)
258{ 230{
259 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 231 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
@@ -268,14 +240,18 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
268 240
269static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) 241static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
270{ 242{
243 struct hist_entry *pair = hist_entry__next_pair(he);
271 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; 244 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
272 char buf[32] = " "; 245 char buf[32] = " ";
273 double diff; 246 double diff = 0.0;
274 247
275 if (he->diff.computed) 248 if (pair) {
276 diff = he->diff.period_ratio_delta; 249 if (he->diff.computed)
277 else 250 diff = he->diff.period_ratio_delta;
278 diff = perf_diff__compute_delta(he); 251 else
252 diff = perf_diff__compute_delta(he, pair);
253 } else
254 diff = perf_diff__period_percent(he, he->stat.period);
279 255
280 if (fabs(diff) >= 0.01) 256 if (fabs(diff) >= 0.01)
281 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); 257 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
@@ -297,14 +273,17 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
297 273
298static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) 274static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
299{ 275{
276 struct hist_entry *pair = hist_entry__next_pair(he);
300 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; 277 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
301 char buf[32] = " "; 278 char buf[32] = " ";
302 double ratio; 279 double ratio = 0.0;
303 280
304 if (he->diff.computed) 281 if (pair) {
305 ratio = he->diff.period_ratio; 282 if (he->diff.computed)
306 else 283 ratio = he->diff.period_ratio;
307 ratio = perf_diff__compute_ratio(he); 284 else
285 ratio = perf_diff__compute_ratio(he, pair);
286 }
308 287
309 if (ratio > 0.0) 288 if (ratio > 0.0)
310 scnprintf(buf, sizeof(buf), "%+14.6F", ratio); 289 scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
@@ -326,14 +305,17 @@ static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
326 305
327static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) 306static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
328{ 307{
308 struct hist_entry *pair = hist_entry__next_pair(he);
329 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; 309 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
330 char buf[32] = " "; 310 char buf[32] = " ";
331 s64 wdiff; 311 s64 wdiff = 0;
332 312
333 if (he->diff.computed) 313 if (pair) {
334 wdiff = he->diff.wdiff; 314 if (he->diff.computed)
335 else 315 wdiff = he->diff.wdiff;
336 wdiff = perf_diff__compute_wdiff(he); 316 else
317 wdiff = perf_diff__compute_wdiff(he, pair);
318 }
337 319
338 if (wdiff != 0) 320 if (wdiff != 0)
339 scnprintf(buf, sizeof(buf), "%14ld", wdiff); 321 scnprintf(buf, sizeof(buf), "%14ld", wdiff);
@@ -341,30 +323,6 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
341 return scnprintf(hpp->buf, hpp->size, fmt, buf); 323 return scnprintf(hpp->buf, hpp->size, fmt, buf);
342} 324}
343 325
344static int hpp__header_displ(struct perf_hpp *hpp)
345{
346 return scnprintf(hpp->buf, hpp->size, "Displ.");
347}
348
349static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
350{
351 return 6;
352}
353
354static int hpp__entry_displ(struct perf_hpp *hpp,
355 struct hist_entry *he)
356{
357 struct hist_entry *pair = hist_entry__next_pair(he);
358 long displacement = pair ? pair->position - he->position : 0;
359 const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
360 char buf[32] = " ";
361
362 if (displacement)
363 scnprintf(buf, sizeof(buf), "%+4ld", displacement);
364
365 return scnprintf(hpp->buf, hpp->size, fmt, buf);
366}
367
368static int hpp__header_formula(struct perf_hpp *hpp) 326static int hpp__header_formula(struct perf_hpp *hpp)
369{ 327{
370 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; 328 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
@@ -379,67 +337,91 @@ static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
379 337
380static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) 338static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
381{ 339{
340 struct hist_entry *pair = hist_entry__next_pair(he);
382 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; 341 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
383 char buf[96] = " "; 342 char buf[96] = " ";
384 343
385 perf_diff__formula(buf, sizeof(buf), he); 344 if (pair)
345 perf_diff__formula(he, pair, buf, sizeof(buf));
346
386 return scnprintf(hpp->buf, hpp->size, fmt, buf); 347 return scnprintf(hpp->buf, hpp->size, fmt, buf);
387} 348}
388 349
389#define HPP__COLOR_PRINT_FNS(_name) \ 350#define HPP__COLOR_PRINT_FNS(_name) \
390 .header = hpp__header_ ## _name, \ 351 { \
391 .width = hpp__width_ ## _name, \ 352 .header = hpp__header_ ## _name, \
392 .color = hpp__color_ ## _name, \ 353 .width = hpp__width_ ## _name, \
393 .entry = hpp__entry_ ## _name 354 .color = hpp__color_ ## _name, \
355 .entry = hpp__entry_ ## _name \
356 }
394 357
395#define HPP__PRINT_FNS(_name) \ 358#define HPP__PRINT_FNS(_name) \
396 .header = hpp__header_ ## _name, \ 359 { \
397 .width = hpp__width_ ## _name, \ 360 .header = hpp__header_ ## _name, \
398 .entry = hpp__entry_ ## _name 361 .width = hpp__width_ ## _name, \
362 .entry = hpp__entry_ ## _name \
363 }
399 364
400struct perf_hpp_fmt perf_hpp__format[] = { 365struct perf_hpp_fmt perf_hpp__format[] = {
401 { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, 366 HPP__COLOR_PRINT_FNS(baseline),
402 { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, 367 HPP__COLOR_PRINT_FNS(overhead),
403 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, 368 HPP__COLOR_PRINT_FNS(overhead_sys),
404 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, 369 HPP__COLOR_PRINT_FNS(overhead_us),
405 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, 370 HPP__COLOR_PRINT_FNS(overhead_guest_sys),
406 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, 371 HPP__COLOR_PRINT_FNS(overhead_guest_us),
407 { .cond = false, HPP__PRINT_FNS(samples) }, 372 HPP__PRINT_FNS(samples),
408 { .cond = false, HPP__PRINT_FNS(period) }, 373 HPP__PRINT_FNS(period),
409 { .cond = false, HPP__PRINT_FNS(period_baseline) }, 374 HPP__PRINT_FNS(period_baseline),
410 { .cond = false, HPP__PRINT_FNS(delta) }, 375 HPP__PRINT_FNS(delta),
411 { .cond = false, HPP__PRINT_FNS(ratio) }, 376 HPP__PRINT_FNS(ratio),
412 { .cond = false, HPP__PRINT_FNS(wdiff) }, 377 HPP__PRINT_FNS(wdiff),
413 { .cond = false, HPP__PRINT_FNS(displ) }, 378 HPP__PRINT_FNS(formula)
414 { .cond = false, HPP__PRINT_FNS(formula) }
415}; 379};
416 380
381LIST_HEAD(perf_hpp__list);
382
383
417#undef HPP__COLOR_PRINT_FNS 384#undef HPP__COLOR_PRINT_FNS
418#undef HPP__PRINT_FNS 385#undef HPP__PRINT_FNS
419 386
387#undef HPP_PERCENT_FNS
388#undef HPP_RAW_FNS
389
390#undef __HPP_HEADER_FN
391#undef __HPP_WIDTH_FN
392#undef __HPP_COLOR_PERCENT_FN
393#undef __HPP_ENTRY_PERCENT_FN
394#undef __HPP_ENTRY_RAW_FN
395
396
420void perf_hpp__init(void) 397void perf_hpp__init(void)
421{ 398{
422 if (symbol_conf.show_cpu_utilization) { 399 if (symbol_conf.show_cpu_utilization) {
423 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; 400 perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
424 perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; 401 perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
425 402
426 if (perf_guest) { 403 if (perf_guest) {
427 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; 404 perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS);
428 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; 405 perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US);
429 } 406 }
430 } 407 }
431 408
432 if (symbol_conf.show_nr_samples) 409 if (symbol_conf.show_nr_samples)
433 perf_hpp__format[PERF_HPP__SAMPLES].cond = true; 410 perf_hpp__column_enable(PERF_HPP__SAMPLES);
434 411
435 if (symbol_conf.show_total_period) 412 if (symbol_conf.show_total_period)
436 perf_hpp__format[PERF_HPP__PERIOD].cond = true; 413 perf_hpp__column_enable(PERF_HPP__PERIOD);
414}
415
416void perf_hpp__column_register(struct perf_hpp_fmt *format)
417{
418 list_add_tail(&format->list, &perf_hpp__list);
437} 419}
438 420
439void perf_hpp__column_enable(unsigned col, bool enable) 421void perf_hpp__column_enable(unsigned col)
440{ 422{
441 BUG_ON(col >= PERF_HPP__MAX_INDEX); 423 BUG_ON(col >= PERF_HPP__MAX_INDEX);
442 perf_hpp__format[col].cond = enable; 424 perf_hpp__column_register(&perf_hpp__format[col]);
443} 425}
444 426
445static inline void advance_hpp(struct perf_hpp *hpp, int inc) 427static inline void advance_hpp(struct perf_hpp *hpp, int inc)
@@ -452,27 +434,29 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
452 bool color) 434 bool color)
453{ 435{
454 const char *sep = symbol_conf.field_sep; 436 const char *sep = symbol_conf.field_sep;
437 struct perf_hpp_fmt *fmt;
455 char *start = hpp->buf; 438 char *start = hpp->buf;
456 int i, ret; 439 int ret;
457 bool first = true; 440 bool first = true;
458 441
459 if (symbol_conf.exclude_other && !he->parent) 442 if (symbol_conf.exclude_other && !he->parent)
460 return 0; 443 return 0;
461 444
462 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 445 perf_hpp__for_each_format(fmt) {
463 if (!perf_hpp__format[i].cond) 446 /*
464 continue; 447 * If there's no field_sep, we still need
465 448 * to display initial ' '.
449 */
466 if (!sep || !first) { 450 if (!sep || !first) {
467 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 451 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
468 advance_hpp(hpp, ret); 452 advance_hpp(hpp, ret);
453 } else
469 first = false; 454 first = false;
470 }
471 455
472 if (color && perf_hpp__format[i].color) 456 if (color && fmt->color)
473 ret = perf_hpp__format[i].color(hpp, he); 457 ret = fmt->color(hpp, he);
474 else 458 else
475 ret = perf_hpp__format[i].entry(hpp, he); 459 ret = fmt->entry(hpp, he);
476 460
477 advance_hpp(hpp, ret); 461 advance_hpp(hpp, ret);
478 } 462 }
@@ -504,16 +488,18 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
504 */ 488 */
505unsigned int hists__sort_list_width(struct hists *hists) 489unsigned int hists__sort_list_width(struct hists *hists)
506{ 490{
491 struct perf_hpp_fmt *fmt;
507 struct sort_entry *se; 492 struct sort_entry *se;
508 int i, ret = 0; 493 int i = 0, ret = 0;
494 struct perf_hpp dummy_hpp = {
495 .ptr = hists_to_evsel(hists),
496 };
509 497
510 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 498 perf_hpp__for_each_format(fmt) {
511 if (!perf_hpp__format[i].cond)
512 continue;
513 if (i) 499 if (i)
514 ret += 2; 500 ret += 2;
515 501
516 ret += perf_hpp__format[i].width(NULL); 502 ret += fmt->width(&dummy_hpp);
517 } 503 }
518 504
519 list_for_each_entry(se, &hist_entry__sort_list, list) 505 list_for_each_entry(se, &hist_entry__sort_list, list)
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h
index 809eca5707fa..65092d576b4e 100644
--- a/tools/perf/ui/keysyms.h
+++ b/tools/perf/ui/keysyms.h
@@ -23,5 +23,6 @@
23#define K_TIMER -1 23#define K_TIMER -1
24#define K_ERROR -2 24#define K_ERROR -2
25#define K_RESIZE -3 25#define K_RESIZE -3
26#define K_SWITCH_INPUT_DATA -4
26 27
27#endif /* _PERF_KEYSYMS_H_ */ 28#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index ebb4cc107876..ae6a789cb0f6 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -8,7 +8,7 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
8 8
9void setup_browser(bool fallback_to_pager) 9void setup_browser(bool fallback_to_pager)
10{ 10{
11 if (!isatty(1) || dump_trace) 11 if (use_browser < 2 && (!isatty(1) || dump_trace))
12 use_browser = 0; 12 use_browser = 0;
13 13
14 /* default to TUI */ 14 /* default to TUI */
@@ -30,6 +30,7 @@ void setup_browser(bool fallback_to_pager)
30 if (fallback_to_pager) 30 if (fallback_to_pager)
31 setup_pager(); 31 setup_pager();
32 32
33 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
33 perf_hpp__init(); 34 perf_hpp__init();
34 break; 35 break;
35 } 36 }
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index f0ee204f99bb..ae7a75432249 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -3,6 +3,7 @@
3#include "../../util/util.h" 3#include "../../util/util.h"
4#include "../../util/hist.h" 4#include "../../util/hist.h"
5#include "../../util/sort.h" 5#include "../../util/sort.h"
6#include "../../util/evsel.h"
6 7
7 8
8static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 9static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -333,19 +334,21 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
333} 334}
334 335
335size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 336size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
336 int max_cols, FILE *fp) 337 int max_cols, float min_pcnt, FILE *fp)
337{ 338{
339 struct perf_hpp_fmt *fmt;
338 struct sort_entry *se; 340 struct sort_entry *se;
339 struct rb_node *nd; 341 struct rb_node *nd;
340 size_t ret = 0; 342 size_t ret = 0;
341 unsigned int width; 343 unsigned int width;
342 const char *sep = symbol_conf.field_sep; 344 const char *sep = symbol_conf.field_sep;
343 const char *col_width = symbol_conf.col_width_list_str; 345 const char *col_width = symbol_conf.col_width_list_str;
344 int idx, nr_rows = 0; 346 int nr_rows = 0;
345 char bf[96]; 347 char bf[96];
346 struct perf_hpp dummy_hpp = { 348 struct perf_hpp dummy_hpp = {
347 .buf = bf, 349 .buf = bf,
348 .size = sizeof(bf), 350 .size = sizeof(bf),
351 .ptr = hists_to_evsel(hists),
349 }; 352 };
350 bool first = true; 353 bool first = true;
351 354
@@ -355,16 +358,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
355 goto print_entries; 358 goto print_entries;
356 359
357 fprintf(fp, "# "); 360 fprintf(fp, "# ");
358 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
359 if (!perf_hpp__format[idx].cond)
360 continue;
361 361
362 perf_hpp__for_each_format(fmt) {
362 if (!first) 363 if (!first)
363 fprintf(fp, "%s", sep ?: " "); 364 fprintf(fp, "%s", sep ?: " ");
364 else 365 else
365 first = false; 366 first = false;
366 367
367 perf_hpp__format[idx].header(&dummy_hpp); 368 fmt->header(&dummy_hpp);
368 fprintf(fp, "%s", bf); 369 fprintf(fp, "%s", bf);
369 } 370 }
370 371
@@ -400,18 +401,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
400 first = true; 401 first = true;
401 402
402 fprintf(fp, "# "); 403 fprintf(fp, "# ");
403 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
404 unsigned int i;
405 404
406 if (!perf_hpp__format[idx].cond) 405 perf_hpp__for_each_format(fmt) {
407 continue; 406 unsigned int i;
408 407
409 if (!first) 408 if (!first)
410 fprintf(fp, "%s", sep ?: " "); 409 fprintf(fp, "%s", sep ?: " ");
411 else 410 else
412 first = false; 411 first = false;
413 412
414 width = perf_hpp__format[idx].width(&dummy_hpp); 413 width = fmt->width(&dummy_hpp);
415 for (i = 0; i < width; i++) 414 for (i = 0; i < width; i++)
416 fprintf(fp, "."); 415 fprintf(fp, ".");
417 } 416 }
@@ -441,10 +440,15 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
441print_entries: 440print_entries:
442 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 441 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
443 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 442 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
443 float percent = h->stat.period * 100.0 /
444 hists->stats.total_period;
444 445
445 if (h->filtered) 446 if (h->filtered)
446 continue; 447 continue;
447 448
449 if (percent < min_pcnt)
450 continue;
451
448 ret += hist_entry__fprintf(h, max_cols, hists, fp); 452 ret += hist_entry__fprintf(h, max_cols, hists, fp);
449 453
450 if (max_rows && ++nr_rows >= max_rows) 454 if (max_rows && ++nr_rows >= max_rows)
@@ -462,7 +466,7 @@ out:
462 return ret; 466 return ret;
463} 467}
464 468
465size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) 469size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
466{ 470{
467 int i; 471 int i;
468 size_t ret = 0; 472 size_t ret = 0;
@@ -470,7 +474,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
470 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 474 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
471 const char *name; 475 const char *name;
472 476
473 if (hists->stats.nr_events[i] == 0) 477 if (stats->nr_events[i] == 0)
474 continue; 478 continue;
475 479
476 name = perf_event__name(i); 480 name = perf_event__name(i);
@@ -478,7 +482,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
478 continue; 482 continue;
479 483
480 ret += fprintf(fp, "%16s events: %10d\n", name, 484 ret += fprintf(fp, "%16s events: %10d\n", name,
481 hists->stats.nr_events[i]); 485 stats->nr_events[i]);
482 } 486 }
483 487
484 return ret; 488 return ret;
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c
index 2884d2f41e33..1c8b9afd5d6e 100644
--- a/tools/perf/ui/tui/helpline.c
+++ b/tools/perf/ui/tui/helpline.c
@@ -8,6 +8,8 @@
8#include "../ui.h" 8#include "../ui.h"
9#include "../libslang.h" 9#include "../libslang.h"
10 10
11char ui_helpline__last_msg[1024];
12
11static void tui_helpline__pop(void) 13static void tui_helpline__pop(void)
12{ 14{
13} 15}
@@ -23,20 +25,7 @@ static void tui_helpline__push(const char *msg)
23 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; 25 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
24} 26}
25 27
26struct ui_helpline tui_helpline_fns = { 28static int tui_helpline__show(const char *format, va_list ap)
27 .pop = tui_helpline__pop,
28 .push = tui_helpline__push,
29};
30
31void ui_helpline__init(void)
32{
33 helpline_fns = &tui_helpline_fns;
34 ui_helpline__puts(" ");
35}
36
37char ui_helpline__last_msg[1024];
38
39int ui_helpline__show_help(const char *format, va_list ap)
40{ 29{
41 int ret; 30 int ret;
42 static int backlog; 31 static int backlog;
@@ -55,3 +44,15 @@ int ui_helpline__show_help(const char *format, va_list ap)
55 44
56 return ret; 45 return ret;
57} 46}
47
48struct ui_helpline tui_helpline_fns = {
49 .pop = tui_helpline__pop,
50 .push = tui_helpline__push,
51 .show = tui_helpline__show,
52};
53
54void ui_helpline__init(void)
55{
56 helpline_fns = &tui_helpline_fns;
57 ui_helpline__puts(" ");
58}
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index 81efa192e86c..b9401482d110 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -1,4 +1,3 @@
1#include <newt.h>
2#include <signal.h> 1#include <signal.h>
3#include <stdbool.h> 2#include <stdbool.h>
4 3
@@ -88,13 +87,6 @@ int ui__getch(int delay_secs)
88 return SLkp_getkey(); 87 return SLkp_getkey();
89} 88}
90 89
91static void newt_suspend(void *d __maybe_unused)
92{
93 newtSuspend();
94 raise(SIGTSTP);
95 newtResume();
96}
97
98static void ui__signal(int sig) 90static void ui__signal(int sig)
99{ 91{
100 ui__exit(false); 92 ui__exit(false);
@@ -106,7 +98,17 @@ int ui__init(void)
106{ 98{
107 int err; 99 int err;
108 100
109 newtInit(); 101 SLutf8_enable(-1);
102 SLtt_get_terminfo();
103 SLtt_get_screen_size();
104
105 err = SLsmg_init_smg();
106 if (err < 0)
107 goto out;
108 err = SLang_init_tty(0, 0, 0);
109 if (err < 0)
110 goto out;
111
110 err = SLkp_init(); 112 err = SLkp_init();
111 if (err < 0) { 113 if (err < 0) {
112 pr_err("TUI initialization failed.\n"); 114 pr_err("TUI initialization failed.\n");
@@ -115,7 +117,6 @@ int ui__init(void)
115 117
116 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); 118 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
117 119
118 newtSetSuspendCallback(newt_suspend, NULL);
119 ui_helpline__init(); 120 ui_helpline__init();
120 ui_browser__init(); 121 ui_browser__init();
121 ui_progress__init(); 122 ui_progress__init();
diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h
index d86359c99907..70cb0d4eb8aa 100644
--- a/tools/perf/ui/ui.h
+++ b/tools/perf/ui/ui.h
@@ -12,7 +12,7 @@ extern int use_browser;
12void setup_browser(bool fallback_to_pager); 12void setup_browser(bool fallback_to_pager);
13void exit_browser(bool wait_for_ok); 13void exit_browser(bool wait_for_ok);
14 14
15#ifdef NEWT_SUPPORT 15#ifdef SLANG_SUPPORT
16int ui__init(void); 16int ui__init(void);
17void ui__exit(bool wait_for_ok); 17void ui__exit(bool wait_for_ok);
18#else 18#else
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
index 4f989774c8c6..e3e0a963d03a 100644
--- a/tools/perf/ui/util.c
+++ b/tools/perf/ui/util.c
@@ -52,7 +52,6 @@ int ui__warning(const char *format, ...)
52 return ret; 52 return ret;
53} 53}
54 54
55
56/** 55/**
57 * perf_error__register - Register error logging functions 56 * perf_error__register - Register error logging functions
58 * @eops: The pointer to error logging function struct 57 * @eops: The pointer to error logging function struct
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 6aa34e5afdcf..055fef34b6f6 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -26,13 +26,13 @@ VN=$(expr "$VN" : v*'\(.*\)')
26 26
27if test -r $GVF 27if test -r $GVF
28then 28then
29 VC=$(sed -e 's/^PERF_VERSION = //' <$GVF) 29 VC=$(sed -e 's/^#define PERF_VERSION "\(.*\)"/\1/' <$GVF)
30else 30else
31 VC=unset 31 VC=unset
32fi 32fi
33test "$VN" = "$VC" || { 33test "$VN" = "$VC" || {
34 echo >&2 "PERF_VERSION = $VN" 34 echo >&2 "PERF_VERSION = $VN"
35 echo "PERF_VERSION = $VN" >$GVF 35 echo "#define PERF_VERSION \"$VN\"" >$GVF
36} 36}
37 37
38 38
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 07aaeea60000..d102716c43a1 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -14,6 +14,7 @@
14#include "symbol.h" 14#include "symbol.h"
15#include "debug.h" 15#include "debug.h"
16#include "annotate.h" 16#include "annotate.h"
17#include "evsel.h"
17#include <pthread.h> 18#include <pthread.h>
18#include <linux/bitops.h> 19#include <linux/bitops.h>
19 20
@@ -602,8 +603,42 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa
602 return NULL; 603 return NULL;
603} 604}
604 605
606double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
607 s64 end, const char **path)
608{
609 struct source_line *src_line = notes->src->lines;
610 double percent = 0.0;
611
612 if (src_line) {
613 size_t sizeof_src_line = sizeof(*src_line) +
614 sizeof(src_line->p) * (src_line->nr_pcnt - 1);
615
616 while (offset < end) {
617 src_line = (void *)notes->src->lines +
618 (sizeof_src_line * offset);
619
620 if (*path == NULL)
621 *path = src_line->path;
622
623 percent += src_line->p[evidx].percent;
624 offset++;
625 }
626 } else {
627 struct sym_hist *h = annotation__histogram(notes, evidx);
628 unsigned int hits = 0;
629
630 while (offset < end)
631 hits += h->addr[offset++];
632
633 if (h->sum)
634 percent = 100.0 * hits / h->sum;
635 }
636
637 return percent;
638}
639
605static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, 640static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
606 int evidx, u64 len, int min_pcnt, int printed, 641 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
607 int max_lines, struct disasm_line *queue) 642 int max_lines, struct disasm_line *queue)
608{ 643{
609 static const char *prev_line; 644 static const char *prev_line;
@@ -611,34 +646,37 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
611 646
612 if (dl->offset != -1) { 647 if (dl->offset != -1) {
613 const char *path = NULL; 648 const char *path = NULL;
614 unsigned int hits = 0; 649 double percent, max_percent = 0.0;
615 double percent = 0.0; 650 double *ppercents = &percent;
651 int i, nr_percent = 1;
616 const char *color; 652 const char *color;
617 struct annotation *notes = symbol__annotation(sym); 653 struct annotation *notes = symbol__annotation(sym);
618 struct source_line *src_line = notes->src->lines;
619 struct sym_hist *h = annotation__histogram(notes, evidx);
620 s64 offset = dl->offset; 654 s64 offset = dl->offset;
621 const u64 addr = start + offset; 655 const u64 addr = start + offset;
622 struct disasm_line *next; 656 struct disasm_line *next;
623 657
624 next = disasm__get_next_ip_line(&notes->src->source, dl); 658 next = disasm__get_next_ip_line(&notes->src->source, dl);
625 659
626 while (offset < (s64)len && 660 if (perf_evsel__is_group_event(evsel)) {
627 (next == NULL || offset < next->offset)) { 661 nr_percent = evsel->nr_members;
628 if (src_line) { 662 ppercents = calloc(nr_percent, sizeof(double));
629 if (path == NULL) 663 if (ppercents == NULL)
630 path = src_line[offset].path; 664 return -1;
631 percent += src_line[offset].percent;
632 } else
633 hits += h->addr[offset];
634
635 ++offset;
636 } 665 }
637 666
638 if (src_line == NULL && h->sum) 667 for (i = 0; i < nr_percent; i++) {
639 percent = 100.0 * hits / h->sum; 668 percent = disasm__calc_percent(notes,
669 notes->src->lines ? i : evsel->idx + i,
670 offset,
671 next ? next->offset : (s64) len,
672 &path);
673
674 ppercents[i] = percent;
675 if (percent > max_percent)
676 max_percent = percent;
677 }
640 678
641 if (percent < min_pcnt) 679 if (max_percent < min_pcnt)
642 return -1; 680 return -1;
643 681
644 if (max_lines && printed >= max_lines) 682 if (max_lines && printed >= max_lines)
@@ -648,12 +686,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
648 list_for_each_entry_from(queue, &notes->src->source, node) { 686 list_for_each_entry_from(queue, &notes->src->source, node) {
649 if (queue == dl) 687 if (queue == dl)
650 break; 688 break;
651 disasm_line__print(queue, sym, start, evidx, len, 689 disasm_line__print(queue, sym, start, evsel, len,
652 0, 0, 1, NULL); 690 0, 0, 1, NULL);
653 } 691 }
654 } 692 }
655 693
656 color = get_percent_color(percent); 694 color = get_percent_color(max_percent);
657 695
658 /* 696 /*
659 * Also color the filename and line if needed, with 697 * Also color the filename and line if needed, with
@@ -669,25 +707,59 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
669 } 707 }
670 } 708 }
671 709
672 color_fprintf(stdout, color, " %7.2f", percent); 710 for (i = 0; i < nr_percent; i++) {
711 percent = ppercents[i];
712 color = get_percent_color(percent);
713 color_fprintf(stdout, color, " %7.2f", percent);
714 }
715
673 printf(" : "); 716 printf(" : ");
674 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); 717 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr);
675 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); 718 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
719
720 if (ppercents != &percent)
721 free(ppercents);
722
676 } else if (max_lines && printed >= max_lines) 723 } else if (max_lines && printed >= max_lines)
677 return 1; 724 return 1;
678 else { 725 else {
726 int width = 8;
727
679 if (queue) 728 if (queue)
680 return -1; 729 return -1;
681 730
731 if (perf_evsel__is_group_event(evsel))
732 width *= evsel->nr_members;
733
682 if (!*dl->line) 734 if (!*dl->line)
683 printf(" :\n"); 735 printf(" %*s:\n", width, " ");
684 else 736 else
685 printf(" : %s\n", dl->line); 737 printf(" %*s: %s\n", width, " ", dl->line);
686 } 738 }
687 739
688 return 0; 740 return 0;
689} 741}
690 742
743/*
744 * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
745 * which looks like following
746 *
747 * 0000000000415500 <_init>:
748 * 415500: sub $0x8,%rsp
749 * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8>
750 * 41550b: test %rax,%rax
751 * 41550e: je 415515 <_init+0x15>
752 * 415510: callq 416e70 <__gmon_start__@plt>
753 * 415515: add $0x8,%rsp
754 * 415519: retq
755 *
756 * it will be parsed and saved into struct disasm_line as
757 * <offset> <name> <ops.raw>
758 *
759 * The offset will be a relative offset from the start of the symbol and -1
760 * means that it's not a disassembly line so should be treated differently.
761 * The ops.raw part will be parsed further according to type of the instruction.
762 */
691static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, 763static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
692 FILE *file, size_t privsize) 764 FILE *file, size_t privsize)
693{ 765{
@@ -809,7 +881,7 @@ fallback:
809 pr_err("Can't annotate %s:\n\n" 881 pr_err("Can't annotate %s:\n\n"
810 "No vmlinux file%s\nwas found in the path.\n\n" 882 "No vmlinux file%s\nwas found in the path.\n\n"
811 "Please use:\n\n" 883 "Please use:\n\n"
812 " perf buildid-cache -av vmlinux\n\n" 884 " perf buildid-cache -vu vmlinux\n\n"
813 "or:\n\n" 885 "or:\n\n"
814 " --vmlinux vmlinux\n", 886 " --vmlinux vmlinux\n",
815 sym->name, build_id_msg ?: ""); 887 sym->name, build_id_msg ?: "");
@@ -858,7 +930,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
858 struct source_line *iter; 930 struct source_line *iter;
859 struct rb_node **p = &root->rb_node; 931 struct rb_node **p = &root->rb_node;
860 struct rb_node *parent = NULL; 932 struct rb_node *parent = NULL;
861 int ret; 933 int i, ret;
862 934
863 while (*p != NULL) { 935 while (*p != NULL) {
864 parent = *p; 936 parent = *p;
@@ -866,7 +938,8 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
866 938
867 ret = strcmp(iter->path, src_line->path); 939 ret = strcmp(iter->path, src_line->path);
868 if (ret == 0) { 940 if (ret == 0) {
869 iter->percent_sum += src_line->percent; 941 for (i = 0; i < src_line->nr_pcnt; i++)
942 iter->p[i].percent_sum += src_line->p[i].percent;
870 return; 943 return;
871 } 944 }
872 945
@@ -876,12 +949,26 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
876 p = &(*p)->rb_right; 949 p = &(*p)->rb_right;
877 } 950 }
878 951
879 src_line->percent_sum = src_line->percent; 952 for (i = 0; i < src_line->nr_pcnt; i++)
953 src_line->p[i].percent_sum = src_line->p[i].percent;
880 954
881 rb_link_node(&src_line->node, parent, p); 955 rb_link_node(&src_line->node, parent, p);
882 rb_insert_color(&src_line->node, root); 956 rb_insert_color(&src_line->node, root);
883} 957}
884 958
959static int cmp_source_line(struct source_line *a, struct source_line *b)
960{
961 int i;
962
963 for (i = 0; i < a->nr_pcnt; i++) {
964 if (a->p[i].percent_sum == b->p[i].percent_sum)
965 continue;
966 return a->p[i].percent_sum > b->p[i].percent_sum;
967 }
968
969 return 0;
970}
971
885static void __resort_source_line(struct rb_root *root, struct source_line *src_line) 972static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
886{ 973{
887 struct source_line *iter; 974 struct source_line *iter;
@@ -892,7 +979,7 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l
892 parent = *p; 979 parent = *p;
893 iter = rb_entry(parent, struct source_line, node); 980 iter = rb_entry(parent, struct source_line, node);
894 981
895 if (src_line->percent_sum > iter->percent_sum) 982 if (cmp_source_line(src_line, iter))
896 p = &(*p)->rb_left; 983 p = &(*p)->rb_left;
897 else 984 else
898 p = &(*p)->rb_right; 985 p = &(*p)->rb_right;
@@ -924,32 +1011,52 @@ static void symbol__free_source_line(struct symbol *sym, int len)
924{ 1011{
925 struct annotation *notes = symbol__annotation(sym); 1012 struct annotation *notes = symbol__annotation(sym);
926 struct source_line *src_line = notes->src->lines; 1013 struct source_line *src_line = notes->src->lines;
1014 size_t sizeof_src_line;
927 int i; 1015 int i;
928 1016
929 for (i = 0; i < len; i++) 1017 sizeof_src_line = sizeof(*src_line) +
930 free(src_line[i].path); 1018 (sizeof(src_line->p) * (src_line->nr_pcnt - 1));
1019
1020 for (i = 0; i < len; i++) {
1021 free(src_line->path);
1022 src_line = (void *)src_line + sizeof_src_line;
1023 }
931 1024
932 free(src_line); 1025 free(notes->src->lines);
933 notes->src->lines = NULL; 1026 notes->src->lines = NULL;
934} 1027}
935 1028
936/* Get the filename:line for the colored entries */ 1029/* Get the filename:line for the colored entries */
937static int symbol__get_source_line(struct symbol *sym, struct map *map, 1030static int symbol__get_source_line(struct symbol *sym, struct map *map,
938 int evidx, struct rb_root *root, int len, 1031 struct perf_evsel *evsel,
1032 struct rb_root *root, int len,
939 const char *filename) 1033 const char *filename)
940{ 1034{
941 u64 start; 1035 u64 start;
942 int i; 1036 int i, k;
1037 int evidx = evsel->idx;
943 char cmd[PATH_MAX * 2]; 1038 char cmd[PATH_MAX * 2];
944 struct source_line *src_line; 1039 struct source_line *src_line;
945 struct annotation *notes = symbol__annotation(sym); 1040 struct annotation *notes = symbol__annotation(sym);
946 struct sym_hist *h = annotation__histogram(notes, evidx); 1041 struct sym_hist *h = annotation__histogram(notes, evidx);
947 struct rb_root tmp_root = RB_ROOT; 1042 struct rb_root tmp_root = RB_ROOT;
1043 int nr_pcnt = 1;
1044 u64 h_sum = h->sum;
1045 size_t sizeof_src_line = sizeof(struct source_line);
1046
1047 if (perf_evsel__is_group_event(evsel)) {
1048 for (i = 1; i < evsel->nr_members; i++) {
1049 h = annotation__histogram(notes, evidx + i);
1050 h_sum += h->sum;
1051 }
1052 nr_pcnt = evsel->nr_members;
1053 sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p);
1054 }
948 1055
949 if (!h->sum) 1056 if (!h_sum)
950 return 0; 1057 return 0;
951 1058
952 src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); 1059 src_line = notes->src->lines = calloc(len, sizeof_src_line);
953 if (!notes->src->lines) 1060 if (!notes->src->lines)
954 return -1; 1061 return -1;
955 1062
@@ -960,29 +1067,41 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
960 size_t line_len; 1067 size_t line_len;
961 u64 offset; 1068 u64 offset;
962 FILE *fp; 1069 FILE *fp;
1070 double percent_max = 0.0;
963 1071
964 src_line[i].percent = 100.0 * h->addr[i] / h->sum; 1072 src_line->nr_pcnt = nr_pcnt;
965 if (src_line[i].percent <= 0.5) 1073
966 continue; 1074 for (k = 0; k < nr_pcnt; k++) {
1075 h = annotation__histogram(notes, evidx + k);
1076 src_line->p[k].percent = 100.0 * h->addr[i] / h->sum;
1077
1078 if (src_line->p[k].percent > percent_max)
1079 percent_max = src_line->p[k].percent;
1080 }
1081
1082 if (percent_max <= 0.5)
1083 goto next;
967 1084
968 offset = start + i; 1085 offset = start + i;
969 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); 1086 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
970 fp = popen(cmd, "r"); 1087 fp = popen(cmd, "r");
971 if (!fp) 1088 if (!fp)
972 continue; 1089 goto next;
973 1090
974 if (getline(&path, &line_len, fp) < 0 || !line_len) 1091 if (getline(&path, &line_len, fp) < 0 || !line_len)
975 goto next; 1092 goto next_close;
976 1093
977 src_line[i].path = malloc(sizeof(char) * line_len + 1); 1094 src_line->path = malloc(sizeof(char) * line_len + 1);
978 if (!src_line[i].path) 1095 if (!src_line->path)
979 goto next; 1096 goto next_close;
980 1097
981 strcpy(src_line[i].path, path); 1098 strcpy(src_line->path, path);
982 insert_source_line(&tmp_root, &src_line[i]); 1099 insert_source_line(&tmp_root, src_line);
983 1100
984 next: 1101 next_close:
985 pclose(fp); 1102 pclose(fp);
1103 next:
1104 src_line = (void *)src_line + sizeof_src_line;
986 } 1105 }
987 1106
988 resort_source_line(root, &tmp_root); 1107 resort_source_line(root, &tmp_root);
@@ -1004,24 +1123,33 @@ static void print_summary(struct rb_root *root, const char *filename)
1004 1123
1005 node = rb_first(root); 1124 node = rb_first(root);
1006 while (node) { 1125 while (node) {
1007 double percent; 1126 double percent, percent_max = 0.0;
1008 const char *color; 1127 const char *color;
1009 char *path; 1128 char *path;
1129 int i;
1010 1130
1011 src_line = rb_entry(node, struct source_line, node); 1131 src_line = rb_entry(node, struct source_line, node);
1012 percent = src_line->percent_sum; 1132 for (i = 0; i < src_line->nr_pcnt; i++) {
1013 color = get_percent_color(percent); 1133 percent = src_line->p[i].percent_sum;
1134 color = get_percent_color(percent);
1135 color_fprintf(stdout, color, " %7.2f", percent);
1136
1137 if (percent > percent_max)
1138 percent_max = percent;
1139 }
1140
1014 path = src_line->path; 1141 path = src_line->path;
1142 color = get_percent_color(percent_max);
1143 color_fprintf(stdout, color, " %s", path);
1015 1144
1016 color_fprintf(stdout, color, " %7.2f %s", percent, path);
1017 node = rb_next(node); 1145 node = rb_next(node);
1018 } 1146 }
1019} 1147}
1020 1148
1021static void symbol__annotate_hits(struct symbol *sym, int evidx) 1149static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
1022{ 1150{
1023 struct annotation *notes = symbol__annotation(sym); 1151 struct annotation *notes = symbol__annotation(sym);
1024 struct sym_hist *h = annotation__histogram(notes, evidx); 1152 struct sym_hist *h = annotation__histogram(notes, evsel->idx);
1025 u64 len = symbol__size(sym), offset; 1153 u64 len = symbol__size(sym), offset;
1026 1154
1027 for (offset = 0; offset < len; ++offset) 1155 for (offset = 0; offset < len; ++offset)
@@ -1031,9 +1159,9 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
1031 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); 1159 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
1032} 1160}
1033 1161
1034int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 1162int symbol__annotate_printf(struct symbol *sym, struct map *map,
1035 bool full_paths, int min_pcnt, int max_lines, 1163 struct perf_evsel *evsel, bool full_paths,
1036 int context) 1164 int min_pcnt, int max_lines, int context)
1037{ 1165{
1038 struct dso *dso = map->dso; 1166 struct dso *dso = map->dso;
1039 char *filename; 1167 char *filename;
@@ -1044,6 +1172,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1044 int printed = 2, queue_len = 0; 1172 int printed = 2, queue_len = 0;
1045 int more = 0; 1173 int more = 0;
1046 u64 len; 1174 u64 len;
1175 int width = 8;
1176 int namelen;
1047 1177
1048 filename = strdup(dso->long_name); 1178 filename = strdup(dso->long_name);
1049 if (!filename) 1179 if (!filename)
@@ -1055,12 +1185,18 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1055 d_filename = basename(filename); 1185 d_filename = basename(filename);
1056 1186
1057 len = symbol__size(sym); 1187 len = symbol__size(sym);
1188 namelen = strlen(d_filename);
1189
1190 if (perf_evsel__is_group_event(evsel))
1191 width *= evsel->nr_members;
1058 1192
1059 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 1193 printf(" %-*.*s| Source code & Disassembly of %s\n",
1060 printf("------------------------------------------------\n"); 1194 width, width, "Percent", d_filename);
1195 printf("-%-*.*s-------------------------------------\n",
1196 width+namelen, width+namelen, graph_dotted_line);
1061 1197
1062 if (verbose) 1198 if (verbose)
1063 symbol__annotate_hits(sym, evidx); 1199 symbol__annotate_hits(sym, evsel);
1064 1200
1065 list_for_each_entry(pos, &notes->src->source, node) { 1201 list_for_each_entry(pos, &notes->src->source, node) {
1066 if (context && queue == NULL) { 1202 if (context && queue == NULL) {
@@ -1068,7 +1204,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1068 queue_len = 0; 1204 queue_len = 0;
1069 } 1205 }
1070 1206
1071 switch (disasm_line__print(pos, sym, start, evidx, len, 1207 switch (disasm_line__print(pos, sym, start, evsel, len,
1072 min_pcnt, printed, max_lines, 1208 min_pcnt, printed, max_lines,
1073 queue)) { 1209 queue)) {
1074 case 0: 1210 case 0:
@@ -1163,9 +1299,9 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp)
1163 return printed; 1299 return printed;
1164} 1300}
1165 1301
1166int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 1302int symbol__tty_annotate(struct symbol *sym, struct map *map,
1167 bool print_lines, bool full_paths, int min_pcnt, 1303 struct perf_evsel *evsel, bool print_lines,
1168 int max_lines) 1304 bool full_paths, int min_pcnt, int max_lines)
1169{ 1305{
1170 struct dso *dso = map->dso; 1306 struct dso *dso = map->dso;
1171 const char *filename = dso->long_name; 1307 const char *filename = dso->long_name;
@@ -1178,12 +1314,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
1178 len = symbol__size(sym); 1314 len = symbol__size(sym);
1179 1315
1180 if (print_lines) { 1316 if (print_lines) {
1181 symbol__get_source_line(sym, map, evidx, &source_line, 1317 symbol__get_source_line(sym, map, evsel, &source_line,
1182 len, filename); 1318 len, filename);
1183 print_summary(&source_line, filename); 1319 print_summary(&source_line, filename);
1184 } 1320 }
1185 1321
1186 symbol__annotate_printf(sym, map, evidx, full_paths, 1322 symbol__annotate_printf(sym, map, evsel, full_paths,
1187 min_pcnt, max_lines, 0); 1323 min_pcnt, max_lines, 0);
1188 if (print_lines) 1324 if (print_lines)
1189 symbol__free_source_line(sym, len); 1325 symbol__free_source_line(sym, len);
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 8eec94358a4a..af755156d278 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -6,6 +6,7 @@
6#include "types.h" 6#include "types.h"
7#include "symbol.h" 7#include "symbol.h"
8#include "hist.h" 8#include "hist.h"
9#include "sort.h"
9#include <linux/list.h> 10#include <linux/list.h>
10#include <linux/rbtree.h> 11#include <linux/rbtree.h>
11#include <pthread.h> 12#include <pthread.h>
@@ -49,6 +50,8 @@ bool ins__is_jump(const struct ins *ins);
49bool ins__is_call(const struct ins *ins); 50bool ins__is_call(const struct ins *ins);
50int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); 51int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
51 52
53struct annotation;
54
52struct disasm_line { 55struct disasm_line {
53 struct list_head node; 56 struct list_head node;
54 s64 offset; 57 s64 offset;
@@ -67,17 +70,24 @@ void disasm_line__free(struct disasm_line *dl);
67struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); 70struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
68int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); 71int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
69size_t disasm__fprintf(struct list_head *head, FILE *fp); 72size_t disasm__fprintf(struct list_head *head, FILE *fp);
73double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
74 s64 end, const char **path);
70 75
71struct sym_hist { 76struct sym_hist {
72 u64 sum; 77 u64 sum;
73 u64 addr[0]; 78 u64 addr[0];
74}; 79};
75 80
76struct source_line { 81struct source_line_percent {
77 struct rb_node node;
78 double percent; 82 double percent;
79 double percent_sum; 83 double percent_sum;
84};
85
86struct source_line {
87 struct rb_node node;
80 char *path; 88 char *path;
89 int nr_pcnt;
90 struct source_line_percent p[1];
81}; 91};
82 92
83/** struct annotated_source - symbols with hits have this attached as in sannotation 93/** struct annotated_source - symbols with hits have this attached as in sannotation
@@ -129,31 +139,56 @@ void symbol__annotate_zero_histograms(struct symbol *sym);
129 139
130int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); 140int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
131int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); 141int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym);
132int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 142int symbol__annotate_printf(struct symbol *sym, struct map *map,
133 bool full_paths, int min_pcnt, int max_lines, 143 struct perf_evsel *evsel, bool full_paths,
134 int context); 144 int min_pcnt, int max_lines, int context);
135void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 145void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
136void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 146void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
137void disasm__purge(struct list_head *head); 147void disasm__purge(struct list_head *head);
138 148
139int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 149int symbol__tty_annotate(struct symbol *sym, struct map *map,
140 bool print_lines, bool full_paths, int min_pcnt, 150 struct perf_evsel *evsel, bool print_lines,
141 int max_lines); 151 bool full_paths, int min_pcnt, int max_lines);
142 152
143#ifdef NEWT_SUPPORT 153#ifdef SLANG_SUPPORT
144int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 154int symbol__tui_annotate(struct symbol *sym, struct map *map,
155 struct perf_evsel *evsel,
145 struct hist_browser_timer *hbt); 156 struct hist_browser_timer *hbt);
146#else 157#else
147static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, 158static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
148 struct map *map __maybe_unused, 159 struct map *map __maybe_unused,
149 int evidx __maybe_unused, 160 struct perf_evsel *evsel __maybe_unused,
150 struct hist_browser_timer *hbt 161 struct hist_browser_timer *hbt
151 __maybe_unused) 162 __maybe_unused)
152{ 163{
153 return 0; 164 return 0;
154} 165}
155#endif 166#endif
156 167
168#ifdef GTK2_SUPPORT
169int symbol__gtk_annotate(struct symbol *sym, struct map *map,
170 struct perf_evsel *evsel,
171 struct hist_browser_timer *hbt);
172
173static inline int hist_entry__gtk_annotate(struct hist_entry *he,
174 struct perf_evsel *evsel,
175 struct hist_browser_timer *hbt)
176{
177 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt);
178}
179
180void perf_gtk__show_annotations(void);
181#else
182static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
183 struct perf_evsel *evsel __maybe_unused,
184 struct hist_browser_timer *hbt __maybe_unused)
185{
186 return 0;
187}
188
189static inline void perf_gtk__show_annotations(void) {}
190#endif
191
157extern const char *disassembler_style; 192extern const char *disassembler_style;
158 193
159#endif /* __PERF_ANNOTATE_H */ 194#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index d3b3f5d82137..42b6a632fe7b 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
444 struct callchain_cursor_node *node = *cursor->last; 444 struct callchain_cursor_node *node = *cursor->last;
445 445
446 if (!node) { 446 if (!node) {
447 node = calloc(sizeof(*node), 1); 447 node = calloc(1, sizeof(*node));
448 if (!node) 448 if (!node)
449 return -ENOMEM; 449 return -ENOMEM;
450 450
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index eb340571e7d6..3ee9f67d5af0 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -143,4 +143,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
143 cursor->curr = cursor->curr->next; 143 cursor->curr = cursor->curr->next;
144 cursor->pos++; 144 cursor->pos++;
145} 145}
146
147struct option;
148
149int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
150extern const char record_callchain_help[];
146#endif /* __PERF_CALLCHAIN_H */ 151#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 2b32ffa9ebdb..beb8cf9f9976 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -1,8 +1,10 @@
1#include "util.h" 1#include "util.h"
2#include "sysfs.h"
2#include "../perf.h" 3#include "../perf.h"
3#include "cpumap.h" 4#include "cpumap.h"
4#include <assert.h> 5#include <assert.h>
5#include <stdio.h> 6#include <stdio.h>
7#include <stdlib.h>
6 8
7static struct cpu_map *cpu_map__default_new(void) 9static struct cpu_map *cpu_map__default_new(void)
8{ 10{
@@ -201,3 +203,117 @@ void cpu_map__delete(struct cpu_map *map)
201{ 203{
202 free(map); 204 free(map);
203} 205}
206
207int cpu_map__get_socket(struct cpu_map *map, int idx)
208{
209 FILE *fp;
210 const char *mnt;
211 char path[PATH_MAX];
212 int cpu, ret;
213
214 if (idx > map->nr)
215 return -1;
216
217 cpu = map->map[idx];
218
219 mnt = sysfs_find_mountpoint();
220 if (!mnt)
221 return -1;
222
223 snprintf(path, PATH_MAX,
224 "%s/devices/system/cpu/cpu%d/topology/physical_package_id",
225 mnt, cpu);
226
227 fp = fopen(path, "r");
228 if (!fp)
229 return -1;
230 ret = fscanf(fp, "%d", &cpu);
231 fclose(fp);
232 return ret == 1 ? cpu : -1;
233}
234
235static int cmp_ids(const void *a, const void *b)
236{
237 return *(int *)a - *(int *)b;
238}
239
240static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
241 int (*f)(struct cpu_map *map, int cpu))
242{
243 struct cpu_map *c;
244 int nr = cpus->nr;
245 int cpu, s1, s2;
246
247 /* allocate as much as possible */
248 c = calloc(1, sizeof(*c) + nr * sizeof(int));
249 if (!c)
250 return -1;
251
252 for (cpu = 0; cpu < nr; cpu++) {
253 s1 = f(cpus, cpu);
254 for (s2 = 0; s2 < c->nr; s2++) {
255 if (s1 == c->map[s2])
256 break;
257 }
258 if (s2 == c->nr) {
259 c->map[c->nr] = s1;
260 c->nr++;
261 }
262 }
263 /* ensure we process id in increasing order */
264 qsort(c->map, c->nr, sizeof(int), cmp_ids);
265
266 *res = c;
267 return 0;
268}
269
270int cpu_map__get_core(struct cpu_map *map, int idx)
271{
272 FILE *fp;
273 const char *mnt;
274 char path[PATH_MAX];
275 int cpu, ret, s;
276
277 if (idx > map->nr)
278 return -1;
279
280 cpu = map->map[idx];
281
282 mnt = sysfs_find_mountpoint();
283 if (!mnt)
284 return -1;
285
286 snprintf(path, PATH_MAX,
287 "%s/devices/system/cpu/cpu%d/topology/core_id",
288 mnt, cpu);
289
290 fp = fopen(path, "r");
291 if (!fp)
292 return -1;
293 ret = fscanf(fp, "%d", &cpu);
294 fclose(fp);
295 if (ret != 1)
296 return -1;
297
298 s = cpu_map__get_socket(map, idx);
299 if (s == -1)
300 return -1;
301
302 /*
303 * encode socket in upper 16 bits
304 * core_id is relative to socket, and
305 * we need a global id. So we combine
306 * socket+ core id
307 */
308 return (s << 16) | (cpu & 0xffff);
309}
310
311int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
312{
313 return cpu_map__build_map(cpus, sockp, cpu_map__get_socket);
314}
315
316int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
317{
318 return cpu_map__build_map(cpus, corep, cpu_map__get_core);
319}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 2f68a3b8c285..9bed02e5fb3d 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -14,6 +14,27 @@ struct cpu_map *cpu_map__dummy_new(void);
14void cpu_map__delete(struct cpu_map *map); 14void cpu_map__delete(struct cpu_map *map);
15struct cpu_map *cpu_map__read(FILE *file); 15struct cpu_map *cpu_map__read(FILE *file);
16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
17int cpu_map__get_socket(struct cpu_map *map, int idx);
18int cpu_map__get_core(struct cpu_map *map, int idx);
19int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
20int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep);
21
22static inline int cpu_map__socket(struct cpu_map *sock, int s)
23{
24 if (!sock || s > sock->nr || s < 0)
25 return 0;
26 return sock->map[s];
27}
28
29static inline int cpu_map__id_to_socket(int id)
30{
31 return id >> 16;
32}
33
34static inline int cpu_map__id_to_cpu(int id)
35{
36 return id & 0xffff;
37}
17 38
18static inline int cpu_map__nr(const struct cpu_map *map) 39static inline int cpu_map__nr(const struct cpu_map *map)
19{ 40{
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 03f830b48148..399e74c34c1a 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -23,10 +23,8 @@ int eprintf(int level, const char *fmt, ...)
23 23
24 if (verbose >= level) { 24 if (verbose >= level) {
25 va_start(args, fmt); 25 va_start(args, fmt);
26 if (use_browser == 1) 26 if (use_browser >= 1)
27 ret = ui_helpline__show_help(fmt, args); 27 ui_helpline__vshow(fmt, args);
28 else if (use_browser == 2)
29 ret = perf_gtk__show_helpline(fmt, args);
30 else 28 else
31 ret = vfprintf(stderr, fmt, args); 29 ret = vfprintf(stderr, fmt, args);
32 va_end(args); 30 va_end(args);
@@ -49,28 +47,6 @@ int dump_printf(const char *fmt, ...)
49 return ret; 47 return ret;
50} 48}
51 49
52#if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT)
53int ui__warning(const char *format, ...)
54{
55 va_list args;
56
57 va_start(args, format);
58 vfprintf(stderr, format, args);
59 va_end(args);
60 return 0;
61}
62#endif
63
64int ui__error_paranoid(void)
65{
66 return ui__error("Permission error - are you root?\n"
67 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
68 " -1 - Not paranoid at all\n"
69 " 0 - Disallow raw tracepoint access for unpriv\n"
70 " 1 - Disallow cpu events for unpriv\n"
71 " 2 - Disallow kernel profiling for unpriv\n");
72}
73
74void trace_event(union perf_event *event) 50void trace_event(union perf_event *event)
75{ 51{
76 unsigned char *raw_event = (void *)event; 52 unsigned char *raw_event = (void *)event;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 83e8d234af6b..efbd98805ad0 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -5,6 +5,8 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include "event.h" 6#include "event.h"
7#include "../ui/helpline.h" 7#include "../ui/helpline.h"
8#include "../ui/progress.h"
9#include "../ui/util.h"
8 10
9extern int verbose; 11extern int verbose;
10extern bool quiet, dump_trace; 12extern bool quiet, dump_trace;
@@ -12,39 +14,7 @@ extern bool quiet, dump_trace;
12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 14int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
13void trace_event(union perf_event *event); 15void trace_event(union perf_event *event);
14 16
15struct ui_progress;
16struct perf_error_ops;
17
18#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT)
19
20#include "../ui/progress.h"
21int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
22#include "../ui/util.h"
23
24#else
25
26static inline void ui_progress__update(u64 curr __maybe_unused,
27 u64 total __maybe_unused,
28 const char *title __maybe_unused) {}
29static inline void ui_progress__finish(void) {}
30
31#define ui__error(format, arg...) ui__warning(format, ##arg)
32
33static inline int
34perf_error__register(struct perf_error_ops *eops __maybe_unused)
35{
36 return 0;
37}
38
39static inline int
40perf_error__unregister(struct perf_error_ops *eops __maybe_unused)
41{
42 return 0;
43}
44
45#endif /* NEWT_SUPPORT || GTK2_SUPPORT */
46
47int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
48int ui__error_paranoid(void);
49 19
50#endif /* __PERF_DEBUG_H */ 20#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
deleted file mode 100644
index dd8b19319c03..000000000000
--- a/tools/perf/util/debugfs.c
+++ /dev/null
@@ -1,114 +0,0 @@
1#include "util.h"
2#include "debugfs.h"
3#include "cache.h"
4
5#include <linux/kernel.h>
6#include <sys/mount.h>
7
8static int debugfs_premounted;
9char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug";
10char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
11
12static const char *debugfs_known_mountpoints[] = {
13 "/sys/kernel/debug/",
14 "/debug/",
15 0,
16};
17
18static int debugfs_found;
19
20/* find the path to the mounted debugfs */
21const char *debugfs_find_mountpoint(void)
22{
23 const char **ptr;
24 char type[100];
25 FILE *fp;
26
27 if (debugfs_found)
28 return (const char *) debugfs_mountpoint;
29
30 ptr = debugfs_known_mountpoints;
31 while (*ptr) {
32 if (debugfs_valid_mountpoint(*ptr) == 0) {
33 debugfs_found = 1;
34 strcpy(debugfs_mountpoint, *ptr);
35 return debugfs_mountpoint;
36 }
37 ptr++;
38 }
39
40 /* give up and parse /proc/mounts */
41 fp = fopen("/proc/mounts", "r");
42 if (fp == NULL)
43 return NULL;
44
45 while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
46 debugfs_mountpoint, type) == 2) {
47 if (strcmp(type, "debugfs") == 0)
48 break;
49 }
50 fclose(fp);
51
52 if (strcmp(type, "debugfs") != 0)
53 return NULL;
54
55 debugfs_found = 1;
56
57 return debugfs_mountpoint;
58}
59
60/* verify that a mountpoint is actually a debugfs instance */
61
62int debugfs_valid_mountpoint(const char *debugfs)
63{
64 struct statfs st_fs;
65
66 if (statfs(debugfs, &st_fs) < 0)
67 return -ENOENT;
68 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
69 return -ENOENT;
70
71 return 0;
72}
73
74static void debugfs_set_tracing_events_path(const char *mountpoint)
75{
76 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
77 mountpoint, "tracing/events");
78}
79
80/* mount the debugfs somewhere if it's not mounted */
81
82char *debugfs_mount(const char *mountpoint)
83{
84 /* see if it's already mounted */
85 if (debugfs_find_mountpoint()) {
86 debugfs_premounted = 1;
87 goto out;
88 }
89
90 /* if not mounted and no argument */
91 if (mountpoint == NULL) {
92 /* see if environment variable set */
93 mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
94 /* if no environment variable, use default */
95 if (mountpoint == NULL)
96 mountpoint = "/sys/kernel/debug";
97 }
98
99 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
100 return NULL;
101
102 /* save the mountpoint */
103 debugfs_found = 1;
104 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
105out:
106 debugfs_set_tracing_events_path(debugfs_mountpoint);
107 return debugfs_mountpoint;
108}
109
110void debugfs_set_path(const char *mountpoint)
111{
112 snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
113 debugfs_set_tracing_events_path(mountpoint);
114}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
deleted file mode 100644
index 68f3e87ec57f..000000000000
--- a/tools/perf/util/debugfs.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__
3
4const char *debugfs_find_mountpoint(void);
5int debugfs_valid_mountpoint(const char *debugfs);
6char *debugfs_mount(const char *mountpoint);
7void debugfs_set_path(const char *mountpoint);
8
9extern char debugfs_mountpoint[];
10extern char tracing_events_path[];
11
12#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index d6d9a465acdb..6f7d5a9d6b05 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -539,13 +539,13 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name)
539} 539}
540 540
541size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 541size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
542 bool with_hits) 542 bool (skip)(struct dso *dso, int parm), int parm)
543{ 543{
544 struct dso *pos; 544 struct dso *pos;
545 size_t ret = 0; 545 size_t ret = 0;
546 546
547 list_for_each_entry(pos, head, node) { 547 list_for_each_entry(pos, head, node) {
548 if (with_hits && !pos->hit) 548 if (skip && skip(pos, parm))
549 continue; 549 continue;
550 ret += dso__fprintf_buildid(pos, fp); 550 ret += dso__fprintf_buildid(pos, fp);
551 ret += fprintf(fp, " %s\n", pos->long_name); 551 ret += fprintf(fp, " %s\n", pos->long_name);
@@ -583,7 +583,7 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
583 if (dso->short_name != dso->long_name) 583 if (dso->short_name != dso->long_name)
584 ret += fprintf(fp, "%s, ", dso->long_name); 584 ret += fprintf(fp, "%s, ", dso->long_name);
585 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 585 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
586 dso->loaded ? "" : "NOT "); 586 dso__loaded(dso, type) ? "" : "NOT ");
587 ret += dso__fprintf_buildid(dso, fp); 587 ret += dso__fprintf_buildid(dso, fp);
588 ret += fprintf(fp, ")\n"); 588 ret += fprintf(fp, ")\n");
589 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { 589 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index e03276940b99..450199ab51b5 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -138,7 +138,7 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name);
138bool __dsos__read_build_ids(struct list_head *head, bool with_hits); 138bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
139 139
140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
141 bool with_hits); 141 bool (skip)(struct dso *dso, int parm), int parm);
142size_t __dsos__fprintf(struct list_head *head, FILE *fp); 142size_t __dsos__fprintf(struct list_head *head, FILE *fp);
143 143
144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); 144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 3cf2c3e0605f..5cd13d768cec 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -476,8 +476,10 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
476 } 476 }
477 } 477 }
478 478
479 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) 479 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) {
480 free(event);
480 return -ENOENT; 481 return -ENOENT;
482 }
481 483
482 map = machine->vmlinux_maps[MAP__FUNCTION]; 484 map = machine->vmlinux_maps[MAP__FUNCTION];
483 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 485 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 0d573ff4771a..181389535c0c 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -88,8 +88,10 @@ struct perf_sample {
88 u64 id; 88 u64 id;
89 u64 stream_id; 89 u64 stream_id;
90 u64 period; 90 u64 period;
91 u64 weight;
91 u32 cpu; 92 u32 cpu;
92 u32 raw_size; 93 u32 raw_size;
94 u64 data_src;
93 void *raw_data; 95 void *raw_data;
94 struct ip_callchain *callchain; 96 struct ip_callchain *callchain;
95 struct branch_stack *branch_stack; 97 struct branch_stack *branch_stack;
@@ -97,6 +99,13 @@ struct perf_sample {
97 struct stack_dump user_stack; 99 struct stack_dump user_stack;
98}; 100};
99 101
102#define PERF_MEM_DATA_SRC_NONE \
103 (PERF_MEM_S(OP, NA) |\
104 PERF_MEM_S(LVL, NA) |\
105 PERF_MEM_S(SNOOP, NA) |\
106 PERF_MEM_S(LOCK, NA) |\
107 PERF_MEM_S(TLB, NA))
108
100struct build_id_event { 109struct build_id_event {
101 struct perf_event_header header; 110 struct perf_event_header header;
102 pid_t pid; 111 pid_t pid;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 705293489e3c..99b43dd18c57 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -7,7 +7,7 @@
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9#include "util.h" 9#include "util.h"
10#include "debugfs.h" 10#include <lk/debugfs.h>
11#include <poll.h> 11#include <poll.h>
12#include "cpumap.h" 12#include "cpumap.h"
13#include "thread_map.h" 13#include "thread_map.h"
@@ -38,21 +38,26 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
38 evlist->workload.pid = -1; 38 evlist->workload.pid = -1;
39} 39}
40 40
41struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 41struct perf_evlist *perf_evlist__new(void)
42 struct thread_map *threads)
43{ 42{
44 struct perf_evlist *evlist = zalloc(sizeof(*evlist)); 43 struct perf_evlist *evlist = zalloc(sizeof(*evlist));
45 44
46 if (evlist != NULL) 45 if (evlist != NULL)
47 perf_evlist__init(evlist, cpus, threads); 46 perf_evlist__init(evlist, NULL, NULL);
48 47
49 return evlist; 48 return evlist;
50} 49}
51 50
52void perf_evlist__config_attrs(struct perf_evlist *evlist, 51void perf_evlist__config(struct perf_evlist *evlist,
53 struct perf_record_opts *opts) 52 struct perf_record_opts *opts)
54{ 53{
55 struct perf_evsel *evsel; 54 struct perf_evsel *evsel;
55 /*
56 * Set the evsel leader links before we configure attributes,
57 * since some might depend on this info.
58 */
59 if (opts->group)
60 perf_evlist__set_leader(evlist);
56 61
57 if (evlist->cpus->map[0] < 0) 62 if (evlist->cpus->map[0] < 0)
58 opts->no_inherit = true; 63 opts->no_inherit = true;
@@ -61,7 +66,7 @@ void perf_evlist__config_attrs(struct perf_evlist *evlist,
61 perf_evsel__config(evsel, opts); 66 perf_evsel__config(evsel, opts);
62 67
63 if (evlist->nr_entries > 1) 68 if (evlist->nr_entries > 1)
64 evsel->attr.sample_type |= PERF_SAMPLE_ID; 69 perf_evsel__set_sample_id(evsel);
65 } 70 }
66} 71}
67 72
@@ -111,18 +116,21 @@ void __perf_evlist__set_leader(struct list_head *list)
111 struct perf_evsel *evsel, *leader; 116 struct perf_evsel *evsel, *leader;
112 117
113 leader = list_entry(list->next, struct perf_evsel, node); 118 leader = list_entry(list->next, struct perf_evsel, node);
114 leader->leader = NULL; 119 evsel = list_entry(list->prev, struct perf_evsel, node);
120
121 leader->nr_members = evsel->idx - leader->idx + 1;
115 122
116 list_for_each_entry(evsel, list, node) { 123 list_for_each_entry(evsel, list, node) {
117 if (evsel != leader) 124 evsel->leader = leader;
118 evsel->leader = leader;
119 } 125 }
120} 126}
121 127
122void perf_evlist__set_leader(struct perf_evlist *evlist) 128void perf_evlist__set_leader(struct perf_evlist *evlist)
123{ 129{
124 if (evlist->nr_entries) 130 if (evlist->nr_entries) {
131 evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0;
125 __perf_evlist__set_leader(&evlist->entries); 132 __perf_evlist__set_leader(&evlist->entries);
133 }
126} 134}
127 135
128int perf_evlist__add_default(struct perf_evlist *evlist) 136int perf_evlist__add_default(struct perf_evlist *evlist)
@@ -219,12 +227,14 @@ void perf_evlist__disable(struct perf_evlist *evlist)
219{ 227{
220 int cpu, thread; 228 int cpu, thread;
221 struct perf_evsel *pos; 229 struct perf_evsel *pos;
230 int nr_cpus = cpu_map__nr(evlist->cpus);
231 int nr_threads = thread_map__nr(evlist->threads);
222 232
223 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 233 for (cpu = 0; cpu < nr_cpus; cpu++) {
224 list_for_each_entry(pos, &evlist->entries, node) { 234 list_for_each_entry(pos, &evlist->entries, node) {
225 if (perf_evsel__is_group_member(pos)) 235 if (!perf_evsel__is_group_leader(pos))
226 continue; 236 continue;
227 for (thread = 0; thread < evlist->threads->nr; thread++) 237 for (thread = 0; thread < nr_threads; thread++)
228 ioctl(FD(pos, cpu, thread), 238 ioctl(FD(pos, cpu, thread),
229 PERF_EVENT_IOC_DISABLE, 0); 239 PERF_EVENT_IOC_DISABLE, 0);
230 } 240 }
@@ -235,12 +245,14 @@ void perf_evlist__enable(struct perf_evlist *evlist)
235{ 245{
236 int cpu, thread; 246 int cpu, thread;
237 struct perf_evsel *pos; 247 struct perf_evsel *pos;
248 int nr_cpus = cpu_map__nr(evlist->cpus);
249 int nr_threads = thread_map__nr(evlist->threads);
238 250
239 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { 251 for (cpu = 0; cpu < nr_cpus; cpu++) {
240 list_for_each_entry(pos, &evlist->entries, node) { 252 list_for_each_entry(pos, &evlist->entries, node) {
241 if (perf_evsel__is_group_member(pos)) 253 if (!perf_evsel__is_group_leader(pos))
242 continue; 254 continue;
243 for (thread = 0; thread < evlist->threads->nr; thread++) 255 for (thread = 0; thread < nr_threads; thread++)
244 ioctl(FD(pos, cpu, thread), 256 ioctl(FD(pos, cpu, thread),
245 PERF_EVENT_IOC_ENABLE, 0); 257 PERF_EVENT_IOC_ENABLE, 0);
246 } 258 }
@@ -249,7 +261,9 @@ void perf_evlist__enable(struct perf_evlist *evlist)
249 261
250static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 262static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
251{ 263{
252 int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries; 264 int nr_cpus = cpu_map__nr(evlist->cpus);
265 int nr_threads = thread_map__nr(evlist->threads);
266 int nfds = nr_cpus * nr_threads * evlist->nr_entries;
253 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); 267 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
254 return evlist->pollfd != NULL ? 0 : -ENOMEM; 268 return evlist->pollfd != NULL ? 0 : -ENOMEM;
255} 269}
@@ -305,7 +319,6 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
305struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) 319struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
306{ 320{
307 struct hlist_head *head; 321 struct hlist_head *head;
308 struct hlist_node *pos;
309 struct perf_sample_id *sid; 322 struct perf_sample_id *sid;
310 int hash; 323 int hash;
311 324
@@ -315,7 +328,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
315 hash = hash_64(id, PERF_EVLIST__HLIST_BITS); 328 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
316 head = &evlist->heads[hash]; 329 head = &evlist->heads[hash];
317 330
318 hlist_for_each_entry(sid, pos, head, node) 331 hlist_for_each_entry(sid, head, node)
319 if (sid->id == id) 332 if (sid->id == id)
320 return sid->evsel; 333 return sid->evsel;
321 334
@@ -366,7 +379,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
366 if ((old & md->mask) + size != ((old + size) & md->mask)) { 379 if ((old & md->mask) + size != ((old + size) & md->mask)) {
367 unsigned int offset = old; 380 unsigned int offset = old;
368 unsigned int len = min(sizeof(*event), size), cpy; 381 unsigned int len = min(sizeof(*event), size), cpy;
369 void *dst = &evlist->event_copy; 382 void *dst = &md->event_copy;
370 383
371 do { 384 do {
372 cpy = min(md->mask + 1 - (offset & md->mask), len); 385 cpy = min(md->mask + 1 - (offset & md->mask), len);
@@ -376,7 +389,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
376 len -= cpy; 389 len -= cpy;
377 } while (len); 390 } while (len);
378 391
379 event = &evlist->event_copy; 392 event = &md->event_copy;
380 } 393 }
381 394
382 old += size; 395 old += size;
@@ -409,7 +422,7 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
409{ 422{
410 evlist->nr_mmaps = cpu_map__nr(evlist->cpus); 423 evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
411 if (cpu_map__all(evlist->cpus)) 424 if (cpu_map__all(evlist->cpus))
412 evlist->nr_mmaps = evlist->threads->nr; 425 evlist->nr_mmaps = thread_map__nr(evlist->threads);
413 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); 426 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
414 return evlist->mmap != NULL ? 0 : -ENOMEM; 427 return evlist->mmap != NULL ? 0 : -ENOMEM;
415} 428}
@@ -434,11 +447,13 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
434{ 447{
435 struct perf_evsel *evsel; 448 struct perf_evsel *evsel;
436 int cpu, thread; 449 int cpu, thread;
450 int nr_cpus = cpu_map__nr(evlist->cpus);
451 int nr_threads = thread_map__nr(evlist->threads);
437 452
438 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 453 for (cpu = 0; cpu < nr_cpus; cpu++) {
439 int output = -1; 454 int output = -1;
440 455
441 for (thread = 0; thread < evlist->threads->nr; thread++) { 456 for (thread = 0; thread < nr_threads; thread++) {
442 list_for_each_entry(evsel, &evlist->entries, node) { 457 list_for_each_entry(evsel, &evlist->entries, node) {
443 int fd = FD(evsel, cpu, thread); 458 int fd = FD(evsel, cpu, thread);
444 459
@@ -462,7 +477,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
462 return 0; 477 return 0;
463 478
464out_unmap: 479out_unmap:
465 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 480 for (cpu = 0; cpu < nr_cpus; cpu++) {
466 if (evlist->mmap[cpu].base != NULL) { 481 if (evlist->mmap[cpu].base != NULL) {
467 munmap(evlist->mmap[cpu].base, evlist->mmap_len); 482 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
468 evlist->mmap[cpu].base = NULL; 483 evlist->mmap[cpu].base = NULL;
@@ -475,8 +490,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
475{ 490{
476 struct perf_evsel *evsel; 491 struct perf_evsel *evsel;
477 int thread; 492 int thread;
493 int nr_threads = thread_map__nr(evlist->threads);
478 494
479 for (thread = 0; thread < evlist->threads->nr; thread++) { 495 for (thread = 0; thread < nr_threads; thread++) {
480 int output = -1; 496 int output = -1;
481 497
482 list_for_each_entry(evsel, &evlist->entries, node) { 498 list_for_each_entry(evsel, &evlist->entries, node) {
@@ -501,7 +517,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
501 return 0; 517 return 0;
502 518
503out_unmap: 519out_unmap:
504 for (thread = 0; thread < evlist->threads->nr; thread++) { 520 for (thread = 0; thread < nr_threads; thread++) {
505 if (evlist->mmap[thread].base != NULL) { 521 if (evlist->mmap[thread].base != NULL) {
506 munmap(evlist->mmap[thread].base, evlist->mmap_len); 522 munmap(evlist->mmap[thread].base, evlist->mmap_len);
507 evlist->mmap[thread].base = NULL; 523 evlist->mmap[thread].base = NULL;
@@ -602,7 +618,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist)
602 struct perf_evsel *evsel; 618 struct perf_evsel *evsel;
603 int err = 0; 619 int err = 0;
604 const int ncpus = cpu_map__nr(evlist->cpus), 620 const int ncpus = cpu_map__nr(evlist->cpus),
605 nthreads = evlist->threads->nr; 621 nthreads = thread_map__nr(evlist->threads);
606 622
607 list_for_each_entry(evsel, &evlist->entries, node) { 623 list_for_each_entry(evsel, &evlist->entries, node) {
608 if (evsel->filter == NULL) 624 if (evsel->filter == NULL)
@@ -621,7 +637,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
621 struct perf_evsel *evsel; 637 struct perf_evsel *evsel;
622 int err = 0; 638 int err = 0;
623 const int ncpus = cpu_map__nr(evlist->cpus), 639 const int ncpus = cpu_map__nr(evlist->cpus),
624 nthreads = evlist->threads->nr; 640 nthreads = thread_map__nr(evlist->threads);
625 641
626 list_for_each_entry(evsel, &evlist->entries, node) { 642 list_for_each_entry(evsel, &evlist->entries, node) {
627 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); 643 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
@@ -704,10 +720,20 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
704 evlist->selected = evsel; 720 evlist->selected = evsel;
705} 721}
706 722
723void perf_evlist__close(struct perf_evlist *evlist)
724{
725 struct perf_evsel *evsel;
726 int ncpus = cpu_map__nr(evlist->cpus);
727 int nthreads = thread_map__nr(evlist->threads);
728
729 list_for_each_entry_reverse(evsel, &evlist->entries, node)
730 perf_evsel__close(evsel, ncpus, nthreads);
731}
732
707int perf_evlist__open(struct perf_evlist *evlist) 733int perf_evlist__open(struct perf_evlist *evlist)
708{ 734{
709 struct perf_evsel *evsel; 735 struct perf_evsel *evsel;
710 int err, ncpus, nthreads; 736 int err;
711 737
712 list_for_each_entry(evsel, &evlist->entries, node) { 738 list_for_each_entry(evsel, &evlist->entries, node) {
713 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); 739 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
@@ -717,19 +743,15 @@ int perf_evlist__open(struct perf_evlist *evlist)
717 743
718 return 0; 744 return 0;
719out_err: 745out_err:
720 ncpus = evlist->cpus ? evlist->cpus->nr : 1; 746 perf_evlist__close(evlist);
721 nthreads = evlist->threads ? evlist->threads->nr : 1;
722
723 list_for_each_entry_reverse(evsel, &evlist->entries, node)
724 perf_evsel__close(evsel, ncpus, nthreads);
725
726 errno = -err; 747 errno = -err;
727 return err; 748 return err;
728} 749}
729 750
730int perf_evlist__prepare_workload(struct perf_evlist *evlist, 751int perf_evlist__prepare_workload(struct perf_evlist *evlist,
731 struct perf_record_opts *opts, 752 struct perf_target *target,
732 const char *argv[]) 753 const char *argv[], bool pipe_output,
754 bool want_signal)
733{ 755{
734 int child_ready_pipe[2], go_pipe[2]; 756 int child_ready_pipe[2], go_pipe[2];
735 char bf; 757 char bf;
@@ -751,9 +773,11 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
751 } 773 }
752 774
753 if (!evlist->workload.pid) { 775 if (!evlist->workload.pid) {
754 if (opts->pipe_output) 776 if (pipe_output)
755 dup2(2, 1); 777 dup2(2, 1);
756 778
779 signal(SIGTERM, SIG_DFL);
780
757 close(child_ready_pipe[0]); 781 close(child_ready_pipe[0]);
758 close(go_pipe[1]); 782 close(go_pipe[1]);
759 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 783 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
@@ -779,11 +803,12 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
779 execvp(argv[0], (char **)argv); 803 execvp(argv[0], (char **)argv);
780 804
781 perror(argv[0]); 805 perror(argv[0]);
782 kill(getppid(), SIGUSR1); 806 if (want_signal)
807 kill(getppid(), SIGUSR1);
783 exit(-1); 808 exit(-1);
784 } 809 }
785 810
786 if (perf_target__none(&opts->target)) 811 if (perf_target__none(target))
787 evlist->threads->map[0] = evlist->workload.pid; 812 evlist->threads->map[0] = evlist->workload.pid;
788 813
789 close(child_ready_pipe[1]); 814 close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 56003f779e60..0583d36252be 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -17,10 +17,18 @@ struct perf_record_opts;
17#define PERF_EVLIST__HLIST_BITS 8 17#define PERF_EVLIST__HLIST_BITS 8
18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
19 19
20struct perf_mmap {
21 void *base;
22 int mask;
23 unsigned int prev;
24 union perf_event event_copy;
25};
26
20struct perf_evlist { 27struct perf_evlist {
21 struct list_head entries; 28 struct list_head entries;
22 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; 29 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
23 int nr_entries; 30 int nr_entries;
31 int nr_groups;
24 int nr_fds; 32 int nr_fds;
25 int nr_mmaps; 33 int nr_mmaps;
26 int mmap_len; 34 int mmap_len;
@@ -29,7 +37,6 @@ struct perf_evlist {
29 pid_t pid; 37 pid_t pid;
30 } workload; 38 } workload;
31 bool overwrite; 39 bool overwrite;
32 union perf_event event_copy;
33 struct perf_mmap *mmap; 40 struct perf_mmap *mmap;
34 struct pollfd *pollfd; 41 struct pollfd *pollfd;
35 struct thread_map *threads; 42 struct thread_map *threads;
@@ -42,8 +49,7 @@ struct perf_evsel_str_handler {
42 void *handler; 49 void *handler;
43}; 50};
44 51
45struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 52struct perf_evlist *perf_evlist__new(void);
46 struct thread_map *threads);
47void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, 53void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
48 struct thread_map *threads); 54 struct thread_map *threads);
49void perf_evlist__exit(struct perf_evlist *evlist); 55void perf_evlist__exit(struct perf_evlist *evlist);
@@ -75,13 +81,15 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
75union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 81union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
76 82
77int perf_evlist__open(struct perf_evlist *evlist); 83int perf_evlist__open(struct perf_evlist *evlist);
84void perf_evlist__close(struct perf_evlist *evlist);
78 85
79void perf_evlist__config_attrs(struct perf_evlist *evlist, 86void perf_evlist__config(struct perf_evlist *evlist,
80 struct perf_record_opts *opts); 87 struct perf_record_opts *opts);
81 88
82int perf_evlist__prepare_workload(struct perf_evlist *evlist, 89int perf_evlist__prepare_workload(struct perf_evlist *evlist,
83 struct perf_record_opts *opts, 90 struct perf_target *target,
84 const char *argv[]); 91 const char *argv[], bool pipe_output,
92 bool want_signal);
85int perf_evlist__start_workload(struct perf_evlist *evlist); 93int perf_evlist__start_workload(struct perf_evlist *evlist);
86 94
87int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 95int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
@@ -135,4 +143,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
135} 143}
136 144
137size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); 145size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
146
147static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
148{
149 struct perf_event_mmap_page *pc = mm->base;
150 int head = pc->data_head;
151 rmb();
152 return head;
153}
154
155static inline void perf_mmap__write_tail(struct perf_mmap *md,
156 unsigned long tail)
157{
158 struct perf_event_mmap_page *pc = md->base;
159
160 /*
161 * ensure all reads are done before we write the tail out.
162 */
163 /* mb(); */
164 pc->data_tail = tail;
165}
166
138#endif /* __PERF_EVLIST_H */ 167#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1b16dd1edc8e..63b6f8c8edf2 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -10,7 +10,7 @@
10#include <byteswap.h> 10#include <byteswap.h>
11#include <linux/bitops.h> 11#include <linux/bitops.h>
12#include "asm/bug.h" 12#include "asm/bug.h"
13#include "debugfs.h" 13#include <lk/debugfs.h>
14#include "event-parse.h" 14#include "event-parse.h"
15#include "evsel.h" 15#include "evsel.h"
16#include "evlist.h" 16#include "evlist.h"
@@ -22,6 +22,11 @@
22#include <linux/perf_event.h> 22#include <linux/perf_event.h>
23#include "perf_regs.h" 23#include "perf_regs.h"
24 24
25static struct {
26 bool sample_id_all;
27 bool exclude_guest;
28} perf_missing_features;
29
25#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 30#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
26 31
27static int __perf_evsel__sample_size(u64 sample_type) 32static int __perf_evsel__sample_size(u64 sample_type)
@@ -50,11 +55,36 @@ void hists__init(struct hists *hists)
50 pthread_mutex_init(&hists->lock, NULL); 55 pthread_mutex_init(&hists->lock, NULL);
51} 56}
52 57
58void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
59 enum perf_event_sample_format bit)
60{
61 if (!(evsel->attr.sample_type & bit)) {
62 evsel->attr.sample_type |= bit;
63 evsel->sample_size += sizeof(u64);
64 }
65}
66
67void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
68 enum perf_event_sample_format bit)
69{
70 if (evsel->attr.sample_type & bit) {
71 evsel->attr.sample_type &= ~bit;
72 evsel->sample_size -= sizeof(u64);
73 }
74}
75
76void perf_evsel__set_sample_id(struct perf_evsel *evsel)
77{
78 perf_evsel__set_sample_bit(evsel, ID);
79 evsel->attr.read_format |= PERF_FORMAT_ID;
80}
81
53void perf_evsel__init(struct perf_evsel *evsel, 82void perf_evsel__init(struct perf_evsel *evsel,
54 struct perf_event_attr *attr, int idx) 83 struct perf_event_attr *attr, int idx)
55{ 84{
56 evsel->idx = idx; 85 evsel->idx = idx;
57 evsel->attr = *attr; 86 evsel->attr = *attr;
87 evsel->leader = evsel;
58 INIT_LIST_HEAD(&evsel->node); 88 INIT_LIST_HEAD(&evsel->node);
59 hists__init(&evsel->hists); 89 hists__init(&evsel->hists);
60 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 90 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
@@ -404,6 +434,31 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
404 return evsel->name ?: "unknown"; 434 return evsel->name ?: "unknown";
405} 435}
406 436
437const char *perf_evsel__group_name(struct perf_evsel *evsel)
438{
439 return evsel->group_name ?: "anon group";
440}
441
442int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
443{
444 int ret;
445 struct perf_evsel *pos;
446 const char *group_name = perf_evsel__group_name(evsel);
447
448 ret = scnprintf(buf, size, "%s", group_name);
449
450 ret += scnprintf(buf + ret, size - ret, " { %s",
451 perf_evsel__name(evsel));
452
453 for_each_group_member(pos, evsel)
454 ret += scnprintf(buf + ret, size - ret, ", %s",
455 perf_evsel__name(pos));
456
457 ret += scnprintf(buf + ret, size - ret, " }");
458
459 return ret;
460}
461
407/* 462/*
408 * The enable_on_exec/disabled value strategy: 463 * The enable_on_exec/disabled value strategy:
409 * 464 *
@@ -438,13 +493,11 @@ void perf_evsel__config(struct perf_evsel *evsel,
438 struct perf_event_attr *attr = &evsel->attr; 493 struct perf_event_attr *attr = &evsel->attr;
439 int track = !evsel->idx; /* only the first counter needs these */ 494 int track = !evsel->idx; /* only the first counter needs these */
440 495
441 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 496 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
442 attr->inherit = !opts->no_inherit; 497 attr->inherit = !opts->no_inherit;
443 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
444 PERF_FORMAT_TOTAL_TIME_RUNNING |
445 PERF_FORMAT_ID;
446 498
447 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 499 perf_evsel__set_sample_bit(evsel, IP);
500 perf_evsel__set_sample_bit(evsel, TID);
448 501
449 /* 502 /*
450 * We default some events to a 1 default interval. But keep 503 * We default some events to a 1 default interval. But keep
@@ -453,7 +506,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
453 if (!attr->sample_period || (opts->user_freq != UINT_MAX && 506 if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
454 opts->user_interval != ULLONG_MAX)) { 507 opts->user_interval != ULLONG_MAX)) {
455 if (opts->freq) { 508 if (opts->freq) {
456 attr->sample_type |= PERF_SAMPLE_PERIOD; 509 perf_evsel__set_sample_bit(evsel, PERIOD);
457 attr->freq = 1; 510 attr->freq = 1;
458 attr->sample_freq = opts->freq; 511 attr->sample_freq = opts->freq;
459 } else { 512 } else {
@@ -468,16 +521,16 @@ void perf_evsel__config(struct perf_evsel *evsel,
468 attr->inherit_stat = 1; 521 attr->inherit_stat = 1;
469 522
470 if (opts->sample_address) { 523 if (opts->sample_address) {
471 attr->sample_type |= PERF_SAMPLE_ADDR; 524 perf_evsel__set_sample_bit(evsel, ADDR);
472 attr->mmap_data = track; 525 attr->mmap_data = track;
473 } 526 }
474 527
475 if (opts->call_graph) { 528 if (opts->call_graph) {
476 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 529 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
477 530
478 if (opts->call_graph == CALLCHAIN_DWARF) { 531 if (opts->call_graph == CALLCHAIN_DWARF) {
479 attr->sample_type |= PERF_SAMPLE_REGS_USER | 532 perf_evsel__set_sample_bit(evsel, REGS_USER);
480 PERF_SAMPLE_STACK_USER; 533 perf_evsel__set_sample_bit(evsel, STACK_USER);
481 attr->sample_regs_user = PERF_REGS_MASK; 534 attr->sample_regs_user = PERF_REGS_MASK;
482 attr->sample_stack_user = opts->stack_dump_size; 535 attr->sample_stack_user = opts->stack_dump_size;
483 attr->exclude_callchain_user = 1; 536 attr->exclude_callchain_user = 1;
@@ -485,31 +538,37 @@ void perf_evsel__config(struct perf_evsel *evsel,
485 } 538 }
486 539
487 if (perf_target__has_cpu(&opts->target)) 540 if (perf_target__has_cpu(&opts->target))
488 attr->sample_type |= PERF_SAMPLE_CPU; 541 perf_evsel__set_sample_bit(evsel, CPU);
489 542
490 if (opts->period) 543 if (opts->period)
491 attr->sample_type |= PERF_SAMPLE_PERIOD; 544 perf_evsel__set_sample_bit(evsel, PERIOD);
492 545
493 if (!opts->sample_id_all_missing && 546 if (!perf_missing_features.sample_id_all &&
494 (opts->sample_time || !opts->no_inherit || 547 (opts->sample_time || !opts->no_inherit ||
495 perf_target__has_cpu(&opts->target))) 548 perf_target__has_cpu(&opts->target)))
496 attr->sample_type |= PERF_SAMPLE_TIME; 549 perf_evsel__set_sample_bit(evsel, TIME);
497 550
498 if (opts->raw_samples) { 551 if (opts->raw_samples) {
499 attr->sample_type |= PERF_SAMPLE_TIME; 552 perf_evsel__set_sample_bit(evsel, TIME);
500 attr->sample_type |= PERF_SAMPLE_RAW; 553 perf_evsel__set_sample_bit(evsel, RAW);
501 attr->sample_type |= PERF_SAMPLE_CPU; 554 perf_evsel__set_sample_bit(evsel, CPU);
502 } 555 }
503 556
557 if (opts->sample_address)
558 attr->sample_type |= PERF_SAMPLE_DATA_SRC;
559
504 if (opts->no_delay) { 560 if (opts->no_delay) {
505 attr->watermark = 0; 561 attr->watermark = 0;
506 attr->wakeup_events = 1; 562 attr->wakeup_events = 1;
507 } 563 }
508 if (opts->branch_stack) { 564 if (opts->branch_stack) {
509 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; 565 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
510 attr->branch_sample_type = opts->branch_stack; 566 attr->branch_sample_type = opts->branch_stack;
511 } 567 }
512 568
569 if (opts->sample_weight)
570 attr->sample_type |= PERF_SAMPLE_WEIGHT;
571
513 attr->mmap = track; 572 attr->mmap = track;
514 attr->comm = track; 573 attr->comm = track;
515 574
@@ -519,14 +578,14 @@ void perf_evsel__config(struct perf_evsel *evsel,
519 * Disabling only independent events or group leaders, 578 * Disabling only independent events or group leaders,
520 * keeping group members enabled. 579 * keeping group members enabled.
521 */ 580 */
522 if (!perf_evsel__is_group_member(evsel)) 581 if (perf_evsel__is_group_leader(evsel))
523 attr->disabled = 1; 582 attr->disabled = 1;
524 583
525 /* 584 /*
526 * Setting enable_on_exec for independent events and 585 * Setting enable_on_exec for independent events and
527 * group leaders for traced executed by perf. 586 * group leaders for traced executed by perf.
528 */ 587 */
529 if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel)) 588 if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel))
530 attr->enable_on_exec = 1; 589 attr->enable_on_exec = 1;
531} 590}
532 591
@@ -580,6 +639,12 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
580 return 0; 639 return 0;
581} 640}
582 641
642void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus)
643{
644 memset(evsel->counts, 0, (sizeof(*evsel->counts) +
645 (ncpus * sizeof(struct perf_counts_values))));
646}
647
583int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 648int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
584{ 649{
585 evsel->counts = zalloc((sizeof(*evsel->counts) + 650 evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -612,12 +677,16 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
612 } 677 }
613} 678}
614 679
680void perf_evsel__free_counts(struct perf_evsel *evsel)
681{
682 free(evsel->counts);
683}
684
615void perf_evsel__exit(struct perf_evsel *evsel) 685void perf_evsel__exit(struct perf_evsel *evsel)
616{ 686{
617 assert(list_empty(&evsel->node)); 687 assert(list_empty(&evsel->node));
618 xyarray__delete(evsel->fd); 688 perf_evsel__free_fd(evsel);
619 xyarray__delete(evsel->sample_id); 689 perf_evsel__free_id(evsel);
620 free(evsel->id);
621} 690}
622 691
623void perf_evsel__delete(struct perf_evsel *evsel) 692void perf_evsel__delete(struct perf_evsel *evsel)
@@ -631,6 +700,28 @@ void perf_evsel__delete(struct perf_evsel *evsel)
631 free(evsel); 700 free(evsel);
632} 701}
633 702
703static inline void compute_deltas(struct perf_evsel *evsel,
704 int cpu,
705 struct perf_counts_values *count)
706{
707 struct perf_counts_values tmp;
708
709 if (!evsel->prev_raw_counts)
710 return;
711
712 if (cpu == -1) {
713 tmp = evsel->prev_raw_counts->aggr;
714 evsel->prev_raw_counts->aggr = *count;
715 } else {
716 tmp = evsel->prev_raw_counts->cpu[cpu];
717 evsel->prev_raw_counts->cpu[cpu] = *count;
718 }
719
720 count->val = count->val - tmp.val;
721 count->ena = count->ena - tmp.ena;
722 count->run = count->run - tmp.run;
723}
724
634int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 725int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
635 int cpu, int thread, bool scale) 726 int cpu, int thread, bool scale)
636{ 727{
@@ -646,6 +737,8 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
646 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) 737 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
647 return -errno; 738 return -errno;
648 739
740 compute_deltas(evsel, cpu, &count);
741
649 if (scale) { 742 if (scale) {
650 if (count.run == 0) 743 if (count.run == 0)
651 count.val = 0; 744 count.val = 0;
@@ -684,6 +777,8 @@ int __perf_evsel__read(struct perf_evsel *evsel,
684 } 777 }
685 } 778 }
686 779
780 compute_deltas(evsel, -1, aggr);
781
687 evsel->counts->scaled = 0; 782 evsel->counts->scaled = 0;
688 if (scale) { 783 if (scale) {
689 if (aggr->run == 0) { 784 if (aggr->run == 0) {
@@ -707,7 +802,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
707 struct perf_evsel *leader = evsel->leader; 802 struct perf_evsel *leader = evsel->leader;
708 int fd; 803 int fd;
709 804
710 if (!perf_evsel__is_group_member(evsel)) 805 if (perf_evsel__is_group_leader(evsel))
711 return -1; 806 return -1;
712 807
713 /* 808 /*
@@ -738,6 +833,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
738 pid = evsel->cgrp->fd; 833 pid = evsel->cgrp->fd;
739 } 834 }
740 835
836fallback_missing_features:
837 if (perf_missing_features.exclude_guest)
838 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
839retry_sample_id:
840 if (perf_missing_features.sample_id_all)
841 evsel->attr.sample_id_all = 0;
842
741 for (cpu = 0; cpu < cpus->nr; cpu++) { 843 for (cpu = 0; cpu < cpus->nr; cpu++) {
742 844
743 for (thread = 0; thread < threads->nr; thread++) { 845 for (thread = 0; thread < threads->nr; thread++) {
@@ -754,13 +856,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
754 group_fd, flags); 856 group_fd, flags);
755 if (FD(evsel, cpu, thread) < 0) { 857 if (FD(evsel, cpu, thread) < 0) {
756 err = -errno; 858 err = -errno;
757 goto out_close; 859 goto try_fallback;
758 } 860 }
759 } 861 }
760 } 862 }
761 863
762 return 0; 864 return 0;
763 865
866try_fallback:
867 if (err != -EINVAL || cpu > 0 || thread > 0)
868 goto out_close;
869
870 if (!perf_missing_features.exclude_guest &&
871 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
872 perf_missing_features.exclude_guest = true;
873 goto fallback_missing_features;
874 } else if (!perf_missing_features.sample_id_all) {
875 perf_missing_features.sample_id_all = true;
876 goto retry_sample_id;
877 }
878
764out_close: 879out_close:
765 do { 880 do {
766 while (--thread >= 0) { 881 while (--thread >= 0) {
@@ -908,6 +1023,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
908 data->cpu = data->pid = data->tid = -1; 1023 data->cpu = data->pid = data->tid = -1;
909 data->stream_id = data->id = data->time = -1ULL; 1024 data->stream_id = data->id = data->time = -1ULL;
910 data->period = 1; 1025 data->period = 1;
1026 data->weight = 0;
911 1027
912 if (event->header.type != PERF_RECORD_SAMPLE) { 1028 if (event->header.type != PERF_RECORD_SAMPLE) {
913 if (!evsel->attr.sample_id_all) 1029 if (!evsel->attr.sample_id_all)
@@ -1058,6 +1174,18 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1058 } 1174 }
1059 } 1175 }
1060 1176
1177 data->weight = 0;
1178 if (type & PERF_SAMPLE_WEIGHT) {
1179 data->weight = *array;
1180 array++;
1181 }
1182
1183 data->data_src = PERF_MEM_DATA_SRC_NONE;
1184 if (type & PERF_SAMPLE_DATA_SRC) {
1185 data->data_src = *array;
1186 array++;
1187 }
1188
1061 return 0; 1189 return 0;
1062} 1190}
1063 1191
@@ -1205,3 +1333,225 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
1205 1333
1206 return 0; 1334 return 0;
1207} 1335}
1336
1337static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
1338{
1339 va_list args;
1340 int ret = 0;
1341
1342 if (!*first) {
1343 ret += fprintf(fp, ",");
1344 } else {
1345 ret += fprintf(fp, ":");
1346 *first = false;
1347 }
1348
1349 va_start(args, fmt);
1350 ret += vfprintf(fp, fmt, args);
1351 va_end(args);
1352 return ret;
1353}
1354
1355static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value)
1356{
1357 if (value == 0)
1358 return 0;
1359
1360 return comma_fprintf(fp, first, " %s: %" PRIu64, field, value);
1361}
1362
1363#define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field)
1364
1365struct bit_names {
1366 int bit;
1367 const char *name;
1368};
1369
1370static int bits__fprintf(FILE *fp, const char *field, u64 value,
1371 struct bit_names *bits, bool *first)
1372{
1373 int i = 0, printed = comma_fprintf(fp, first, " %s: ", field);
1374 bool first_bit = true;
1375
1376 do {
1377 if (value & bits[i].bit) {
1378 printed += fprintf(fp, "%s%s", first_bit ? "" : "|", bits[i].name);
1379 first_bit = false;
1380 }
1381 } while (bits[++i].name != NULL);
1382
1383 return printed;
1384}
1385
1386static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
1387{
1388#define bit_name(n) { PERF_SAMPLE_##n, #n }
1389 struct bit_names bits[] = {
1390 bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR),
1391 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
1392 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
1393 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
1394 { .name = NULL, }
1395 };
1396#undef bit_name
1397 return bits__fprintf(fp, "sample_type", value, bits, first);
1398}
1399
1400static int read_format__fprintf(FILE *fp, bool *first, u64 value)
1401{
1402#define bit_name(n) { PERF_FORMAT_##n, #n }
1403 struct bit_names bits[] = {
1404 bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING),
1405 bit_name(ID), bit_name(GROUP),
1406 { .name = NULL, }
1407 };
1408#undef bit_name
1409 return bits__fprintf(fp, "read_format", value, bits, first);
1410}
1411
1412int perf_evsel__fprintf(struct perf_evsel *evsel,
1413 struct perf_attr_details *details, FILE *fp)
1414{
1415 bool first = true;
1416 int printed = 0;
1417
1418 if (details->event_group) {
1419 struct perf_evsel *pos;
1420
1421 if (!perf_evsel__is_group_leader(evsel))
1422 return 0;
1423
1424 if (evsel->nr_members > 1)
1425 printed += fprintf(fp, "%s{", evsel->group_name ?: "");
1426
1427 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
1428 for_each_group_member(pos, evsel)
1429 printed += fprintf(fp, ",%s", perf_evsel__name(pos));
1430
1431 if (evsel->nr_members > 1)
1432 printed += fprintf(fp, "}");
1433 goto out;
1434 }
1435
1436 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
1437
1438 if (details->verbose || details->freq) {
1439 printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64,
1440 (u64)evsel->attr.sample_freq);
1441 }
1442
1443 if (details->verbose) {
1444 if_print(type);
1445 if_print(config);
1446 if_print(config1);
1447 if_print(config2);
1448 if_print(size);
1449 printed += sample_type__fprintf(fp, &first, evsel->attr.sample_type);
1450 if (evsel->attr.read_format)
1451 printed += read_format__fprintf(fp, &first, evsel->attr.read_format);
1452 if_print(disabled);
1453 if_print(inherit);
1454 if_print(pinned);
1455 if_print(exclusive);
1456 if_print(exclude_user);
1457 if_print(exclude_kernel);
1458 if_print(exclude_hv);
1459 if_print(exclude_idle);
1460 if_print(mmap);
1461 if_print(comm);
1462 if_print(freq);
1463 if_print(inherit_stat);
1464 if_print(enable_on_exec);
1465 if_print(task);
1466 if_print(watermark);
1467 if_print(precise_ip);
1468 if_print(mmap_data);
1469 if_print(sample_id_all);
1470 if_print(exclude_host);
1471 if_print(exclude_guest);
1472 if_print(__reserved_1);
1473 if_print(wakeup_events);
1474 if_print(bp_type);
1475 if_print(branch_sample_type);
1476 }
1477out:
1478 fputc('\n', fp);
1479 return ++printed;
1480}
1481
1482bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1483 char *msg, size_t msgsize)
1484{
1485 if ((err == ENOENT || err == ENXIO) &&
1486 evsel->attr.type == PERF_TYPE_HARDWARE &&
1487 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
1488 /*
1489 * If it's cycles then fall back to hrtimer based
1490 * cpu-clock-tick sw counter, which is always available even if
1491 * no PMU support.
1492 *
1493 * PPC returns ENXIO until 2.6.37 (behavior changed with commit
1494 * b0a873e).
1495 */
1496 scnprintf(msg, msgsize, "%s",
1497"The cycles event is not supported, trying to fall back to cpu-clock-ticks");
1498
1499 evsel->attr.type = PERF_TYPE_SOFTWARE;
1500 evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK;
1501
1502 free(evsel->name);
1503 evsel->name = NULL;
1504 return true;
1505 }
1506
1507 return false;
1508}
1509
1510int perf_evsel__open_strerror(struct perf_evsel *evsel,
1511 struct perf_target *target,
1512 int err, char *msg, size_t size)
1513{
1514 switch (err) {
1515 case EPERM:
1516 case EACCES:
1517 return scnprintf(msg, size,
1518 "You may not have permission to collect %sstats.\n"
1519 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
1520 " -1 - Not paranoid at all\n"
1521 " 0 - Disallow raw tracepoint access for unpriv\n"
1522 " 1 - Disallow cpu events for unpriv\n"
1523 " 2 - Disallow kernel profiling for unpriv",
1524 target->system_wide ? "system-wide " : "");
1525 case ENOENT:
1526 return scnprintf(msg, size, "The %s event is not supported.",
1527 perf_evsel__name(evsel));
1528 case EMFILE:
1529 return scnprintf(msg, size, "%s",
1530 "Too many events are opened.\n"
1531 "Try again after reducing the number of events.");
1532 case ENODEV:
1533 if (target->cpu_list)
1534 return scnprintf(msg, size, "%s",
1535 "No such device - did you specify an out-of-range profile CPU?\n");
1536 break;
1537 case EOPNOTSUPP:
1538 if (evsel->attr.precise_ip)
1539 return scnprintf(msg, size, "%s",
1540 "\'precise\' request may not be supported. Try removing 'p' modifier.");
1541#if defined(__i386__) || defined(__x86_64__)
1542 if (evsel->attr.type == PERF_TYPE_HARDWARE)
1543 return scnprintf(msg, size, "%s",
1544 "No hardware sampling interrupt available.\n"
1545 "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
1546#endif
1547 break;
1548 default:
1549 break;
1550 }
1551
1552 return scnprintf(msg, size,
1553 "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n"
1554 "/bin/dmesg may provide additional information.\n"
1555 "No CONFIG_PERF_EVENTS=y kernel support configured?\n",
1556 err, strerror(err), perf_evsel__name(evsel));
1557}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3d2b8017438c..3f156ccc1acb 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -9,6 +9,7 @@
9#include "xyarray.h" 9#include "xyarray.h"
10#include "cgroup.h" 10#include "cgroup.h"
11#include "hist.h" 11#include "hist.h"
12#include "symbol.h"
12 13
13struct perf_counts_values { 14struct perf_counts_values {
14 union { 15 union {
@@ -53,6 +54,7 @@ struct perf_evsel {
53 struct xyarray *sample_id; 54 struct xyarray *sample_id;
54 u64 *id; 55 u64 *id;
55 struct perf_counts *counts; 56 struct perf_counts *counts;
57 struct perf_counts *prev_raw_counts;
56 int idx; 58 int idx;
57 u32 ids; 59 u32 ids;
58 struct hists hists; 60 struct hists hists;
@@ -73,10 +75,13 @@ struct perf_evsel {
73 bool needs_swap; 75 bool needs_swap;
74 /* parse modifier helper */ 76 /* parse modifier helper */
75 int exclude_GH; 77 int exclude_GH;
78 int nr_members;
76 struct perf_evsel *leader; 79 struct perf_evsel *leader;
77 char *group_name; 80 char *group_name;
78}; 81};
79 82
83#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
84
80struct cpu_map; 85struct cpu_map;
81struct thread_map; 86struct thread_map;
82struct perf_evlist; 87struct perf_evlist;
@@ -110,14 +115,31 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
110int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, 115int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
111 char *bf, size_t size); 116 char *bf, size_t size);
112const char *perf_evsel__name(struct perf_evsel *evsel); 117const char *perf_evsel__name(struct perf_evsel *evsel);
118const char *perf_evsel__group_name(struct perf_evsel *evsel);
119int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
113 120
114int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 121int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
115int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 122int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
116int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 123int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
124void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus);
117void perf_evsel__free_fd(struct perf_evsel *evsel); 125void perf_evsel__free_fd(struct perf_evsel *evsel);
118void perf_evsel__free_id(struct perf_evsel *evsel); 126void perf_evsel__free_id(struct perf_evsel *evsel);
127void perf_evsel__free_counts(struct perf_evsel *evsel);
119void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 128void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
120 129
130void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
131 enum perf_event_sample_format bit);
132void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
133 enum perf_event_sample_format bit);
134
135#define perf_evsel__set_sample_bit(evsel, bit) \
136 __perf_evsel__set_sample_bit(evsel, PERF_SAMPLE_##bit)
137
138#define perf_evsel__reset_sample_bit(evsel, bit) \
139 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
140
141void perf_evsel__set_sample_id(struct perf_evsel *evsel);
142
121int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 143int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
122 const char *filter); 144 const char *filter);
123 145
@@ -226,8 +248,57 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
226 return list_entry(evsel->node.next, struct perf_evsel, node); 248 return list_entry(evsel->node.next, struct perf_evsel, node);
227} 249}
228 250
229static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel) 251/**
252 * perf_evsel__is_group_leader - Return whether given evsel is a leader event
253 *
254 * @evsel - evsel selector to be tested
255 *
256 * Return %true if @evsel is a group leader or a stand-alone event
257 */
258static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel)
259{
260 return evsel->leader == evsel;
261}
262
263/**
264 * perf_evsel__is_group_event - Return whether given evsel is a group event
265 *
266 * @evsel - evsel selector to be tested
267 *
268 * Return %true iff event group view is enabled and @evsel is a actual group
269 * leader which has other members in the group
270 */
271static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel)
272{
273 if (!symbol_conf.event_group)
274 return false;
275
276 return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1;
277}
278
279struct perf_attr_details {
280 bool freq;
281 bool verbose;
282 bool event_group;
283};
284
285int perf_evsel__fprintf(struct perf_evsel *evsel,
286 struct perf_attr_details *details, FILE *fp);
287
288bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
289 char *msg, size_t msgsize);
290int perf_evsel__open_strerror(struct perf_evsel *evsel,
291 struct perf_target *target,
292 int err, char *msg, size_t size);
293
294static inline int perf_evsel__group_idx(struct perf_evsel *evsel)
230{ 295{
231 return evsel->leader != NULL; 296 return evsel->idx - evsel->leader->idx;
232} 297}
298
299#define for_each_group_member(_evsel, _leader) \
300for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \
301 (_evsel) && (_evsel)->leader == (_leader); \
302 (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
303
233#endif /* __PERF_EVSEL_H */ 304#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b7da4634a047..738d3b8d9745 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,5 +1,3 @@
1#define _FILE_OFFSET_BITS 64
2
3#include "util.h" 1#include "util.h"
4#include <sys/types.h> 2#include <sys/types.h>
5#include <byteswap.h> 3#include <byteswap.h>
@@ -148,7 +146,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
148 u32 len; 146 u32 len;
149 char *buf; 147 char *buf;
150 148
151 sz = read(fd, &len, sizeof(len)); 149 sz = readn(fd, &len, sizeof(len));
152 if (sz < (ssize_t)sizeof(len)) 150 if (sz < (ssize_t)sizeof(len))
153 return NULL; 151 return NULL;
154 152
@@ -159,7 +157,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
159 if (!buf) 157 if (!buf)
160 return NULL; 158 return NULL;
161 159
162 ret = read(fd, buf, len); 160 ret = readn(fd, buf, len);
163 if (ret == (ssize_t)len) { 161 if (ret == (ssize_t)len) {
164 /* 162 /*
165 * strings are padded by zeroes 163 * strings are padded by zeroes
@@ -287,12 +285,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
287 struct perf_session *session = container_of(header, 285 struct perf_session *session = container_of(header,
288 struct perf_session, header); 286 struct perf_session, header);
289 struct rb_node *nd; 287 struct rb_node *nd;
290 int err = machine__write_buildid_table(&session->host_machine, fd); 288 int err = machine__write_buildid_table(&session->machines.host, fd);
291 289
292 if (err) 290 if (err)
293 return err; 291 return err;
294 292
295 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 293 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
296 struct machine *pos = rb_entry(nd, struct machine, rb_node); 294 struct machine *pos = rb_entry(nd, struct machine, rb_node);
297 err = machine__write_buildid_table(pos, fd); 295 err = machine__write_buildid_table(pos, fd);
298 if (err) 296 if (err)
@@ -313,7 +311,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
313 if (is_kallsyms) { 311 if (is_kallsyms) {
314 if (symbol_conf.kptr_restrict) { 312 if (symbol_conf.kptr_restrict) {
315 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); 313 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
316 return 0; 314 err = 0;
315 goto out_free;
317 } 316 }
318 realname = (char *) name; 317 realname = (char *) name;
319 } else 318 } else
@@ -448,9 +447,9 @@ static int perf_session__cache_build_ids(struct perf_session *session)
448 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 447 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
449 return -1; 448 return -1;
450 449
451 ret = machine__cache_build_ids(&session->host_machine, debugdir); 450 ret = machine__cache_build_ids(&session->machines.host, debugdir);
452 451
453 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 452 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
454 struct machine *pos = rb_entry(nd, struct machine, rb_node); 453 struct machine *pos = rb_entry(nd, struct machine, rb_node);
455 ret |= machine__cache_build_ids(pos, debugdir); 454 ret |= machine__cache_build_ids(pos, debugdir);
456 } 455 }
@@ -467,9 +466,9 @@ static bool machine__read_build_ids(struct machine *machine, bool with_hits)
467static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) 466static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
468{ 467{
469 struct rb_node *nd; 468 struct rb_node *nd;
470 bool ret = machine__read_build_ids(&session->host_machine, with_hits); 469 bool ret = machine__read_build_ids(&session->machines.host, with_hits);
471 470
472 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 471 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
473 struct machine *pos = rb_entry(nd, struct machine, rb_node); 472 struct machine *pos = rb_entry(nd, struct machine, rb_node);
474 ret |= machine__read_build_ids(pos, with_hits); 473 ret |= machine__read_build_ids(pos, with_hits);
475 } 474 }
@@ -954,6 +953,7 @@ static int write_topo_node(int fd, int node)
954 } 953 }
955 954
956 fclose(fp); 955 fclose(fp);
956 fp = NULL;
957 957
958 ret = do_write(fd, &mem_total, sizeof(u64)); 958 ret = do_write(fd, &mem_total, sizeof(u64));
959 if (ret) 959 if (ret)
@@ -980,7 +980,8 @@ static int write_topo_node(int fd, int node)
980 ret = do_write_string(fd, buf); 980 ret = do_write_string(fd, buf);
981done: 981done:
982 free(buf); 982 free(buf);
983 fclose(fp); 983 if (fp)
984 fclose(fp);
984 return ret; 985 return ret;
985} 986}
986 987
@@ -1051,16 +1052,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1051 struct perf_pmu *pmu = NULL; 1052 struct perf_pmu *pmu = NULL;
1052 off_t offset = lseek(fd, 0, SEEK_CUR); 1053 off_t offset = lseek(fd, 0, SEEK_CUR);
1053 __u32 pmu_num = 0; 1054 __u32 pmu_num = 0;
1055 int ret;
1054 1056
1055 /* write real pmu_num later */ 1057 /* write real pmu_num later */
1056 do_write(fd, &pmu_num, sizeof(pmu_num)); 1058 ret = do_write(fd, &pmu_num, sizeof(pmu_num));
1059 if (ret < 0)
1060 return ret;
1057 1061
1058 while ((pmu = perf_pmu__scan(pmu))) { 1062 while ((pmu = perf_pmu__scan(pmu))) {
1059 if (!pmu->name) 1063 if (!pmu->name)
1060 continue; 1064 continue;
1061 pmu_num++; 1065 pmu_num++;
1062 do_write(fd, &pmu->type, sizeof(pmu->type)); 1066
1063 do_write_string(fd, pmu->name); 1067 ret = do_write(fd, &pmu->type, sizeof(pmu->type));
1068 if (ret < 0)
1069 return ret;
1070
1071 ret = do_write_string(fd, pmu->name);
1072 if (ret < 0)
1073 return ret;
1064 } 1074 }
1065 1075
1066 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { 1076 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
@@ -1073,6 +1083,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1073} 1083}
1074 1084
1075/* 1085/*
1086 * File format:
1087 *
1088 * struct group_descs {
1089 * u32 nr_groups;
1090 * struct group_desc {
1091 * char name[];
1092 * u32 leader_idx;
1093 * u32 nr_members;
1094 * }[nr_groups];
1095 * };
1096 */
1097static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
1098 struct perf_evlist *evlist)
1099{
1100 u32 nr_groups = evlist->nr_groups;
1101 struct perf_evsel *evsel;
1102 int ret;
1103
1104 ret = do_write(fd, &nr_groups, sizeof(nr_groups));
1105 if (ret < 0)
1106 return ret;
1107
1108 list_for_each_entry(evsel, &evlist->entries, node) {
1109 if (perf_evsel__is_group_leader(evsel) &&
1110 evsel->nr_members > 1) {
1111 const char *name = evsel->group_name ?: "{anon_group}";
1112 u32 leader_idx = evsel->idx;
1113 u32 nr_members = evsel->nr_members;
1114
1115 ret = do_write_string(fd, name);
1116 if (ret < 0)
1117 return ret;
1118
1119 ret = do_write(fd, &leader_idx, sizeof(leader_idx));
1120 if (ret < 0)
1121 return ret;
1122
1123 ret = do_write(fd, &nr_members, sizeof(nr_members));
1124 if (ret < 0)
1125 return ret;
1126 }
1127 }
1128 return 0;
1129}
1130
1131/*
1076 * default get_cpuid(): nothing gets recorded 1132 * default get_cpuid(): nothing gets recorded
1077 * actual implementation must be in arch/$(ARCH)/util/header.c 1133 * actual implementation must be in arch/$(ARCH)/util/header.c
1078 */ 1134 */
@@ -1209,14 +1265,14 @@ read_event_desc(struct perf_header *ph, int fd)
1209 size_t msz; 1265 size_t msz;
1210 1266
1211 /* number of events */ 1267 /* number of events */
1212 ret = read(fd, &nre, sizeof(nre)); 1268 ret = readn(fd, &nre, sizeof(nre));
1213 if (ret != (ssize_t)sizeof(nre)) 1269 if (ret != (ssize_t)sizeof(nre))
1214 goto error; 1270 goto error;
1215 1271
1216 if (ph->needs_swap) 1272 if (ph->needs_swap)
1217 nre = bswap_32(nre); 1273 nre = bswap_32(nre);
1218 1274
1219 ret = read(fd, &sz, sizeof(sz)); 1275 ret = readn(fd, &sz, sizeof(sz));
1220 if (ret != (ssize_t)sizeof(sz)) 1276 if (ret != (ssize_t)sizeof(sz))
1221 goto error; 1277 goto error;
1222 1278
@@ -1244,7 +1300,7 @@ read_event_desc(struct perf_header *ph, int fd)
1244 * must read entire on-file attr struct to 1300 * must read entire on-file attr struct to
1245 * sync up with layout. 1301 * sync up with layout.
1246 */ 1302 */
1247 ret = read(fd, buf, sz); 1303 ret = readn(fd, buf, sz);
1248 if (ret != (ssize_t)sz) 1304 if (ret != (ssize_t)sz)
1249 goto error; 1305 goto error;
1250 1306
@@ -1253,7 +1309,7 @@ read_event_desc(struct perf_header *ph, int fd)
1253 1309
1254 memcpy(&evsel->attr, buf, msz); 1310 memcpy(&evsel->attr, buf, msz);
1255 1311
1256 ret = read(fd, &nr, sizeof(nr)); 1312 ret = readn(fd, &nr, sizeof(nr));
1257 if (ret != (ssize_t)sizeof(nr)) 1313 if (ret != (ssize_t)sizeof(nr))
1258 goto error; 1314 goto error;
1259 1315
@@ -1274,7 +1330,7 @@ read_event_desc(struct perf_header *ph, int fd)
1274 evsel->id = id; 1330 evsel->id = id;
1275 1331
1276 for (j = 0 ; j < nr; j++) { 1332 for (j = 0 ; j < nr; j++) {
1277 ret = read(fd, id, sizeof(*id)); 1333 ret = readn(fd, id, sizeof(*id));
1278 if (ret != (ssize_t)sizeof(*id)) 1334 if (ret != (ssize_t)sizeof(*id))
1279 goto error; 1335 goto error;
1280 if (ph->needs_swap) 1336 if (ph->needs_swap)
@@ -1435,6 +1491,31 @@ error:
1435 fprintf(fp, "# pmu mappings: unable to read\n"); 1491 fprintf(fp, "# pmu mappings: unable to read\n");
1436} 1492}
1437 1493
1494static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
1495 FILE *fp)
1496{
1497 struct perf_session *session;
1498 struct perf_evsel *evsel;
1499 u32 nr = 0;
1500
1501 session = container_of(ph, struct perf_session, header);
1502
1503 list_for_each_entry(evsel, &session->evlist->entries, node) {
1504 if (perf_evsel__is_group_leader(evsel) &&
1505 evsel->nr_members > 1) {
1506 fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
1507 perf_evsel__name(evsel));
1508
1509 nr = evsel->nr_members - 1;
1510 } else if (nr) {
1511 fprintf(fp, ",%s", perf_evsel__name(evsel));
1512
1513 if (--nr == 0)
1514 fprintf(fp, "}\n");
1515 }
1516 }
1517}
1518
1438static int __event_process_build_id(struct build_id_event *bev, 1519static int __event_process_build_id(struct build_id_event *bev,
1439 char *filename, 1520 char *filename,
1440 struct perf_session *session) 1521 struct perf_session *session)
@@ -1506,14 +1587,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1506 while (offset < limit) { 1587 while (offset < limit) {
1507 ssize_t len; 1588 ssize_t len;
1508 1589
1509 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) 1590 if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
1510 return -1; 1591 return -1;
1511 1592
1512 if (header->needs_swap) 1593 if (header->needs_swap)
1513 perf_event_header__bswap(&old_bev.header); 1594 perf_event_header__bswap(&old_bev.header);
1514 1595
1515 len = old_bev.header.size - sizeof(old_bev); 1596 len = old_bev.header.size - sizeof(old_bev);
1516 if (read(input, filename, len) != len) 1597 if (readn(input, filename, len) != len)
1517 return -1; 1598 return -1;
1518 1599
1519 bev.header = old_bev.header; 1600 bev.header = old_bev.header;
@@ -1548,14 +1629,14 @@ static int perf_header__read_build_ids(struct perf_header *header,
1548 while (offset < limit) { 1629 while (offset < limit) {
1549 ssize_t len; 1630 ssize_t len;
1550 1631
1551 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 1632 if (readn(input, &bev, sizeof(bev)) != sizeof(bev))
1552 goto out; 1633 goto out;
1553 1634
1554 if (header->needs_swap) 1635 if (header->needs_swap)
1555 perf_event_header__bswap(&bev.header); 1636 perf_event_header__bswap(&bev.header);
1556 1637
1557 len = bev.header.size - sizeof(bev); 1638 len = bev.header.size - sizeof(bev);
1558 if (read(input, filename, len) != len) 1639 if (readn(input, filename, len) != len)
1559 goto out; 1640 goto out;
1560 /* 1641 /*
1561 * The a1645ce1 changeset: 1642 * The a1645ce1 changeset:
@@ -1589,8 +1670,8 @@ static int process_tracing_data(struct perf_file_section *section __maybe_unused
1589 struct perf_header *ph __maybe_unused, 1670 struct perf_header *ph __maybe_unused,
1590 int fd, void *data) 1671 int fd, void *data)
1591{ 1672{
1592 trace_report(fd, data, false); 1673 ssize_t ret = trace_report(fd, data, false);
1593 return 0; 1674 return ret < 0 ? -1 : 0;
1594} 1675}
1595 1676
1596static int process_build_id(struct perf_file_section *section, 1677static int process_build_id(struct perf_file_section *section,
@@ -1641,7 +1722,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1641 size_t ret; 1722 size_t ret;
1642 u32 nr; 1723 u32 nr;
1643 1724
1644 ret = read(fd, &nr, sizeof(nr)); 1725 ret = readn(fd, &nr, sizeof(nr));
1645 if (ret != sizeof(nr)) 1726 if (ret != sizeof(nr))
1646 return -1; 1727 return -1;
1647 1728
@@ -1650,7 +1731,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1650 1731
1651 ph->env.nr_cpus_online = nr; 1732 ph->env.nr_cpus_online = nr;
1652 1733
1653 ret = read(fd, &nr, sizeof(nr)); 1734 ret = readn(fd, &nr, sizeof(nr));
1654 if (ret != sizeof(nr)) 1735 if (ret != sizeof(nr))
1655 return -1; 1736 return -1;
1656 1737
@@ -1684,7 +1765,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
1684 uint64_t mem; 1765 uint64_t mem;
1685 size_t ret; 1766 size_t ret;
1686 1767
1687 ret = read(fd, &mem, sizeof(mem)); 1768 ret = readn(fd, &mem, sizeof(mem));
1688 if (ret != sizeof(mem)) 1769 if (ret != sizeof(mem))
1689 return -1; 1770 return -1;
1690 1771
@@ -1756,7 +1837,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
1756 u32 nr, i; 1837 u32 nr, i;
1757 struct strbuf sb; 1838 struct strbuf sb;
1758 1839
1759 ret = read(fd, &nr, sizeof(nr)); 1840 ret = readn(fd, &nr, sizeof(nr));
1760 if (ret != sizeof(nr)) 1841 if (ret != sizeof(nr))
1761 return -1; 1842 return -1;
1762 1843
@@ -1792,7 +1873,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1792 char *str; 1873 char *str;
1793 struct strbuf sb; 1874 struct strbuf sb;
1794 1875
1795 ret = read(fd, &nr, sizeof(nr)); 1876 ret = readn(fd, &nr, sizeof(nr));
1796 if (ret != sizeof(nr)) 1877 if (ret != sizeof(nr))
1797 return -1; 1878 return -1;
1798 1879
@@ -1813,7 +1894,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1813 } 1894 }
1814 ph->env.sibling_cores = strbuf_detach(&sb, NULL); 1895 ph->env.sibling_cores = strbuf_detach(&sb, NULL);
1815 1896
1816 ret = read(fd, &nr, sizeof(nr)); 1897 ret = readn(fd, &nr, sizeof(nr));
1817 if (ret != sizeof(nr)) 1898 if (ret != sizeof(nr))
1818 return -1; 1899 return -1;
1819 1900
@@ -1850,7 +1931,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1850 struct strbuf sb; 1931 struct strbuf sb;
1851 1932
1852 /* nr nodes */ 1933 /* nr nodes */
1853 ret = read(fd, &nr, sizeof(nr)); 1934 ret = readn(fd, &nr, sizeof(nr));
1854 if (ret != sizeof(nr)) 1935 if (ret != sizeof(nr))
1855 goto error; 1936 goto error;
1856 1937
@@ -1862,15 +1943,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1862 1943
1863 for (i = 0; i < nr; i++) { 1944 for (i = 0; i < nr; i++) {
1864 /* node number */ 1945 /* node number */
1865 ret = read(fd, &node, sizeof(node)); 1946 ret = readn(fd, &node, sizeof(node));
1866 if (ret != sizeof(node)) 1947 if (ret != sizeof(node))
1867 goto error; 1948 goto error;
1868 1949
1869 ret = read(fd, &mem_total, sizeof(u64)); 1950 ret = readn(fd, &mem_total, sizeof(u64));
1870 if (ret != sizeof(u64)) 1951 if (ret != sizeof(u64))
1871 goto error; 1952 goto error;
1872 1953
1873 ret = read(fd, &mem_free, sizeof(u64)); 1954 ret = readn(fd, &mem_free, sizeof(u64));
1874 if (ret != sizeof(u64)) 1955 if (ret != sizeof(u64))
1875 goto error; 1956 goto error;
1876 1957
@@ -1909,7 +1990,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1909 u32 type; 1990 u32 type;
1910 struct strbuf sb; 1991 struct strbuf sb;
1911 1992
1912 ret = read(fd, &pmu_num, sizeof(pmu_num)); 1993 ret = readn(fd, &pmu_num, sizeof(pmu_num));
1913 if (ret != sizeof(pmu_num)) 1994 if (ret != sizeof(pmu_num))
1914 return -1; 1995 return -1;
1915 1996
@@ -1925,7 +2006,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1925 strbuf_init(&sb, 128); 2006 strbuf_init(&sb, 128);
1926 2007
1927 while (pmu_num) { 2008 while (pmu_num) {
1928 if (read(fd, &type, sizeof(type)) != sizeof(type)) 2009 if (readn(fd, &type, sizeof(type)) != sizeof(type))
1929 goto error; 2010 goto error;
1930 if (ph->needs_swap) 2011 if (ph->needs_swap)
1931 type = bswap_32(type); 2012 type = bswap_32(type);
@@ -1949,6 +2030,98 @@ error:
1949 return -1; 2030 return -1;
1950} 2031}
1951 2032
2033static int process_group_desc(struct perf_file_section *section __maybe_unused,
2034 struct perf_header *ph, int fd,
2035 void *data __maybe_unused)
2036{
2037 size_t ret = -1;
2038 u32 i, nr, nr_groups;
2039 struct perf_session *session;
2040 struct perf_evsel *evsel, *leader = NULL;
2041 struct group_desc {
2042 char *name;
2043 u32 leader_idx;
2044 u32 nr_members;
2045 } *desc;
2046
2047 if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups))
2048 return -1;
2049
2050 if (ph->needs_swap)
2051 nr_groups = bswap_32(nr_groups);
2052
2053 ph->env.nr_groups = nr_groups;
2054 if (!nr_groups) {
2055 pr_debug("group desc not available\n");
2056 return 0;
2057 }
2058
2059 desc = calloc(nr_groups, sizeof(*desc));
2060 if (!desc)
2061 return -1;
2062
2063 for (i = 0; i < nr_groups; i++) {
2064 desc[i].name = do_read_string(fd, ph);
2065 if (!desc[i].name)
2066 goto out_free;
2067
2068 if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32))
2069 goto out_free;
2070
2071 if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32))
2072 goto out_free;
2073
2074 if (ph->needs_swap) {
2075 desc[i].leader_idx = bswap_32(desc[i].leader_idx);
2076 desc[i].nr_members = bswap_32(desc[i].nr_members);
2077 }
2078 }
2079
2080 /*
2081 * Rebuild group relationship based on the group_desc
2082 */
2083 session = container_of(ph, struct perf_session, header);
2084 session->evlist->nr_groups = nr_groups;
2085
2086 i = nr = 0;
2087 list_for_each_entry(evsel, &session->evlist->entries, node) {
2088 if (evsel->idx == (int) desc[i].leader_idx) {
2089 evsel->leader = evsel;
2090 /* {anon_group} is a dummy name */
2091 if (strcmp(desc[i].name, "{anon_group}"))
2092 evsel->group_name = desc[i].name;
2093 evsel->nr_members = desc[i].nr_members;
2094
2095 if (i >= nr_groups || nr > 0) {
2096 pr_debug("invalid group desc\n");
2097 goto out_free;
2098 }
2099
2100 leader = evsel;
2101 nr = evsel->nr_members - 1;
2102 i++;
2103 } else if (nr) {
2104 /* This is a group member */
2105 evsel->leader = leader;
2106
2107 nr--;
2108 }
2109 }
2110
2111 if (i != nr_groups || nr != 0) {
2112 pr_debug("invalid group desc\n");
2113 goto out_free;
2114 }
2115
2116 ret = 0;
2117out_free:
2118 while ((int) --i >= 0)
2119 free(desc[i].name);
2120 free(desc);
2121
2122 return ret;
2123}
2124
1952struct feature_ops { 2125struct feature_ops {
1953 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 2126 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1954 void (*print)(struct perf_header *h, int fd, FILE *fp); 2127 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1988,6 +2161,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1988 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), 2161 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
1989 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), 2162 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
1990 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), 2163 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
2164 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1991}; 2165};
1992 2166
1993struct header_print_data { 2167struct header_print_data {
@@ -2077,7 +2251,7 @@ static int perf_header__adds_write(struct perf_header *header,
2077 if (!nr_sections) 2251 if (!nr_sections)
2078 return 0; 2252 return 0;
2079 2253
2080 feat_sec = p = calloc(sizeof(*feat_sec), nr_sections); 2254 feat_sec = p = calloc(nr_sections, sizeof(*feat_sec));
2081 if (feat_sec == NULL) 2255 if (feat_sec == NULL)
2082 return -ENOMEM; 2256 return -ENOMEM;
2083 2257
@@ -2217,7 +2391,6 @@ out_err_write:
2217 } 2391 }
2218 lseek(fd, header->data_offset + header->data_size, SEEK_SET); 2392 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
2219 2393
2220 header->frozen = 1;
2221 return 0; 2394 return 0;
2222} 2395}
2223 2396
@@ -2249,7 +2422,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
2249 if (!nr_sections) 2422 if (!nr_sections)
2250 return 0; 2423 return 0;
2251 2424
2252 feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); 2425 feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec));
2253 if (!feat_sec) 2426 if (!feat_sec)
2254 return -1; 2427 return -1;
2255 2428
@@ -2576,6 +2749,11 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
2576 if (evsel->tp_format) 2749 if (evsel->tp_format)
2577 return 0; 2750 return 0;
2578 2751
2752 if (pevent == NULL) {
2753 pr_debug("broken or missing trace data\n");
2754 return -1;
2755 }
2756
2579 event = pevent_find_event(pevent, evsel->attr.config); 2757 event = pevent_find_event(pevent, evsel->attr.config);
2580 if (event == NULL) 2758 if (event == NULL)
2581 return -1; 2759 return -1;
@@ -2613,7 +2791,7 @@ int perf_session__read_header(struct perf_session *session, int fd)
2613 u64 f_id; 2791 u64 f_id;
2614 int nr_attrs, nr_ids, i, j; 2792 int nr_attrs, nr_ids, i, j;
2615 2793
2616 session->evlist = perf_evlist__new(NULL, NULL); 2794 session->evlist = perf_evlist__new();
2617 if (session->evlist == NULL) 2795 if (session->evlist == NULL)
2618 return -ENOMEM; 2796 return -ENOMEM;
2619 2797
@@ -2692,7 +2870,6 @@ int perf_session__read_header(struct perf_session *session, int fd)
2692 session->pevent)) 2870 session->pevent))
2693 goto out_delete_evlist; 2871 goto out_delete_evlist;
2694 2872
2695 header->frozen = 1;
2696 return 0; 2873 return 0;
2697out_errno: 2874out_errno:
2698 return -errno; 2875 return -errno;
@@ -2764,7 +2941,7 @@ int perf_event__process_attr(union perf_event *event,
2764 struct perf_evlist *evlist = *pevlist; 2941 struct perf_evlist *evlist = *pevlist;
2765 2942
2766 if (evlist == NULL) { 2943 if (evlist == NULL) {
2767 *pevlist = evlist = perf_evlist__new(NULL, NULL); 2944 *pevlist = evlist = perf_evlist__new();
2768 if (evlist == NULL) 2945 if (evlist == NULL)
2769 return -ENOMEM; 2946 return -ENOMEM;
2770 } 2947 }
@@ -2912,16 +3089,22 @@ int perf_event__process_tracing_data(union perf_event *event,
2912 session->repipe); 3089 session->repipe);
2913 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 3090 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
2914 3091
2915 if (read(session->fd, buf, padding) < 0) 3092 if (readn(session->fd, buf, padding) < 0) {
2916 die("reading input file"); 3093 pr_err("%s: reading input file", __func__);
3094 return -1;
3095 }
2917 if (session->repipe) { 3096 if (session->repipe) {
2918 int retw = write(STDOUT_FILENO, buf, padding); 3097 int retw = write(STDOUT_FILENO, buf, padding);
2919 if (retw <= 0 || retw != padding) 3098 if (retw <= 0 || retw != padding) {
2920 die("repiping tracing data padding"); 3099 pr_err("%s: repiping tracing data padding", __func__);
3100 return -1;
3101 }
2921 } 3102 }
2922 3103
2923 if (size_read + padding != size) 3104 if (size_read + padding != size) {
2924 die("tracing data size mismatch"); 3105 pr_err("%s: tracing data size mismatch", __func__);
3106 return -1;
3107 }
2925 3108
2926 perf_evlist__prepare_tracepoint_events(session->evlist, 3109 perf_evlist__prepare_tracepoint_events(session->evlist,
2927 session->pevent); 3110 session->pevent);
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 20f0344accb1..16a3e83c584e 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -29,6 +29,7 @@ enum {
29 HEADER_NUMA_TOPOLOGY, 29 HEADER_NUMA_TOPOLOGY,
30 HEADER_BRANCH_STACK, 30 HEADER_BRANCH_STACK,
31 HEADER_PMU_MAPPINGS, 31 HEADER_PMU_MAPPINGS,
32 HEADER_GROUP_DESC,
32 HEADER_LAST_FEATURE, 33 HEADER_LAST_FEATURE,
33 HEADER_FEAT_BITS = 256, 34 HEADER_FEAT_BITS = 256,
34}; 35};
@@ -79,10 +80,10 @@ struct perf_session_env {
79 char *numa_nodes; 80 char *numa_nodes;
80 int nr_pmu_mappings; 81 int nr_pmu_mappings;
81 char *pmu_mappings; 82 char *pmu_mappings;
83 int nr_groups;
82}; 84};
83 85
84struct perf_header { 86struct perf_header {
85 int frozen;
86 bool needs_swap; 87 bool needs_swap;
87 s64 attr_offset; 88 s64 attr_offset;
88 u64 data_offset; 89 u64 data_offset;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index cb17e2a8c6ed..b11a6cfdb414 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
4#include "hist.h" 4#include "hist.h"
5#include "session.h" 5#include "session.h"
6#include "sort.h" 6#include "sort.h"
7#include "evsel.h"
7#include <math.h> 8#include <math.h>
8 9
9static bool hists__filter_entry_by_dso(struct hists *hists, 10static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -66,12 +67,24 @@ static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
66void hists__calc_col_len(struct hists *hists, struct hist_entry *h) 67void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
67{ 68{
68 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 69 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
70 int symlen;
69 u16 len; 71 u16 len;
70 72
71 if (h->ms.sym) 73 /*
72 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); 74 * +4 accounts for '[x] ' priv level info
73 else 75 * +2 accounts for 0x prefix on raw addresses
76 * +3 accounts for ' y ' symtab origin info
77 */
78 if (h->ms.sym) {
79 symlen = h->ms.sym->namelen + 4;
80 if (verbose)
81 symlen += BITS_PER_LONG / 4 + 2 + 3;
82 hists__new_col_len(hists, HISTC_SYMBOL, symlen);
83 } else {
84 symlen = unresolved_col_width + 4 + 2;
85 hists__new_col_len(hists, HISTC_SYMBOL, symlen);
74 hists__set_unres_dso_col_len(hists, HISTC_DSO); 86 hists__set_unres_dso_col_len(hists, HISTC_DSO);
87 }
75 88
76 len = thread__comm_len(h->thread); 89 len = thread__comm_len(h->thread);
77 if (hists__new_col_len(hists, HISTC_COMM, len)) 90 if (hists__new_col_len(hists, HISTC_COMM, len))
@@ -82,14 +95,14 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
82 hists__new_col_len(hists, HISTC_DSO, len); 95 hists__new_col_len(hists, HISTC_DSO, len);
83 } 96 }
84 97
98 if (h->parent)
99 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
100
85 if (h->branch_info) { 101 if (h->branch_info) {
86 int symlen;
87 /*
88 * +4 accounts for '[x] ' priv level info
89 * +2 account of 0x prefix on raw addresses
90 */
91 if (h->branch_info->from.sym) { 102 if (h->branch_info->from.sym) {
92 symlen = (int)h->branch_info->from.sym->namelen + 4; 103 symlen = (int)h->branch_info->from.sym->namelen + 4;
104 if (verbose)
105 symlen += BITS_PER_LONG / 4 + 2 + 3;
93 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen); 106 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
94 107
95 symlen = dso__name_len(h->branch_info->from.map->dso); 108 symlen = dso__name_len(h->branch_info->from.map->dso);
@@ -102,6 +115,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
102 115
103 if (h->branch_info->to.sym) { 116 if (h->branch_info->to.sym) {
104 symlen = (int)h->branch_info->to.sym->namelen + 4; 117 symlen = (int)h->branch_info->to.sym->namelen + 4;
118 if (verbose)
119 symlen += BITS_PER_LONG / 4 + 2 + 3;
105 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); 120 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
106 121
107 symlen = dso__name_len(h->branch_info->to.map->dso); 122 symlen = dso__name_len(h->branch_info->to.map->dso);
@@ -112,6 +127,38 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
112 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); 127 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
113 } 128 }
114 } 129 }
130
131 if (h->mem_info) {
132 if (h->mem_info->daddr.sym) {
133 symlen = (int)h->mem_info->daddr.sym->namelen + 4
134 + unresolved_col_width + 2;
135 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
136 symlen);
137 } else {
138 symlen = unresolved_col_width + 4 + 2;
139 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
140 symlen);
141 }
142 if (h->mem_info->daddr.map) {
143 symlen = dso__name_len(h->mem_info->daddr.map->dso);
144 hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
145 symlen);
146 } else {
147 symlen = unresolved_col_width + 4 + 2;
148 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
149 }
150 } else {
151 symlen = unresolved_col_width + 4 + 2;
152 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
153 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
154 }
155
156 hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
157 hists__new_col_len(hists, HISTC_MEM_TLB, 22);
158 hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
159 hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
160 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
161 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
115} 162}
116 163
117void hists__output_recalc_col_len(struct hists *hists, int max_rows) 164void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -151,9 +198,12 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
151 } 198 }
152} 199}
153 200
154static void he_stat__add_period(struct he_stat *he_stat, u64 period) 201static void he_stat__add_period(struct he_stat *he_stat, u64 period,
202 u64 weight)
155{ 203{
204
156 he_stat->period += period; 205 he_stat->period += period;
206 he_stat->weight += weight;
157 he_stat->nr_events += 1; 207 he_stat->nr_events += 1;
158} 208}
159 209
@@ -165,12 +215,14 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
165 dest->period_guest_sys += src->period_guest_sys; 215 dest->period_guest_sys += src->period_guest_sys;
166 dest->period_guest_us += src->period_guest_us; 216 dest->period_guest_us += src->period_guest_us;
167 dest->nr_events += src->nr_events; 217 dest->nr_events += src->nr_events;
218 dest->weight += src->weight;
168} 219}
169 220
170static void hist_entry__decay(struct hist_entry *he) 221static void hist_entry__decay(struct hist_entry *he)
171{ 222{
172 he->stat.period = (he->stat.period * 7) / 8; 223 he->stat.period = (he->stat.period * 7) / 8;
173 he->stat.nr_events = (he->stat.nr_events * 7) / 8; 224 he->stat.nr_events = (he->stat.nr_events * 7) / 8;
225 /* XXX need decay for weight too? */
174} 226}
175 227
176static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 228static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
@@ -188,8 +240,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
188 return he->stat.period == 0; 240 return he->stat.period == 0;
189} 241}
190 242
191static void __hists__decay_entries(struct hists *hists, bool zap_user, 243void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
192 bool zap_kernel, bool threaded)
193{ 244{
194 struct rb_node *next = rb_first(&hists->entries); 245 struct rb_node *next = rb_first(&hists->entries);
195 struct hist_entry *n; 246 struct hist_entry *n;
@@ -208,7 +259,7 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
208 !n->used) { 259 !n->used) {
209 rb_erase(&n->rb_node, &hists->entries); 260 rb_erase(&n->rb_node, &hists->entries);
210 261
211 if (sort__need_collapse || threaded) 262 if (sort__need_collapse)
212 rb_erase(&n->rb_node_in, &hists->entries_collapsed); 263 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
213 264
214 hist_entry__free(n); 265 hist_entry__free(n);
@@ -217,17 +268,6 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
217 } 268 }
218} 269}
219 270
220void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
221{
222 return __hists__decay_entries(hists, zap_user, zap_kernel, false);
223}
224
225void hists__decay_entries_threaded(struct hists *hists,
226 bool zap_user, bool zap_kernel)
227{
228 return __hists__decay_entries(hists, zap_user, zap_kernel, true);
229}
230
231/* 271/*
232 * histogram, sorted on item, collects periods 272 * histogram, sorted on item, collects periods
233 */ 273 */
@@ -235,13 +275,42 @@ void hists__decay_entries_threaded(struct hists *hists,
235static struct hist_entry *hist_entry__new(struct hist_entry *template) 275static struct hist_entry *hist_entry__new(struct hist_entry *template)
236{ 276{
237 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 277 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
238 struct hist_entry *he = malloc(sizeof(*he) + callchain_size); 278 struct hist_entry *he = zalloc(sizeof(*he) + callchain_size);
239 279
240 if (he != NULL) { 280 if (he != NULL) {
241 *he = *template; 281 *he = *template;
242 282
243 if (he->ms.map) 283 if (he->ms.map)
244 he->ms.map->referenced = true; 284 he->ms.map->referenced = true;
285
286 if (he->branch_info) {
287 /*
288 * This branch info is (a part of) allocated from
289 * machine__resolve_bstack() and will be freed after
290 * adding new entries. So we need to save a copy.
291 */
292 he->branch_info = malloc(sizeof(*he->branch_info));
293 if (he->branch_info == NULL) {
294 free(he);
295 return NULL;
296 }
297
298 memcpy(he->branch_info, template->branch_info,
299 sizeof(*he->branch_info));
300
301 if (he->branch_info->from.map)
302 he->branch_info->from.map->referenced = true;
303 if (he->branch_info->to.map)
304 he->branch_info->to.map->referenced = true;
305 }
306
307 if (he->mem_info) {
308 if (he->mem_info->iaddr.map)
309 he->mem_info->iaddr.map->referenced = true;
310 if (he->mem_info->daddr.map)
311 he->mem_info->daddr.map->referenced = true;
312 }
313
245 if (symbol_conf.use_callchain) 314 if (symbol_conf.use_callchain)
246 callchain_init(he->callchain); 315 callchain_init(he->callchain);
247 316
@@ -251,7 +320,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
251 return he; 320 return he;
252} 321}
253 322
254static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) 323void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
255{ 324{
256 if (!h->filtered) { 325 if (!h->filtered) {
257 hists__calc_col_len(hists, h); 326 hists__calc_col_len(hists, h);
@@ -270,25 +339,36 @@ static u8 symbol__parent_filter(const struct symbol *parent)
270static struct hist_entry *add_hist_entry(struct hists *hists, 339static struct hist_entry *add_hist_entry(struct hists *hists,
271 struct hist_entry *entry, 340 struct hist_entry *entry,
272 struct addr_location *al, 341 struct addr_location *al,
273 u64 period) 342 u64 period,
343 u64 weight)
274{ 344{
275 struct rb_node **p; 345 struct rb_node **p;
276 struct rb_node *parent = NULL; 346 struct rb_node *parent = NULL;
277 struct hist_entry *he; 347 struct hist_entry *he;
278 int cmp; 348 int cmp;
279 349
280 pthread_mutex_lock(&hists->lock);
281
282 p = &hists->entries_in->rb_node; 350 p = &hists->entries_in->rb_node;
283 351
284 while (*p != NULL) { 352 while (*p != NULL) {
285 parent = *p; 353 parent = *p;
286 he = rb_entry(parent, struct hist_entry, rb_node_in); 354 he = rb_entry(parent, struct hist_entry, rb_node_in);
287 355
288 cmp = hist_entry__cmp(entry, he); 356 /*
357 * Make sure that it receives arguments in a same order as
358 * hist_entry__collapse() so that we can use an appropriate
359 * function when searching an entry regardless which sort
360 * keys were used.
361 */
362 cmp = hist_entry__cmp(he, entry);
289 363
290 if (!cmp) { 364 if (!cmp) {
291 he_stat__add_period(&he->stat, period); 365 he_stat__add_period(&he->stat, period, weight);
366
367 /*
368 * This mem info was allocated from machine__resolve_mem
369 * and will not be used anymore.
370 */
371 free(entry->mem_info);
292 372
293 /* If the map of an existing hist_entry has 373 /* If the map of an existing hist_entry has
294 * become out-of-date due to an exec() or 374 * become out-of-date due to an exec() or
@@ -312,22 +392,51 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
312 392
313 he = hist_entry__new(entry); 393 he = hist_entry__new(entry);
314 if (!he) 394 if (!he)
315 goto out_unlock; 395 return NULL;
316 396
317 rb_link_node(&he->rb_node_in, parent, p); 397 rb_link_node(&he->rb_node_in, parent, p);
318 rb_insert_color(&he->rb_node_in, hists->entries_in); 398 rb_insert_color(&he->rb_node_in, hists->entries_in);
319out: 399out:
320 hist_entry__add_cpumode_period(he, al->cpumode, period); 400 hist_entry__add_cpumode_period(he, al->cpumode, period);
321out_unlock:
322 pthread_mutex_unlock(&hists->lock);
323 return he; 401 return he;
324} 402}
325 403
404struct hist_entry *__hists__add_mem_entry(struct hists *self,
405 struct addr_location *al,
406 struct symbol *sym_parent,
407 struct mem_info *mi,
408 u64 period,
409 u64 weight)
410{
411 struct hist_entry entry = {
412 .thread = al->thread,
413 .ms = {
414 .map = al->map,
415 .sym = al->sym,
416 },
417 .stat = {
418 .period = period,
419 .weight = weight,
420 .nr_events = 1,
421 },
422 .cpu = al->cpu,
423 .ip = al->addr,
424 .level = al->level,
425 .parent = sym_parent,
426 .filtered = symbol__parent_filter(sym_parent),
427 .hists = self,
428 .mem_info = mi,
429 .branch_info = NULL,
430 };
431 return add_hist_entry(self, &entry, al, period, weight);
432}
433
326struct hist_entry *__hists__add_branch_entry(struct hists *self, 434struct hist_entry *__hists__add_branch_entry(struct hists *self,
327 struct addr_location *al, 435 struct addr_location *al,
328 struct symbol *sym_parent, 436 struct symbol *sym_parent,
329 struct branch_info *bi, 437 struct branch_info *bi,
330 u64 period) 438 u64 period,
439 u64 weight)
331{ 440{
332 struct hist_entry entry = { 441 struct hist_entry entry = {
333 .thread = al->thread, 442 .thread = al->thread,
@@ -341,19 +450,22 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
341 .stat = { 450 .stat = {
342 .period = period, 451 .period = period,
343 .nr_events = 1, 452 .nr_events = 1,
453 .weight = weight,
344 }, 454 },
345 .parent = sym_parent, 455 .parent = sym_parent,
346 .filtered = symbol__parent_filter(sym_parent), 456 .filtered = symbol__parent_filter(sym_parent),
347 .branch_info = bi, 457 .branch_info = bi,
348 .hists = self, 458 .hists = self,
459 .mem_info = NULL,
349 }; 460 };
350 461
351 return add_hist_entry(self, &entry, al, period); 462 return add_hist_entry(self, &entry, al, period, weight);
352} 463}
353 464
354struct hist_entry *__hists__add_entry(struct hists *self, 465struct hist_entry *__hists__add_entry(struct hists *self,
355 struct addr_location *al, 466 struct addr_location *al,
356 struct symbol *sym_parent, u64 period) 467 struct symbol *sym_parent, u64 period,
468 u64 weight)
357{ 469{
358 struct hist_entry entry = { 470 struct hist_entry entry = {
359 .thread = al->thread, 471 .thread = al->thread,
@@ -367,13 +479,16 @@ struct hist_entry *__hists__add_entry(struct hists *self,
367 .stat = { 479 .stat = {
368 .period = period, 480 .period = period,
369 .nr_events = 1, 481 .nr_events = 1,
482 .weight = weight,
370 }, 483 },
371 .parent = sym_parent, 484 .parent = sym_parent,
372 .filtered = symbol__parent_filter(sym_parent), 485 .filtered = symbol__parent_filter(sym_parent),
373 .hists = self, 486 .hists = self,
487 .branch_info = NULL,
488 .mem_info = NULL,
374 }; 489 };
375 490
376 return add_hist_entry(self, &entry, al, period); 491 return add_hist_entry(self, &entry, al, period, weight);
377} 492}
378 493
379int64_t 494int64_t
@@ -413,6 +528,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
413void hist_entry__free(struct hist_entry *he) 528void hist_entry__free(struct hist_entry *he)
414{ 529{
415 free(he->branch_info); 530 free(he->branch_info);
531 free(he->mem_info);
416 free(he); 532 free(he);
417} 533}
418 534
@@ -481,13 +597,13 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
481 hists__filter_entry_by_symbol(hists, he); 597 hists__filter_entry_by_symbol(hists, he);
482} 598}
483 599
484static void __hists__collapse_resort(struct hists *hists, bool threaded) 600void hists__collapse_resort(struct hists *hists)
485{ 601{
486 struct rb_root *root; 602 struct rb_root *root;
487 struct rb_node *next; 603 struct rb_node *next;
488 struct hist_entry *n; 604 struct hist_entry *n;
489 605
490 if (!sort__need_collapse && !threaded) 606 if (!sort__need_collapse)
491 return; 607 return;
492 608
493 root = hists__get_rotate_entries_in(hists); 609 root = hists__get_rotate_entries_in(hists);
@@ -509,19 +625,65 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
509 } 625 }
510} 626}
511 627
512void hists__collapse_resort(struct hists *hists) 628/*
629 * reverse the map, sort on period.
630 */
631
632static int period_cmp(u64 period_a, u64 period_b)
513{ 633{
514 return __hists__collapse_resort(hists, false); 634 if (period_a > period_b)
635 return 1;
636 if (period_a < period_b)
637 return -1;
638 return 0;
515} 639}
516 640
517void hists__collapse_resort_threaded(struct hists *hists) 641static int hist_entry__sort_on_period(struct hist_entry *a,
642 struct hist_entry *b)
518{ 643{
519 return __hists__collapse_resort(hists, true); 644 int ret;
520} 645 int i, nr_members;
646 struct perf_evsel *evsel;
647 struct hist_entry *pair;
648 u64 *periods_a, *periods_b;
521 649
522/* 650 ret = period_cmp(a->stat.period, b->stat.period);
523 * reverse the map, sort on period. 651 if (ret || !symbol_conf.event_group)
524 */ 652 return ret;
653
654 evsel = hists_to_evsel(a->hists);
655 nr_members = evsel->nr_members;
656 if (nr_members <= 1)
657 return ret;
658
659 periods_a = zalloc(sizeof(periods_a) * nr_members);
660 periods_b = zalloc(sizeof(periods_b) * nr_members);
661
662 if (!periods_a || !periods_b)
663 goto out;
664
665 list_for_each_entry(pair, &a->pairs.head, pairs.node) {
666 evsel = hists_to_evsel(pair->hists);
667 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period;
668 }
669
670 list_for_each_entry(pair, &b->pairs.head, pairs.node) {
671 evsel = hists_to_evsel(pair->hists);
672 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
673 }
674
675 for (i = 1; i < nr_members; i++) {
676 ret = period_cmp(periods_a[i], periods_b[i]);
677 if (ret)
678 break;
679 }
680
681out:
682 free(periods_a);
683 free(periods_b);
684
685 return ret;
686}
525 687
526static void __hists__insert_output_entry(struct rb_root *entries, 688static void __hists__insert_output_entry(struct rb_root *entries,
527 struct hist_entry *he, 689 struct hist_entry *he,
@@ -539,7 +701,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
539 parent = *p; 701 parent = *p;
540 iter = rb_entry(parent, struct hist_entry, rb_node); 702 iter = rb_entry(parent, struct hist_entry, rb_node);
541 703
542 if (he->stat.period > iter->stat.period) 704 if (hist_entry__sort_on_period(he, iter) > 0)
543 p = &(*p)->rb_left; 705 p = &(*p)->rb_left;
544 else 706 else
545 p = &(*p)->rb_right; 707 p = &(*p)->rb_right;
@@ -549,7 +711,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
549 rb_insert_color(&he->rb_node, entries); 711 rb_insert_color(&he->rb_node, entries);
550} 712}
551 713
552static void __hists__output_resort(struct hists *hists, bool threaded) 714void hists__output_resort(struct hists *hists)
553{ 715{
554 struct rb_root *root; 716 struct rb_root *root;
555 struct rb_node *next; 717 struct rb_node *next;
@@ -558,7 +720,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
558 720
559 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); 721 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
560 722
561 if (sort__need_collapse || threaded) 723 if (sort__need_collapse)
562 root = &hists->entries_collapsed; 724 root = &hists->entries_collapsed;
563 else 725 else
564 root = hists->entries_in; 726 root = hists->entries_in;
@@ -579,16 +741,6 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
579 } 741 }
580} 742}
581 743
582void hists__output_resort(struct hists *hists)
583{
584 return __hists__output_resort(hists, false);
585}
586
587void hists__output_resort_threaded(struct hists *hists)
588{
589 return __hists__output_resort(hists, true);
590}
591
592static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, 744static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
593 enum hist_filter filter) 745 enum hist_filter filter)
594{ 746{
@@ -711,25 +863,38 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
711 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 863 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
712} 864}
713 865
866void events_stats__inc(struct events_stats *stats, u32 type)
867{
868 ++stats->nr_events[0];
869 ++stats->nr_events[type];
870}
871
714void hists__inc_nr_events(struct hists *hists, u32 type) 872void hists__inc_nr_events(struct hists *hists, u32 type)
715{ 873{
716 ++hists->stats.nr_events[0]; 874 events_stats__inc(&hists->stats, type);
717 ++hists->stats.nr_events[type];
718} 875}
719 876
720static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 877static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
721 struct hist_entry *pair) 878 struct hist_entry *pair)
722{ 879{
723 struct rb_node **p = &hists->entries.rb_node; 880 struct rb_root *root;
881 struct rb_node **p;
724 struct rb_node *parent = NULL; 882 struct rb_node *parent = NULL;
725 struct hist_entry *he; 883 struct hist_entry *he;
726 int cmp; 884 int cmp;
727 885
886 if (sort__need_collapse)
887 root = &hists->entries_collapsed;
888 else
889 root = hists->entries_in;
890
891 p = &root->rb_node;
892
728 while (*p != NULL) { 893 while (*p != NULL) {
729 parent = *p; 894 parent = *p;
730 he = rb_entry(parent, struct hist_entry, rb_node); 895 he = rb_entry(parent, struct hist_entry, rb_node_in);
731 896
732 cmp = hist_entry__cmp(pair, he); 897 cmp = hist_entry__collapse(he, pair);
733 898
734 if (!cmp) 899 if (!cmp)
735 goto out; 900 goto out;
@@ -744,8 +909,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
744 if (he) { 909 if (he) {
745 memset(&he->stat, 0, sizeof(he->stat)); 910 memset(&he->stat, 0, sizeof(he->stat));
746 he->hists = hists; 911 he->hists = hists;
747 rb_link_node(&he->rb_node, parent, p); 912 rb_link_node(&he->rb_node_in, parent, p);
748 rb_insert_color(&he->rb_node, &hists->entries); 913 rb_insert_color(&he->rb_node_in, root);
749 hists__inc_nr_entries(hists, he); 914 hists__inc_nr_entries(hists, he);
750 } 915 }
751out: 916out:
@@ -755,11 +920,16 @@ out:
755static struct hist_entry *hists__find_entry(struct hists *hists, 920static struct hist_entry *hists__find_entry(struct hists *hists,
756 struct hist_entry *he) 921 struct hist_entry *he)
757{ 922{
758 struct rb_node *n = hists->entries.rb_node; 923 struct rb_node *n;
924
925 if (sort__need_collapse)
926 n = hists->entries_collapsed.rb_node;
927 else
928 n = hists->entries_in->rb_node;
759 929
760 while (n) { 930 while (n) {
761 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 931 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
762 int64_t cmp = hist_entry__cmp(he, iter); 932 int64_t cmp = hist_entry__collapse(iter, he);
763 933
764 if (cmp < 0) 934 if (cmp < 0)
765 n = n->rb_left; 935 n = n->rb_left;
@@ -777,15 +947,21 @@ static struct hist_entry *hists__find_entry(struct hists *hists,
777 */ 947 */
778void hists__match(struct hists *leader, struct hists *other) 948void hists__match(struct hists *leader, struct hists *other)
779{ 949{
950 struct rb_root *root;
780 struct rb_node *nd; 951 struct rb_node *nd;
781 struct hist_entry *pos, *pair; 952 struct hist_entry *pos, *pair;
782 953
783 for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { 954 if (sort__need_collapse)
784 pos = rb_entry(nd, struct hist_entry, rb_node); 955 root = &leader->entries_collapsed;
956 else
957 root = leader->entries_in;
958
959 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
960 pos = rb_entry(nd, struct hist_entry, rb_node_in);
785 pair = hists__find_entry(other, pos); 961 pair = hists__find_entry(other, pos);
786 962
787 if (pair) 963 if (pair)
788 hist__entry_add_pair(pos, pair); 964 hist_entry__add_pair(pair, pos);
789 } 965 }
790} 966}
791 967
@@ -796,17 +972,23 @@ void hists__match(struct hists *leader, struct hists *other)
796 */ 972 */
797int hists__link(struct hists *leader, struct hists *other) 973int hists__link(struct hists *leader, struct hists *other)
798{ 974{
975 struct rb_root *root;
799 struct rb_node *nd; 976 struct rb_node *nd;
800 struct hist_entry *pos, *pair; 977 struct hist_entry *pos, *pair;
801 978
802 for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { 979 if (sort__need_collapse)
803 pos = rb_entry(nd, struct hist_entry, rb_node); 980 root = &other->entries_collapsed;
981 else
982 root = other->entries_in;
983
984 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
985 pos = rb_entry(nd, struct hist_entry, rb_node_in);
804 986
805 if (!hist_entry__has_pairs(pos)) { 987 if (!hist_entry__has_pairs(pos)) {
806 pair = hists__add_dummy_entry(leader, pos); 988 pair = hists__add_dummy_entry(leader, pos);
807 if (pair == NULL) 989 if (pair == NULL)
808 return -1; 990 return -1;
809 hist__entry_add_pair(pair, pos); 991 hist_entry__add_pair(pos, pair);
810 } 992 }
811 } 993 }
812 994
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 8b091a51e4a2..2d3790fd99bb 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -43,12 +43,20 @@ enum hist_column {
43 HISTC_COMM, 43 HISTC_COMM,
44 HISTC_PARENT, 44 HISTC_PARENT,
45 HISTC_CPU, 45 HISTC_CPU,
46 HISTC_SRCLINE,
46 HISTC_MISPREDICT, 47 HISTC_MISPREDICT,
47 HISTC_SYMBOL_FROM, 48 HISTC_SYMBOL_FROM,
48 HISTC_SYMBOL_TO, 49 HISTC_SYMBOL_TO,
49 HISTC_DSO_FROM, 50 HISTC_DSO_FROM,
50 HISTC_DSO_TO, 51 HISTC_DSO_TO,
51 HISTC_SRCLINE, 52 HISTC_LOCAL_WEIGHT,
53 HISTC_GLOBAL_WEIGHT,
54 HISTC_MEM_DADDR_SYMBOL,
55 HISTC_MEM_DADDR_DSO,
56 HISTC_MEM_LOCKED,
57 HISTC_MEM_TLB,
58 HISTC_MEM_LVL,
59 HISTC_MEM_SNOOP,
52 HISTC_NR_COLS, /* Last entry */ 60 HISTC_NR_COLS, /* Last entry */
53}; 61};
54 62
@@ -73,7 +81,8 @@ struct hists {
73 81
74struct hist_entry *__hists__add_entry(struct hists *self, 82struct hist_entry *__hists__add_entry(struct hists *self,
75 struct addr_location *al, 83 struct addr_location *al,
76 struct symbol *parent, u64 period); 84 struct symbol *parent, u64 period,
85 u64 weight);
77int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 86int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
78int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 87int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
79int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, 88int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size,
@@ -84,23 +93,29 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
84 struct addr_location *al, 93 struct addr_location *al,
85 struct symbol *sym_parent, 94 struct symbol *sym_parent,
86 struct branch_info *bi, 95 struct branch_info *bi,
87 u64 period); 96 u64 period,
97 u64 weight);
98
99struct hist_entry *__hists__add_mem_entry(struct hists *self,
100 struct addr_location *al,
101 struct symbol *sym_parent,
102 struct mem_info *mi,
103 u64 period,
104 u64 weight);
88 105
89void hists__output_resort(struct hists *self); 106void hists__output_resort(struct hists *self);
90void hists__output_resort_threaded(struct hists *hists);
91void hists__collapse_resort(struct hists *self); 107void hists__collapse_resort(struct hists *self);
92void hists__collapse_resort_threaded(struct hists *hists);
93 108
94void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 109void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
95void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
96 bool zap_kernel);
97void hists__output_recalc_col_len(struct hists *hists, int max_rows); 110void hists__output_recalc_col_len(struct hists *hists, int max_rows);
98 111
112void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
99void hists__inc_nr_events(struct hists *self, u32 type); 113void hists__inc_nr_events(struct hists *self, u32 type);
100size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 114void events_stats__inc(struct events_stats *stats, u32 type);
115size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
101 116
102size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, 117size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
103 int max_cols, FILE *fp); 118 int max_cols, float min_pcnt, FILE *fp);
104 119
105int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 120int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
106int hist_entry__annotate(struct hist_entry *self, size_t privsize); 121int hist_entry__annotate(struct hist_entry *self, size_t privsize);
@@ -126,13 +141,19 @@ struct perf_hpp {
126}; 141};
127 142
128struct perf_hpp_fmt { 143struct perf_hpp_fmt {
129 bool cond;
130 int (*header)(struct perf_hpp *hpp); 144 int (*header)(struct perf_hpp *hpp);
131 int (*width)(struct perf_hpp *hpp); 145 int (*width)(struct perf_hpp *hpp);
132 int (*color)(struct perf_hpp *hpp, struct hist_entry *he); 146 int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
133 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); 147 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
148
149 struct list_head list;
134}; 150};
135 151
152extern struct list_head perf_hpp__list;
153
154#define perf_hpp__for_each_format(format) \
155 list_for_each_entry(format, &perf_hpp__list, list)
156
136extern struct perf_hpp_fmt perf_hpp__format[]; 157extern struct perf_hpp_fmt perf_hpp__format[];
137 158
138enum { 159enum {
@@ -148,14 +169,14 @@ enum {
148 PERF_HPP__DELTA, 169 PERF_HPP__DELTA,
149 PERF_HPP__RATIO, 170 PERF_HPP__RATIO,
150 PERF_HPP__WEIGHTED_DIFF, 171 PERF_HPP__WEIGHTED_DIFF,
151 PERF_HPP__DISPL,
152 PERF_HPP__FORMULA, 172 PERF_HPP__FORMULA,
153 173
154 PERF_HPP__MAX_INDEX 174 PERF_HPP__MAX_INDEX
155}; 175};
156 176
157void perf_hpp__init(void); 177void perf_hpp__init(void);
158void perf_hpp__column_enable(unsigned col, bool enable); 178void perf_hpp__column_register(struct perf_hpp_fmt *format);
179void perf_hpp__column_enable(unsigned col);
159int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, 180int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
160 bool color); 181 bool color);
161 182
@@ -167,13 +188,14 @@ struct hist_browser_timer {
167 int refresh; 188 int refresh;
168}; 189};
169 190
170#ifdef NEWT_SUPPORT 191#ifdef SLANG_SUPPORT
171#include "../ui/keysyms.h" 192#include "../ui/keysyms.h"
172int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 193int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
173 struct hist_browser_timer *hbt); 194 struct hist_browser_timer *hbt);
174 195
175int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 196int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
176 struct hist_browser_timer *hbt, 197 struct hist_browser_timer *hbt,
198 float min_pcnt,
177 struct perf_session_env *env); 199 struct perf_session_env *env);
178int script_browse(const char *script_opt); 200int script_browse(const char *script_opt);
179#else 201#else
@@ -181,6 +203,7 @@ static inline
181int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, 203int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
182 const char *help __maybe_unused, 204 const char *help __maybe_unused,
183 struct hist_browser_timer *hbt __maybe_unused, 205 struct hist_browser_timer *hbt __maybe_unused,
206 float min_pcnt __maybe_unused,
184 struct perf_session_env *env __maybe_unused) 207 struct perf_session_env *env __maybe_unused)
185{ 208{
186 return 0; 209 return 0;
@@ -188,7 +211,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
188 211
189static inline int hist_entry__tui_annotate(struct hist_entry *self 212static inline int hist_entry__tui_annotate(struct hist_entry *self
190 __maybe_unused, 213 __maybe_unused,
191 int evidx __maybe_unused, 214 struct perf_evsel *evsel
215 __maybe_unused,
192 struct hist_browser_timer *hbt 216 struct hist_browser_timer *hbt
193 __maybe_unused) 217 __maybe_unused)
194{ 218{
@@ -200,18 +224,21 @@ static inline int script_browse(const char *script_opt __maybe_unused)
200 return 0; 224 return 0;
201} 225}
202 226
203#define K_LEFT -1 227#define K_LEFT -1000
204#define K_RIGHT -2 228#define K_RIGHT -2000
229#define K_SWITCH_INPUT_DATA -3000
205#endif 230#endif
206 231
207#ifdef GTK2_SUPPORT 232#ifdef GTK2_SUPPORT
208int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, 233int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
209 struct hist_browser_timer *hbt __maybe_unused); 234 struct hist_browser_timer *hbt __maybe_unused,
235 float min_pcnt);
210#else 236#else
211static inline 237static inline
212int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, 238int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
213 const char *help __maybe_unused, 239 const char *help __maybe_unused,
214 struct hist_browser_timer *hbt __maybe_unused) 240 struct hist_browser_timer *hbt __maybe_unused,
241 float min_pcnt __maybe_unused)
215{ 242{
216 return 0; 243 return 0;
217} 244}
@@ -219,8 +246,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
219 246
220unsigned int hists__sort_list_width(struct hists *self); 247unsigned int hists__sort_list_width(struct hists *self);
221 248
222double perf_diff__compute_delta(struct hist_entry *he); 249double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
223double perf_diff__compute_ratio(struct hist_entry *he); 250double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
224s64 perf_diff__compute_wdiff(struct hist_entry *he); 251s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
225int perf_diff__formula(char *buf, size_t size, struct hist_entry *he); 252int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
253 char *buf, size_t size);
254double perf_diff__period_percent(struct hist_entry *he, u64 period);
226#endif /* __PERF_HIST_H */ 255#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index a55d8cf083c9..45cf10a562bd 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -14,6 +14,7 @@
14#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 14#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) 15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) 16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
17#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE)
17 18
18#define for_each_set_bit(bit, addr, size) \ 19#define for_each_set_bit(bit, addr, size) \
19 for ((bit) = find_first_bit((addr), (size)); \ 20 for ((bit) = find_first_bit((addr), (size)); \
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
index 9d0740024ba8..11a8d86f7fea 100644
--- a/tools/perf/util/intlist.c
+++ b/tools/perf/util/intlist.c
@@ -59,16 +59,40 @@ void intlist__remove(struct intlist *ilist, struct int_node *node)
59 59
60struct int_node *intlist__find(struct intlist *ilist, int i) 60struct int_node *intlist__find(struct intlist *ilist, int i)
61{ 61{
62 struct int_node *node = NULL; 62 struct int_node *node;
63 struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); 63 struct rb_node *rb_node;
64 64
65 if (ilist == NULL)
66 return NULL;
67
68 node = NULL;
69 rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
65 if (rb_node) 70 if (rb_node)
66 node = container_of(rb_node, struct int_node, rb_node); 71 node = container_of(rb_node, struct int_node, rb_node);
67 72
68 return node; 73 return node;
69} 74}
70 75
71struct intlist *intlist__new(void) 76static int intlist__parse_list(struct intlist *ilist, const char *s)
77{
78 char *sep;
79 int err;
80
81 do {
82 long value = strtol(s, &sep, 10);
83 err = -EINVAL;
84 if (*sep != ',' && *sep != '\0')
85 break;
86 err = intlist__add(ilist, value);
87 if (err)
88 break;
89 s = sep + 1;
90 } while (*sep != '\0');
91
92 return err;
93}
94
95struct intlist *intlist__new(const char *slist)
72{ 96{
73 struct intlist *ilist = malloc(sizeof(*ilist)); 97 struct intlist *ilist = malloc(sizeof(*ilist));
74 98
@@ -77,9 +101,15 @@ struct intlist *intlist__new(void)
77 ilist->rblist.node_cmp = intlist__node_cmp; 101 ilist->rblist.node_cmp = intlist__node_cmp;
78 ilist->rblist.node_new = intlist__node_new; 102 ilist->rblist.node_new = intlist__node_new;
79 ilist->rblist.node_delete = intlist__node_delete; 103 ilist->rblist.node_delete = intlist__node_delete;
104
105 if (slist && intlist__parse_list(ilist, slist))
106 goto out_delete;
80 } 107 }
81 108
82 return ilist; 109 return ilist;
110out_delete:
111 intlist__delete(ilist);
112 return NULL;
83} 113}
84 114
85void intlist__delete(struct intlist *ilist) 115void intlist__delete(struct intlist *ilist)
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
index 6d63ab90db50..62351dad848f 100644
--- a/tools/perf/util/intlist.h
+++ b/tools/perf/util/intlist.h
@@ -15,7 +15,7 @@ struct intlist {
15 struct rblist rblist; 15 struct rblist rblist;
16}; 16};
17 17
18struct intlist *intlist__new(void); 18struct intlist *intlist__new(const char *slist);
19void intlist__delete(struct intlist *ilist); 19void intlist__delete(struct intlist *ilist);
20 20
21void intlist__remove(struct intlist *ilist, struct int_node *in); 21void intlist__remove(struct intlist *ilist, struct int_node *in);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 1f09d0581e6b..b2ecad6ec46b 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1,10 +1,15 @@
1#include "callchain.h"
1#include "debug.h" 2#include "debug.h"
2#include "event.h" 3#include "event.h"
4#include "evsel.h"
5#include "hist.h"
3#include "machine.h" 6#include "machine.h"
4#include "map.h" 7#include "map.h"
8#include "sort.h"
5#include "strlist.h" 9#include "strlist.h"
6#include "thread.h" 10#include "thread.h"
7#include <stdbool.h> 11#include <stdbool.h>
12#include "unwind.h"
8 13
9int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 14int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
10{ 15{
@@ -48,6 +53,29 @@ static void dsos__delete(struct list_head *dsos)
48 } 53 }
49} 54}
50 55
56void machine__delete_dead_threads(struct machine *machine)
57{
58 struct thread *n, *t;
59
60 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
61 list_del(&t->node);
62 thread__delete(t);
63 }
64}
65
66void machine__delete_threads(struct machine *machine)
67{
68 struct rb_node *nd = rb_first(&machine->threads);
69
70 while (nd) {
71 struct thread *t = rb_entry(nd, struct thread, rb_node);
72
73 rb_erase(&t->rb_node, &machine->threads);
74 nd = rb_next(nd);
75 thread__delete(t);
76 }
77}
78
51void machine__exit(struct machine *machine) 79void machine__exit(struct machine *machine)
52{ 80{
53 map_groups__exit(&machine->kmaps); 81 map_groups__exit(&machine->kmaps);
@@ -63,10 +91,22 @@ void machine__delete(struct machine *machine)
63 free(machine); 91 free(machine);
64} 92}
65 93
66struct machine *machines__add(struct rb_root *machines, pid_t pid, 94void machines__init(struct machines *machines)
95{
96 machine__init(&machines->host, "", HOST_KERNEL_ID);
97 machines->guests = RB_ROOT;
98}
99
100void machines__exit(struct machines *machines)
101{
102 machine__exit(&machines->host);
103 /* XXX exit guest */
104}
105
106struct machine *machines__add(struct machines *machines, pid_t pid,
67 const char *root_dir) 107 const char *root_dir)
68{ 108{
69 struct rb_node **p = &machines->rb_node; 109 struct rb_node **p = &machines->guests.rb_node;
70 struct rb_node *parent = NULL; 110 struct rb_node *parent = NULL;
71 struct machine *pos, *machine = malloc(sizeof(*machine)); 111 struct machine *pos, *machine = malloc(sizeof(*machine));
72 112
@@ -88,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid,
88 } 128 }
89 129
90 rb_link_node(&machine->rb_node, parent, p); 130 rb_link_node(&machine->rb_node, parent, p);
91 rb_insert_color(&machine->rb_node, machines); 131 rb_insert_color(&machine->rb_node, &machines->guests);
92 132
93 return machine; 133 return machine;
94} 134}
95 135
96struct machine *machines__find(struct rb_root *machines, pid_t pid) 136struct machine *machines__find(struct machines *machines, pid_t pid)
97{ 137{
98 struct rb_node **p = &machines->rb_node; 138 struct rb_node **p = &machines->guests.rb_node;
99 struct rb_node *parent = NULL; 139 struct rb_node *parent = NULL;
100 struct machine *machine; 140 struct machine *machine;
101 struct machine *default_machine = NULL; 141 struct machine *default_machine = NULL;
102 142
143 if (pid == HOST_KERNEL_ID)
144 return &machines->host;
145
103 while (*p != NULL) { 146 while (*p != NULL) {
104 parent = *p; 147 parent = *p;
105 machine = rb_entry(parent, struct machine, rb_node); 148 machine = rb_entry(parent, struct machine, rb_node);
@@ -116,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid)
116 return default_machine; 159 return default_machine;
117} 160}
118 161
119struct machine *machines__findnew(struct rb_root *machines, pid_t pid) 162struct machine *machines__findnew(struct machines *machines, pid_t pid)
120{ 163{
121 char path[PATH_MAX]; 164 char path[PATH_MAX];
122 const char *root_dir = ""; 165 const char *root_dir = "";
@@ -150,12 +193,12 @@ out:
150 return machine; 193 return machine;
151} 194}
152 195
153void machines__process(struct rb_root *machines, 196void machines__process_guests(struct machines *machines,
154 machine__process_t process, void *data) 197 machine__process_t process, void *data)
155{ 198{
156 struct rb_node *nd; 199 struct rb_node *nd;
157 200
158 for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 201 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
159 struct machine *pos = rb_entry(nd, struct machine, rb_node); 202 struct machine *pos = rb_entry(nd, struct machine, rb_node);
160 process(pos, data); 203 process(pos, data);
161 } 204 }
@@ -175,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
175 return bf; 218 return bf;
176} 219}
177 220
178void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) 221void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
179{ 222{
180 struct rb_node *node; 223 struct rb_node *node;
181 struct machine *machine; 224 struct machine *machine;
182 225
183 for (node = rb_first(machines); node; node = rb_next(node)) { 226 machines->host.id_hdr_size = id_hdr_size;
227
228 for (node = rb_first(&machines->guests); node; node = rb_next(node)) {
184 machine = rb_entry(node, struct machine, rb_node); 229 machine = rb_entry(node, struct machine, rb_node);
185 machine->id_hdr_size = id_hdr_size; 230 machine->id_hdr_size = id_hdr_size;
186 } 231 }
@@ -264,6 +309,537 @@ int machine__process_lost_event(struct machine *machine __maybe_unused,
264 return 0; 309 return 0;
265} 310}
266 311
312struct map *machine__new_module(struct machine *machine, u64 start,
313 const char *filename)
314{
315 struct map *map;
316 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
317
318 if (dso == NULL)
319 return NULL;
320
321 map = map__new2(start, dso, MAP__FUNCTION);
322 if (map == NULL)
323 return NULL;
324
325 if (machine__is_host(machine))
326 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
327 else
328 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
329 map_groups__insert(&machine->kmaps, map);
330 return map;
331}
332
333size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
334{
335 struct rb_node *nd;
336 size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) +
337 __dsos__fprintf(&machines->host.user_dsos, fp);
338
339 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
340 struct machine *pos = rb_entry(nd, struct machine, rb_node);
341 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
342 ret += __dsos__fprintf(&pos->user_dsos, fp);
343 }
344
345 return ret;
346}
347
348size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
349 bool (skip)(struct dso *dso, int parm), int parm)
350{
351 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) +
352 __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
353}
354
355size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
356 bool (skip)(struct dso *dso, int parm), int parm)
357{
358 struct rb_node *nd;
359 size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
360
361 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
362 struct machine *pos = rb_entry(nd, struct machine, rb_node);
363 ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
364 }
365 return ret;
366}
367
368size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
369{
370 int i;
371 size_t printed = 0;
372 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
373
374 if (kdso->has_build_id) {
375 char filename[PATH_MAX];
376 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
377 printed += fprintf(fp, "[0] %s\n", filename);
378 }
379
380 for (i = 0; i < vmlinux_path__nr_entries; ++i)
381 printed += fprintf(fp, "[%d] %s\n",
382 i + kdso->has_build_id, vmlinux_path[i]);
383
384 return printed;
385}
386
387size_t machine__fprintf(struct machine *machine, FILE *fp)
388{
389 size_t ret = 0;
390 struct rb_node *nd;
391
392 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
393 struct thread *pos = rb_entry(nd, struct thread, rb_node);
394
395 ret += thread__fprintf(pos, fp);
396 }
397
398 return ret;
399}
400
401static struct dso *machine__get_kernel(struct machine *machine)
402{
403 const char *vmlinux_name = NULL;
404 struct dso *kernel;
405
406 if (machine__is_host(machine)) {
407 vmlinux_name = symbol_conf.vmlinux_name;
408 if (!vmlinux_name)
409 vmlinux_name = "[kernel.kallsyms]";
410
411 kernel = dso__kernel_findnew(machine, vmlinux_name,
412 "[kernel]",
413 DSO_TYPE_KERNEL);
414 } else {
415 char bf[PATH_MAX];
416
417 if (machine__is_default_guest(machine))
418 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
419 if (!vmlinux_name)
420 vmlinux_name = machine__mmap_name(machine, bf,
421 sizeof(bf));
422
423 kernel = dso__kernel_findnew(machine, vmlinux_name,
424 "[guest.kernel]",
425 DSO_TYPE_GUEST_KERNEL);
426 }
427
428 if (kernel != NULL && (!kernel->has_build_id))
429 dso__read_running_kernel_build_id(kernel, machine);
430
431 return kernel;
432}
433
434struct process_args {
435 u64 start;
436};
437
438static int symbol__in_kernel(void *arg, const char *name,
439 char type __maybe_unused, u64 start)
440{
441 struct process_args *args = arg;
442
443 if (strchr(name, '['))
444 return 0;
445
446 args->start = start;
447 return 1;
448}
449
450/* Figure out the start address of kernel map from /proc/kallsyms */
451static u64 machine__get_kernel_start_addr(struct machine *machine)
452{
453 const char *filename;
454 char path[PATH_MAX];
455 struct process_args args;
456
457 if (machine__is_host(machine)) {
458 filename = "/proc/kallsyms";
459 } else {
460 if (machine__is_default_guest(machine))
461 filename = (char *)symbol_conf.default_guest_kallsyms;
462 else {
463 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
464 filename = path;
465 }
466 }
467
468 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
469 return 0;
470
471 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
472 return 0;
473
474 return args.start;
475}
476
477int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
478{
479 enum map_type type;
480 u64 start = machine__get_kernel_start_addr(machine);
481
482 for (type = 0; type < MAP__NR_TYPES; ++type) {
483 struct kmap *kmap;
484
485 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
486 if (machine->vmlinux_maps[type] == NULL)
487 return -1;
488
489 machine->vmlinux_maps[type]->map_ip =
490 machine->vmlinux_maps[type]->unmap_ip =
491 identity__map_ip;
492 kmap = map__kmap(machine->vmlinux_maps[type]);
493 kmap->kmaps = &machine->kmaps;
494 map_groups__insert(&machine->kmaps,
495 machine->vmlinux_maps[type]);
496 }
497
498 return 0;
499}
500
501void machine__destroy_kernel_maps(struct machine *machine)
502{
503 enum map_type type;
504
505 for (type = 0; type < MAP__NR_TYPES; ++type) {
506 struct kmap *kmap;
507
508 if (machine->vmlinux_maps[type] == NULL)
509 continue;
510
511 kmap = map__kmap(machine->vmlinux_maps[type]);
512 map_groups__remove(&machine->kmaps,
513 machine->vmlinux_maps[type]);
514 if (kmap->ref_reloc_sym) {
515 /*
516 * ref_reloc_sym is shared among all maps, so free just
517 * on one of them.
518 */
519 if (type == MAP__FUNCTION) {
520 free((char *)kmap->ref_reloc_sym->name);
521 kmap->ref_reloc_sym->name = NULL;
522 free(kmap->ref_reloc_sym);
523 }
524 kmap->ref_reloc_sym = NULL;
525 }
526
527 map__delete(machine->vmlinux_maps[type]);
528 machine->vmlinux_maps[type] = NULL;
529 }
530}
531
532int machines__create_guest_kernel_maps(struct machines *machines)
533{
534 int ret = 0;
535 struct dirent **namelist = NULL;
536 int i, items = 0;
537 char path[PATH_MAX];
538 pid_t pid;
539 char *endp;
540
541 if (symbol_conf.default_guest_vmlinux_name ||
542 symbol_conf.default_guest_modules ||
543 symbol_conf.default_guest_kallsyms) {
544 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
545 }
546
547 if (symbol_conf.guestmount) {
548 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
549 if (items <= 0)
550 return -ENOENT;
551 for (i = 0; i < items; i++) {
552 if (!isdigit(namelist[i]->d_name[0])) {
553 /* Filter out . and .. */
554 continue;
555 }
556 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
557 if ((*endp != '\0') ||
558 (endp == namelist[i]->d_name) ||
559 (errno == ERANGE)) {
560 pr_debug("invalid directory (%s). Skipping.\n",
561 namelist[i]->d_name);
562 continue;
563 }
564 sprintf(path, "%s/%s/proc/kallsyms",
565 symbol_conf.guestmount,
566 namelist[i]->d_name);
567 ret = access(path, R_OK);
568 if (ret) {
569 pr_debug("Can't access file %s\n", path);
570 goto failure;
571 }
572 machines__create_kernel_maps(machines, pid);
573 }
574failure:
575 free(namelist);
576 }
577
578 return ret;
579}
580
581void machines__destroy_kernel_maps(struct machines *machines)
582{
583 struct rb_node *next = rb_first(&machines->guests);
584
585 machine__destroy_kernel_maps(&machines->host);
586
587 while (next) {
588 struct machine *pos = rb_entry(next, struct machine, rb_node);
589
590 next = rb_next(&pos->rb_node);
591 rb_erase(&pos->rb_node, &machines->guests);
592 machine__delete(pos);
593 }
594}
595
596int machines__create_kernel_maps(struct machines *machines, pid_t pid)
597{
598 struct machine *machine = machines__findnew(machines, pid);
599
600 if (machine == NULL)
601 return -1;
602
603 return machine__create_kernel_maps(machine);
604}
605
606int machine__load_kallsyms(struct machine *machine, const char *filename,
607 enum map_type type, symbol_filter_t filter)
608{
609 struct map *map = machine->vmlinux_maps[type];
610 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
611
612 if (ret > 0) {
613 dso__set_loaded(map->dso, type);
614 /*
615 * Since /proc/kallsyms will have multiple sessions for the
616 * kernel, with modules between them, fixup the end of all
617 * sections.
618 */
619 __map_groups__fixup_end(&machine->kmaps, type);
620 }
621
622 return ret;
623}
624
625int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
626 symbol_filter_t filter)
627{
628 struct map *map = machine->vmlinux_maps[type];
629 int ret = dso__load_vmlinux_path(map->dso, map, filter);
630
631 if (ret > 0) {
632 dso__set_loaded(map->dso, type);
633 map__reloc_vmlinux(map);
634 }
635
636 return ret;
637}
638
639static void map_groups__fixup_end(struct map_groups *mg)
640{
641 int i;
642 for (i = 0; i < MAP__NR_TYPES; ++i)
643 __map_groups__fixup_end(mg, i);
644}
645
646static char *get_kernel_version(const char *root_dir)
647{
648 char version[PATH_MAX];
649 FILE *file;
650 char *name, *tmp;
651 const char *prefix = "Linux version ";
652
653 sprintf(version, "%s/proc/version", root_dir);
654 file = fopen(version, "r");
655 if (!file)
656 return NULL;
657
658 version[0] = '\0';
659 tmp = fgets(version, sizeof(version), file);
660 fclose(file);
661
662 name = strstr(version, prefix);
663 if (!name)
664 return NULL;
665 name += strlen(prefix);
666 tmp = strchr(name, ' ');
667 if (tmp)
668 *tmp = '\0';
669
670 return strdup(name);
671}
672
673static int map_groups__set_modules_path_dir(struct map_groups *mg,
674 const char *dir_name)
675{
676 struct dirent *dent;
677 DIR *dir = opendir(dir_name);
678 int ret = 0;
679
680 if (!dir) {
681 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
682 return -1;
683 }
684
685 while ((dent = readdir(dir)) != NULL) {
686 char path[PATH_MAX];
687 struct stat st;
688
689 /*sshfs might return bad dent->d_type, so we have to stat*/
690 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
691 if (stat(path, &st))
692 continue;
693
694 if (S_ISDIR(st.st_mode)) {
695 if (!strcmp(dent->d_name, ".") ||
696 !strcmp(dent->d_name, ".."))
697 continue;
698
699 ret = map_groups__set_modules_path_dir(mg, path);
700 if (ret < 0)
701 goto out;
702 } else {
703 char *dot = strrchr(dent->d_name, '.'),
704 dso_name[PATH_MAX];
705 struct map *map;
706 char *long_name;
707
708 if (dot == NULL || strcmp(dot, ".ko"))
709 continue;
710 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
711 (int)(dot - dent->d_name), dent->d_name);
712
713 strxfrchar(dso_name, '-', '_');
714 map = map_groups__find_by_name(mg, MAP__FUNCTION,
715 dso_name);
716 if (map == NULL)
717 continue;
718
719 long_name = strdup(path);
720 if (long_name == NULL) {
721 ret = -1;
722 goto out;
723 }
724 dso__set_long_name(map->dso, long_name);
725 map->dso->lname_alloc = 1;
726 dso__kernel_module_get_build_id(map->dso, "");
727 }
728 }
729
730out:
731 closedir(dir);
732 return ret;
733}
734
735static int machine__set_modules_path(struct machine *machine)
736{
737 char *version;
738 char modules_path[PATH_MAX];
739
740 version = get_kernel_version(machine->root_dir);
741 if (!version)
742 return -1;
743
744 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
745 machine->root_dir, version);
746 free(version);
747
748 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
749}
750
751static int machine__create_modules(struct machine *machine)
752{
753 char *line = NULL;
754 size_t n;
755 FILE *file;
756 struct map *map;
757 const char *modules;
758 char path[PATH_MAX];
759
760 if (machine__is_default_guest(machine))
761 modules = symbol_conf.default_guest_modules;
762 else {
763 sprintf(path, "%s/proc/modules", machine->root_dir);
764 modules = path;
765 }
766
767 if (symbol__restricted_filename(path, "/proc/modules"))
768 return -1;
769
770 file = fopen(modules, "r");
771 if (file == NULL)
772 return -1;
773
774 while (!feof(file)) {
775 char name[PATH_MAX];
776 u64 start;
777 char *sep;
778 int line_len;
779
780 line_len = getline(&line, &n, file);
781 if (line_len < 0)
782 break;
783
784 if (!line)
785 goto out_failure;
786
787 line[--line_len] = '\0'; /* \n */
788
789 sep = strrchr(line, 'x');
790 if (sep == NULL)
791 continue;
792
793 hex2u64(sep + 1, &start);
794
795 sep = strchr(line, ' ');
796 if (sep == NULL)
797 continue;
798
799 *sep = '\0';
800
801 snprintf(name, sizeof(name), "[%s]", line);
802 map = machine__new_module(machine, start, name);
803 if (map == NULL)
804 goto out_delete_line;
805 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
806 }
807
808 free(line);
809 fclose(file);
810
811 return machine__set_modules_path(machine);
812
813out_delete_line:
814 free(line);
815out_failure:
816 return -1;
817}
818
819int machine__create_kernel_maps(struct machine *machine)
820{
821 struct dso *kernel = machine__get_kernel(machine);
822
823 if (kernel == NULL ||
824 __machine__create_kernel_maps(machine, kernel) < 0)
825 return -1;
826
827 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
828 if (machine__is_host(machine))
829 pr_debug("Problems creating module maps, "
830 "continuing anyway...\n");
831 else
832 pr_debug("Problems creating module maps for guest %d, "
833 "continuing anyway...\n", machine->pid);
834 }
835
836 /*
837 * Now that we have all the maps created, just set the ->end of them:
838 */
839 map_groups__fixup_end(&machine->kmaps);
840 return 0;
841}
842
267static void machine__set_kernel_mmap_len(struct machine *machine, 843static void machine__set_kernel_mmap_len(struct machine *machine,
268 union perf_event *event) 844 union perf_event *event)
269{ 845{
@@ -379,6 +955,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
379 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 955 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
380 struct thread *thread; 956 struct thread *thread;
381 struct map *map; 957 struct map *map;
958 enum map_type type;
382 int ret = 0; 959 int ret = 0;
383 960
384 if (dump_trace) 961 if (dump_trace)
@@ -395,10 +972,17 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
395 thread = machine__findnew_thread(machine, event->mmap.pid); 972 thread = machine__findnew_thread(machine, event->mmap.pid);
396 if (thread == NULL) 973 if (thread == NULL)
397 goto out_problem; 974 goto out_problem;
975
976 if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
977 type = MAP__VARIABLE;
978 else
979 type = MAP__FUNCTION;
980
398 map = map__new(&machine->user_dsos, event->mmap.start, 981 map = map__new(&machine->user_dsos, event->mmap.start,
399 event->mmap.len, event->mmap.pgoff, 982 event->mmap.len, event->mmap.pgoff,
400 event->mmap.pid, event->mmap.filename, 983 event->mmap.pid, event->mmap.filename,
401 MAP__FUNCTION); 984 type);
985
402 if (map == NULL) 986 if (map == NULL)
403 goto out_problem; 987 goto out_problem;
404 988
@@ -427,6 +1011,17 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
427 return 0; 1011 return 0;
428} 1012}
429 1013
1014static void machine__remove_thread(struct machine *machine, struct thread *th)
1015{
1016 machine->last_match = NULL;
1017 rb_erase(&th->rb_node, &machine->threads);
1018 /*
1019 * We may have references to this thread, for instance in some hist_entry
1020 * instances, so just move them to a separate list.
1021 */
1022 list_add_tail(&th->node, &machine->dead_threads);
1023}
1024
430int machine__process_exit_event(struct machine *machine, union perf_event *event) 1025int machine__process_exit_event(struct machine *machine, union perf_event *event)
431{ 1026{
432 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1027 struct thread *thread = machine__find_thread(machine, event->fork.tid);
@@ -462,3 +1057,210 @@ int machine__process_event(struct machine *machine, union perf_event *event)
462 1057
463 return ret; 1058 return ret;
464} 1059}
1060
1061static bool symbol__match_parent_regex(struct symbol *sym)
1062{
1063 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
1064 return 1;
1065
1066 return 0;
1067}
1068
1069static const u8 cpumodes[] = {
1070 PERF_RECORD_MISC_USER,
1071 PERF_RECORD_MISC_KERNEL,
1072 PERF_RECORD_MISC_GUEST_USER,
1073 PERF_RECORD_MISC_GUEST_KERNEL
1074};
1075#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
1076
1077static void ip__resolve_ams(struct machine *machine, struct thread *thread,
1078 struct addr_map_symbol *ams,
1079 u64 ip)
1080{
1081 struct addr_location al;
1082 size_t i;
1083 u8 m;
1084
1085 memset(&al, 0, sizeof(al));
1086
1087 for (i = 0; i < NCPUMODES; i++) {
1088 m = cpumodes[i];
1089 /*
1090 * We cannot use the header.misc hint to determine whether a
1091 * branch stack address is user, kernel, guest, hypervisor.
1092 * Branches may straddle the kernel/user/hypervisor boundaries.
1093 * Thus, we have to try consecutively until we find a match
1094 * or else, the symbol is unknown
1095 */
1096 thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
1097 ip, &al, NULL);
1098 if (al.sym)
1099 goto found;
1100 }
1101found:
1102 ams->addr = ip;
1103 ams->al_addr = al.addr;
1104 ams->sym = al.sym;
1105 ams->map = al.map;
1106}
1107
1108static void ip__resolve_data(struct machine *machine, struct thread *thread,
1109 u8 m, struct addr_map_symbol *ams, u64 addr)
1110{
1111 struct addr_location al;
1112
1113 memset(&al, 0, sizeof(al));
1114
1115 thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al,
1116 NULL);
1117 ams->addr = addr;
1118 ams->al_addr = al.addr;
1119 ams->sym = al.sym;
1120 ams->map = al.map;
1121}
1122
1123struct mem_info *machine__resolve_mem(struct machine *machine,
1124 struct thread *thr,
1125 struct perf_sample *sample,
1126 u8 cpumode)
1127{
1128 struct mem_info *mi = zalloc(sizeof(*mi));
1129
1130 if (!mi)
1131 return NULL;
1132
1133 ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip);
1134 ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr);
1135 mi->data_src.val = sample->data_src;
1136
1137 return mi;
1138}
1139
1140struct branch_info *machine__resolve_bstack(struct machine *machine,
1141 struct thread *thr,
1142 struct branch_stack *bs)
1143{
1144 struct branch_info *bi;
1145 unsigned int i;
1146
1147 bi = calloc(bs->nr, sizeof(struct branch_info));
1148 if (!bi)
1149 return NULL;
1150
1151 for (i = 0; i < bs->nr; i++) {
1152 ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to);
1153 ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from);
1154 bi[i].flags = bs->entries[i].flags;
1155 }
1156 return bi;
1157}
1158
1159static int machine__resolve_callchain_sample(struct machine *machine,
1160 struct thread *thread,
1161 struct ip_callchain *chain,
1162 struct symbol **parent)
1163
1164{
1165 u8 cpumode = PERF_RECORD_MISC_USER;
1166 unsigned int i;
1167 int err;
1168
1169 callchain_cursor_reset(&callchain_cursor);
1170
1171 if (chain->nr > PERF_MAX_STACK_DEPTH) {
1172 pr_warning("corrupted callchain. skipping...\n");
1173 return 0;
1174 }
1175
1176 for (i = 0; i < chain->nr; i++) {
1177 u64 ip;
1178 struct addr_location al;
1179
1180 if (callchain_param.order == ORDER_CALLEE)
1181 ip = chain->ips[i];
1182 else
1183 ip = chain->ips[chain->nr - i - 1];
1184
1185 if (ip >= PERF_CONTEXT_MAX) {
1186 switch (ip) {
1187 case PERF_CONTEXT_HV:
1188 cpumode = PERF_RECORD_MISC_HYPERVISOR;
1189 break;
1190 case PERF_CONTEXT_KERNEL:
1191 cpumode = PERF_RECORD_MISC_KERNEL;
1192 break;
1193 case PERF_CONTEXT_USER:
1194 cpumode = PERF_RECORD_MISC_USER;
1195 break;
1196 default:
1197 pr_debug("invalid callchain context: "
1198 "%"PRId64"\n", (s64) ip);
1199 /*
1200 * It seems the callchain is corrupted.
1201 * Discard all.
1202 */
1203 callchain_cursor_reset(&callchain_cursor);
1204 return 0;
1205 }
1206 continue;
1207 }
1208
1209 al.filtered = false;
1210 thread__find_addr_location(thread, machine, cpumode,
1211 MAP__FUNCTION, ip, &al, NULL);
1212 if (al.sym != NULL) {
1213 if (sort__has_parent && !*parent &&
1214 symbol__match_parent_regex(al.sym))
1215 *parent = al.sym;
1216 if (!symbol_conf.use_callchain)
1217 break;
1218 }
1219
1220 err = callchain_cursor_append(&callchain_cursor,
1221 ip, al.map, al.sym);
1222 if (err)
1223 return err;
1224 }
1225
1226 return 0;
1227}
1228
1229static int unwind_entry(struct unwind_entry *entry, void *arg)
1230{
1231 struct callchain_cursor *cursor = arg;
1232 return callchain_cursor_append(cursor, entry->ip,
1233 entry->map, entry->sym);
1234}
1235
1236int machine__resolve_callchain(struct machine *machine,
1237 struct perf_evsel *evsel,
1238 struct thread *thread,
1239 struct perf_sample *sample,
1240 struct symbol **parent)
1241
1242{
1243 int ret;
1244
1245 callchain_cursor_reset(&callchain_cursor);
1246
1247 ret = machine__resolve_callchain_sample(machine, thread,
1248 sample->callchain, parent);
1249 if (ret)
1250 return ret;
1251
1252 /* Can we do dwarf post unwind? */
1253 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
1254 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
1255 return 0;
1256
1257 /* Bail out if nothing was captured. */
1258 if ((!sample->user_regs.regs) ||
1259 (!sample->user_stack.size))
1260 return 0;
1261
1262 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
1263 thread, evsel->attr.sample_regs_user,
1264 sample);
1265
1266}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index b7cde7467d55..77940680f1fc 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -47,26 +47,38 @@ int machine__process_event(struct machine *machine, union perf_event *event);
47 47
48typedef void (*machine__process_t)(struct machine *machine, void *data); 48typedef void (*machine__process_t)(struct machine *machine, void *data);
49 49
50void machines__process(struct rb_root *machines, 50struct machines {
51 machine__process_t process, void *data); 51 struct machine host;
52 struct rb_root guests;
53};
54
55void machines__init(struct machines *machines);
56void machines__exit(struct machines *machines);
52 57
53struct machine *machines__add(struct rb_root *machines, pid_t pid, 58void machines__process_guests(struct machines *machines,
59 machine__process_t process, void *data);
60
61struct machine *machines__add(struct machines *machines, pid_t pid,
54 const char *root_dir); 62 const char *root_dir);
55struct machine *machines__find_host(struct rb_root *machines); 63struct machine *machines__find_host(struct machines *machines);
56struct machine *machines__find(struct rb_root *machines, pid_t pid); 64struct machine *machines__find(struct machines *machines, pid_t pid);
57struct machine *machines__findnew(struct rb_root *machines, pid_t pid); 65struct machine *machines__findnew(struct machines *machines, pid_t pid);
58 66
59void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size); 67void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
60char *machine__mmap_name(struct machine *machine, char *bf, size_t size); 68char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
61 69
62int machine__init(struct machine *machine, const char *root_dir, pid_t pid); 70int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
63void machine__exit(struct machine *machine); 71void machine__exit(struct machine *machine);
72void machine__delete_dead_threads(struct machine *machine);
73void machine__delete_threads(struct machine *machine);
64void machine__delete(struct machine *machine); 74void machine__delete(struct machine *machine);
65 75
66
67struct branch_info *machine__resolve_bstack(struct machine *machine, 76struct branch_info *machine__resolve_bstack(struct machine *machine,
68 struct thread *thread, 77 struct thread *thread,
69 struct branch_stack *bs); 78 struct branch_stack *bs);
79struct mem_info *machine__resolve_mem(struct machine *machine,
80 struct thread *thread,
81 struct perf_sample *sample, u8 cpumode);
70int machine__resolve_callchain(struct machine *machine, 82int machine__resolve_callchain(struct machine *machine,
71 struct perf_evsel *evsel, 83 struct perf_evsel *evsel,
72 struct thread *thread, 84 struct thread *thread,
@@ -88,7 +100,6 @@ static inline bool machine__is_host(struct machine *machine)
88} 100}
89 101
90struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); 102struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
91void machine__remove_thread(struct machine *machine, struct thread *th);
92 103
93size_t machine__fprintf(struct machine *machine, FILE *fp); 104size_t machine__fprintf(struct machine *machine, FILE *fp);
94 105
@@ -129,19 +140,19 @@ int machine__load_kallsyms(struct machine *machine, const char *filename,
129int machine__load_vmlinux_path(struct machine *machine, enum map_type type, 140int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
130 symbol_filter_t filter); 141 symbol_filter_t filter);
131 142
132size_t machine__fprintf_dsos_buildid(struct machine *machine, 143size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
133 FILE *fp, bool with_hits); 144 bool (skip)(struct dso *dso, int parm), int parm);
134size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); 145size_t machines__fprintf_dsos(struct machines *machines, FILE *fp);
135size_t machines__fprintf_dsos_buildid(struct rb_root *machines, 146size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
136 FILE *fp, bool with_hits); 147 bool (skip)(struct dso *dso, int parm), int parm);
137 148
138void machine__destroy_kernel_maps(struct machine *machine); 149void machine__destroy_kernel_maps(struct machine *machine);
139int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); 150int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
140int machine__create_kernel_maps(struct machine *machine); 151int machine__create_kernel_maps(struct machine *machine);
141 152
142int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); 153int machines__create_kernel_maps(struct machines *machines, pid_t pid);
143int machines__create_guest_kernel_maps(struct rb_root *machines); 154int machines__create_guest_kernel_maps(struct machines *machines);
144void machines__destroy_guest_kernel_maps(struct rb_root *machines); 155void machines__destroy_kernel_maps(struct machines *machines);
145 156
146size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); 157size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
147 158
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 0328d45c4f2a..8bcdf9e54089 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -11,6 +11,7 @@
11#include "strlist.h" 11#include "strlist.h"
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h" 13#include "build-id.h"
14#include <linux/string.h>
14 15
15const char *map_type__name[MAP__NR_TYPES] = { 16const char *map_type__name[MAP__NR_TYPES] = {
16 [MAP__FUNCTION] = "Functions", 17 [MAP__FUNCTION] = "Functions",
@@ -19,7 +20,9 @@ const char *map_type__name[MAP__NR_TYPES] = {
19 20
20static inline int is_anon_memory(const char *filename) 21static inline int is_anon_memory(const char *filename)
21{ 22{
22 return strcmp(filename, "//anon") == 0; 23 return !strcmp(filename, "//anon") ||
24 !strcmp(filename, "/dev/zero (deleted)") ||
25 !strcmp(filename, "/anon_hugepage (deleted)");
23} 26}
24 27
25static inline int is_no_dso_memory(const char *filename) 28static inline int is_no_dso_memory(const char *filename)
@@ -28,29 +31,29 @@ static inline int is_no_dso_memory(const char *filename)
28 !strcmp(filename, "[heap]"); 31 !strcmp(filename, "[heap]");
29} 32}
30 33
31void map__init(struct map *self, enum map_type type, 34void map__init(struct map *map, enum map_type type,
32 u64 start, u64 end, u64 pgoff, struct dso *dso) 35 u64 start, u64 end, u64 pgoff, struct dso *dso)
33{ 36{
34 self->type = type; 37 map->type = type;
35 self->start = start; 38 map->start = start;
36 self->end = end; 39 map->end = end;
37 self->pgoff = pgoff; 40 map->pgoff = pgoff;
38 self->dso = dso; 41 map->dso = dso;
39 self->map_ip = map__map_ip; 42 map->map_ip = map__map_ip;
40 self->unmap_ip = map__unmap_ip; 43 map->unmap_ip = map__unmap_ip;
41 RB_CLEAR_NODE(&self->rb_node); 44 RB_CLEAR_NODE(&map->rb_node);
42 self->groups = NULL; 45 map->groups = NULL;
43 self->referenced = false; 46 map->referenced = false;
44 self->erange_warned = false; 47 map->erange_warned = false;
45} 48}
46 49
47struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 50struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
48 u64 pgoff, u32 pid, char *filename, 51 u64 pgoff, u32 pid, char *filename,
49 enum map_type type) 52 enum map_type type)
50{ 53{
51 struct map *self = malloc(sizeof(*self)); 54 struct map *map = malloc(sizeof(*map));
52 55
53 if (self != NULL) { 56 if (map != NULL) {
54 char newfilename[PATH_MAX]; 57 char newfilename[PATH_MAX];
55 struct dso *dso; 58 struct dso *dso;
56 int anon, no_dso, vdso; 59 int anon, no_dso, vdso;
@@ -73,10 +76,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
73 if (dso == NULL) 76 if (dso == NULL)
74 goto out_delete; 77 goto out_delete;
75 78
76 map__init(self, type, start, start + len, pgoff, dso); 79 map__init(map, type, start, start + len, pgoff, dso);
77 80
78 if (anon || no_dso) { 81 if (anon || no_dso) {
79 self->map_ip = self->unmap_ip = identity__map_ip; 82 map->map_ip = map->unmap_ip = identity__map_ip;
80 83
81 /* 84 /*
82 * Set memory without DSO as loaded. All map__find_* 85 * Set memory without DSO as loaded. All map__find_*
@@ -84,12 +87,12 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
84 * unnecessary map__load warning. 87 * unnecessary map__load warning.
85 */ 88 */
86 if (no_dso) 89 if (no_dso)
87 dso__set_loaded(dso, self->type); 90 dso__set_loaded(dso, map->type);
88 } 91 }
89 } 92 }
90 return self; 93 return map;
91out_delete: 94out_delete:
92 free(self); 95 free(map);
93 return NULL; 96 return NULL;
94} 97}
95 98
@@ -112,48 +115,48 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
112 return map; 115 return map;
113} 116}
114 117
115void map__delete(struct map *self) 118void map__delete(struct map *map)
116{ 119{
117 free(self); 120 free(map);
118} 121}
119 122
120void map__fixup_start(struct map *self) 123void map__fixup_start(struct map *map)
121{ 124{
122 struct rb_root *symbols = &self->dso->symbols[self->type]; 125 struct rb_root *symbols = &map->dso->symbols[map->type];
123 struct rb_node *nd = rb_first(symbols); 126 struct rb_node *nd = rb_first(symbols);
124 if (nd != NULL) { 127 if (nd != NULL) {
125 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 128 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
126 self->start = sym->start; 129 map->start = sym->start;
127 } 130 }
128} 131}
129 132
130void map__fixup_end(struct map *self) 133void map__fixup_end(struct map *map)
131{ 134{
132 struct rb_root *symbols = &self->dso->symbols[self->type]; 135 struct rb_root *symbols = &map->dso->symbols[map->type];
133 struct rb_node *nd = rb_last(symbols); 136 struct rb_node *nd = rb_last(symbols);
134 if (nd != NULL) { 137 if (nd != NULL) {
135 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 138 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
136 self->end = sym->end; 139 map->end = sym->end;
137 } 140 }
138} 141}
139 142
140#define DSO__DELETED "(deleted)" 143#define DSO__DELETED "(deleted)"
141 144
142int map__load(struct map *self, symbol_filter_t filter) 145int map__load(struct map *map, symbol_filter_t filter)
143{ 146{
144 const char *name = self->dso->long_name; 147 const char *name = map->dso->long_name;
145 int nr; 148 int nr;
146 149
147 if (dso__loaded(self->dso, self->type)) 150 if (dso__loaded(map->dso, map->type))
148 return 0; 151 return 0;
149 152
150 nr = dso__load(self->dso, self, filter); 153 nr = dso__load(map->dso, map, filter);
151 if (nr < 0) { 154 if (nr < 0) {
152 if (self->dso->has_build_id) { 155 if (map->dso->has_build_id) {
153 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 156 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
154 157
155 build_id__sprintf(self->dso->build_id, 158 build_id__sprintf(map->dso->build_id,
156 sizeof(self->dso->build_id), 159 sizeof(map->dso->build_id),
157 sbuild_id); 160 sbuild_id);
158 pr_warning("%s with build id %s not found", 161 pr_warning("%s with build id %s not found",
159 name, sbuild_id); 162 name, sbuild_id);
@@ -183,43 +186,36 @@ int map__load(struct map *self, symbol_filter_t filter)
183 * Only applies to the kernel, as its symtabs aren't relative like the 186 * Only applies to the kernel, as its symtabs aren't relative like the
184 * module ones. 187 * module ones.
185 */ 188 */
186 if (self->dso->kernel) 189 if (map->dso->kernel)
187 map__reloc_vmlinux(self); 190 map__reloc_vmlinux(map);
188 191
189 return 0; 192 return 0;
190} 193}
191 194
192struct symbol *map__find_symbol(struct map *self, u64 addr, 195struct symbol *map__find_symbol(struct map *map, u64 addr,
193 symbol_filter_t filter) 196 symbol_filter_t filter)
194{ 197{
195 if (map__load(self, filter) < 0) 198 if (map__load(map, filter) < 0)
196 return NULL; 199 return NULL;
197 200
198 return dso__find_symbol(self->dso, self->type, addr); 201 return dso__find_symbol(map->dso, map->type, addr);
199} 202}
200 203
201struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 204struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
202 symbol_filter_t filter) 205 symbol_filter_t filter)
203{ 206{
204 if (map__load(self, filter) < 0) 207 if (map__load(map, filter) < 0)
205 return NULL; 208 return NULL;
206 209
207 if (!dso__sorted_by_name(self->dso, self->type)) 210 if (!dso__sorted_by_name(map->dso, map->type))
208 dso__sort_by_name(self->dso, self->type); 211 dso__sort_by_name(map->dso, map->type);
209 212
210 return dso__find_symbol_by_name(self->dso, self->type, name); 213 return dso__find_symbol_by_name(map->dso, map->type, name);
211} 214}
212 215
213struct map *map__clone(struct map *self) 216struct map *map__clone(struct map *map)
214{ 217{
215 struct map *map = malloc(sizeof(*self)); 218 return memdup(map, sizeof(*map));
216
217 if (!map)
218 return NULL;
219
220 memcpy(map, self, sizeof(*self));
221
222 return map;
223} 219}
224 220
225int map__overlap(struct map *l, struct map *r) 221int map__overlap(struct map *l, struct map *r)
@@ -236,10 +232,10 @@ int map__overlap(struct map *l, struct map *r)
236 return 0; 232 return 0;
237} 233}
238 234
239size_t map__fprintf(struct map *self, FILE *fp) 235size_t map__fprintf(struct map *map, FILE *fp)
240{ 236{
241 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", 237 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
242 self->start, self->end, self->pgoff, self->dso->name); 238 map->start, map->end, map->pgoff, map->dso->name);
243} 239}
244 240
245size_t map__fprintf_dsoname(struct map *map, FILE *fp) 241size_t map__fprintf_dsoname(struct map *map, FILE *fp)
@@ -527,9 +523,9 @@ static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
527 return ip - (s64)map->pgoff; 523 return ip - (s64)map->pgoff;
528} 524}
529 525
530void map__reloc_vmlinux(struct map *self) 526void map__reloc_vmlinux(struct map *map)
531{ 527{
532 struct kmap *kmap = map__kmap(self); 528 struct kmap *kmap = map__kmap(map);
533 s64 reloc; 529 s64 reloc;
534 530
535 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr) 531 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
@@ -541,9 +537,9 @@ void map__reloc_vmlinux(struct map *self)
541 if (!reloc) 537 if (!reloc)
542 return; 538 return;
543 539
544 self->map_ip = map__reloc_map_ip; 540 map->map_ip = map__reloc_map_ip;
545 self->unmap_ip = map__reloc_unmap_ip; 541 map->unmap_ip = map__reloc_unmap_ip;
546 self->pgoff = reloc; 542 map->pgoff = reloc;
547} 543}
548 544
549void maps__insert(struct rb_root *maps, struct map *map) 545void maps__insert(struct rb_root *maps, struct map *map)
@@ -566,9 +562,9 @@ void maps__insert(struct rb_root *maps, struct map *map)
566 rb_insert_color(&map->rb_node, maps); 562 rb_insert_color(&map->rb_node, maps);
567} 563}
568 564
569void maps__remove(struct rb_root *self, struct map *map) 565void maps__remove(struct rb_root *maps, struct map *map)
570{ 566{
571 rb_erase(&map->rb_node, self); 567 rb_erase(&map->rb_node, maps);
572} 568}
573 569
574struct map *maps__find(struct rb_root *maps, u64 ip) 570struct map *maps__find(struct rb_root *maps, u64 ip)
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index bcb39e2a6965..a887f2c9dfbb 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -57,9 +57,9 @@ struct map_groups {
57 struct machine *machine; 57 struct machine *machine;
58}; 58};
59 59
60static inline struct kmap *map__kmap(struct map *self) 60static inline struct kmap *map__kmap(struct map *map)
61{ 61{
62 return (struct kmap *)(self + 1); 62 return (struct kmap *)(map + 1);
63} 63}
64 64
65static inline u64 map__map_ip(struct map *map, u64 ip) 65static inline u64 map__map_ip(struct map *map, u64 ip)
@@ -85,27 +85,27 @@ struct symbol;
85 85
86typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 86typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
87 87
88void map__init(struct map *self, enum map_type type, 88void map__init(struct map *map, enum map_type type,
89 u64 start, u64 end, u64 pgoff, struct dso *dso); 89 u64 start, u64 end, u64 pgoff, struct dso *dso);
90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
91 u64 pgoff, u32 pid, char *filename, 91 u64 pgoff, u32 pid, char *filename,
92 enum map_type type); 92 enum map_type type);
93struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 93struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
94void map__delete(struct map *self); 94void map__delete(struct map *map);
95struct map *map__clone(struct map *self); 95struct map *map__clone(struct map *map);
96int map__overlap(struct map *l, struct map *r); 96int map__overlap(struct map *l, struct map *r);
97size_t map__fprintf(struct map *self, FILE *fp); 97size_t map__fprintf(struct map *map, FILE *fp);
98size_t map__fprintf_dsoname(struct map *map, FILE *fp); 98size_t map__fprintf_dsoname(struct map *map, FILE *fp);
99 99
100int map__load(struct map *self, symbol_filter_t filter); 100int map__load(struct map *map, symbol_filter_t filter);
101struct symbol *map__find_symbol(struct map *self, 101struct symbol *map__find_symbol(struct map *map,
102 u64 addr, symbol_filter_t filter); 102 u64 addr, symbol_filter_t filter);
103struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 103struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
104 symbol_filter_t filter); 104 symbol_filter_t filter);
105void map__fixup_start(struct map *self); 105void map__fixup_start(struct map *map);
106void map__fixup_end(struct map *self); 106void map__fixup_end(struct map *map);
107 107
108void map__reloc_vmlinux(struct map *self); 108void map__reloc_vmlinux(struct map *map);
109 109
110size_t __map_groups__fprintf_maps(struct map_groups *mg, 110size_t __map_groups__fprintf_maps(struct map_groups *mg,
111 enum map_type type, int verbose, FILE *fp); 111 enum map_type type, int verbose, FILE *fp);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 2d8d53bec17e..6c8bb0fb189b 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -10,7 +10,7 @@
10#include "symbol.h" 10#include "symbol.h"
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
13#include "debugfs.h" 13#include <lk/debugfs.h>
14#include "parse-events-bison.h" 14#include "parse-events-bison.h"
15#define YY_EXTRA_TYPE int 15#define YY_EXTRA_TYPE int
16#include "parse-events-flex.h" 16#include "parse-events-flex.h"
@@ -380,8 +380,8 @@ static int add_tracepoint(struct list_head **listp, int *idx,
380 return 0; 380 return 0;
381} 381}
382 382
383static int add_tracepoint_multi(struct list_head **list, int *idx, 383static int add_tracepoint_multi_event(struct list_head **list, int *idx,
384 char *sys_name, char *evt_name) 384 char *sys_name, char *evt_name)
385{ 385{
386 char evt_path[MAXPATHLEN]; 386 char evt_path[MAXPATHLEN];
387 struct dirent *evt_ent; 387 struct dirent *evt_ent;
@@ -408,6 +408,47 @@ static int add_tracepoint_multi(struct list_head **list, int *idx,
408 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); 408 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
409 } 409 }
410 410
411 closedir(evt_dir);
412 return ret;
413}
414
415static int add_tracepoint_event(struct list_head **list, int *idx,
416 char *sys_name, char *evt_name)
417{
418 return strpbrk(evt_name, "*?") ?
419 add_tracepoint_multi_event(list, idx, sys_name, evt_name) :
420 add_tracepoint(list, idx, sys_name, evt_name);
421}
422
423static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
424 char *sys_name, char *evt_name)
425{
426 struct dirent *events_ent;
427 DIR *events_dir;
428 int ret = 0;
429
430 events_dir = opendir(tracing_events_path);
431 if (!events_dir) {
432 perror("Can't open event dir");
433 return -1;
434 }
435
436 while (!ret && (events_ent = readdir(events_dir))) {
437 if (!strcmp(events_ent->d_name, ".")
438 || !strcmp(events_ent->d_name, "..")
439 || !strcmp(events_ent->d_name, "enable")
440 || !strcmp(events_ent->d_name, "header_event")
441 || !strcmp(events_ent->d_name, "header_page"))
442 continue;
443
444 if (!strglobmatch(events_ent->d_name, sys_name))
445 continue;
446
447 ret = add_tracepoint_event(list, idx, events_ent->d_name,
448 evt_name);
449 }
450
451 closedir(events_dir);
411 return ret; 452 return ret;
412} 453}
413 454
@@ -420,9 +461,10 @@ int parse_events_add_tracepoint(struct list_head **list, int *idx,
420 if (ret) 461 if (ret)
421 return ret; 462 return ret;
422 463
423 return strpbrk(event, "*?") ? 464 if (strpbrk(sys, "*?"))
424 add_tracepoint_multi(list, idx, sys, event) : 465 return add_tracepoint_multi_sys(list, idx, sys, event);
425 add_tracepoint(list, idx, sys, event); 466 else
467 return add_tracepoint_event(list, idx, sys, event);
426} 468}
427 469
428static int 470static int
@@ -492,7 +534,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
492} 534}
493 535
494static int config_term(struct perf_event_attr *attr, 536static int config_term(struct perf_event_attr *attr,
495 struct parse_events__term *term) 537 struct parse_events_term *term)
496{ 538{
497#define CHECK_TYPE_VAL(type) \ 539#define CHECK_TYPE_VAL(type) \
498do { \ 540do { \
@@ -537,7 +579,7 @@ do { \
537static int config_attr(struct perf_event_attr *attr, 579static int config_attr(struct perf_event_attr *attr,
538 struct list_head *head, int fail) 580 struct list_head *head, int fail)
539{ 581{
540 struct parse_events__term *term; 582 struct parse_events_term *term;
541 583
542 list_for_each_entry(term, head, list) 584 list_for_each_entry(term, head, list)
543 if (config_term(attr, term) && fail) 585 if (config_term(attr, term) && fail)
@@ -563,14 +605,14 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
563 return add_event(list, idx, &attr, NULL); 605 return add_event(list, idx, &attr, NULL);
564} 606}
565 607
566static int parse_events__is_name_term(struct parse_events__term *term) 608static int parse_events__is_name_term(struct parse_events_term *term)
567{ 609{
568 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; 610 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
569} 611}
570 612
571static char *pmu_event_name(struct list_head *head_terms) 613static char *pmu_event_name(struct list_head *head_terms)
572{ 614{
573 struct parse_events__term *term; 615 struct parse_events_term *term;
574 616
575 list_for_each_entry(term, head_terms, list) 617 list_for_each_entry(term, head_terms, list)
576 if (parse_events__is_name_term(term)) 618 if (parse_events__is_name_term(term))
@@ -657,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
657 int exclude = eu | ek | eh; 699 int exclude = eu | ek | eh;
658 int exclude_GH = evsel ? evsel->exclude_GH : 0; 700 int exclude_GH = evsel ? evsel->exclude_GH : 0;
659 701
660 /*
661 * We are here for group and 'GH' was not set as event
662 * modifier and whatever event/group modifier override
663 * default 'GH' setup.
664 */
665 if (evsel && !exclude_GH)
666 eH = eG = 0;
667
668 memset(mod, 0, sizeof(*mod)); 702 memset(mod, 0, sizeof(*mod));
669 703
670 while (*str) { 704 while (*str) {
@@ -814,7 +848,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
814 */ 848 */
815int parse_events_terms(struct list_head *terms, const char *str) 849int parse_events_terms(struct list_head *terms, const char *str)
816{ 850{
817 struct parse_events_data__terms data = { 851 struct parse_events_terms data = {
818 .terms = NULL, 852 .terms = NULL,
819 }; 853 };
820 int ret; 854 int ret;
@@ -830,10 +864,9 @@ int parse_events_terms(struct list_head *terms, const char *str)
830 return ret; 864 return ret;
831} 865}
832 866
833int parse_events(struct perf_evlist *evlist, const char *str, 867int parse_events(struct perf_evlist *evlist, const char *str)
834 int unset __maybe_unused)
835{ 868{
836 struct parse_events_data__events data = { 869 struct parse_events_evlist data = {
837 .list = LIST_HEAD_INIT(data.list), 870 .list = LIST_HEAD_INIT(data.list),
838 .idx = evlist->nr_entries, 871 .idx = evlist->nr_entries,
839 }; 872 };
@@ -843,6 +876,7 @@ int parse_events(struct perf_evlist *evlist, const char *str,
843 if (!ret) { 876 if (!ret) {
844 int entries = data.idx - evlist->nr_entries; 877 int entries = data.idx - evlist->nr_entries;
845 perf_evlist__splice_list_tail(evlist, &data.list, entries); 878 perf_evlist__splice_list_tail(evlist, &data.list, entries);
879 evlist->nr_groups += data.nr_groups;
846 return 0; 880 return 0;
847 } 881 }
848 882
@@ -858,7 +892,7 @@ int parse_events_option(const struct option *opt, const char *str,
858 int unset __maybe_unused) 892 int unset __maybe_unused)
859{ 893{
860 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 894 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
861 int ret = parse_events(evlist, str, unset); 895 int ret = parse_events(evlist, str);
862 896
863 if (ret) { 897 if (ret) {
864 fprintf(stderr, "invalid or unsupported event: '%s'\n", str); 898 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
@@ -1121,16 +1155,16 @@ void print_events(const char *event_glob, bool name_only)
1121 print_tracepoint_events(NULL, NULL, name_only); 1155 print_tracepoint_events(NULL, NULL, name_only);
1122} 1156}
1123 1157
1124int parse_events__is_hardcoded_term(struct parse_events__term *term) 1158int parse_events__is_hardcoded_term(struct parse_events_term *term)
1125{ 1159{
1126 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; 1160 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
1127} 1161}
1128 1162
1129static int new_term(struct parse_events__term **_term, int type_val, 1163static int new_term(struct parse_events_term **_term, int type_val,
1130 int type_term, char *config, 1164 int type_term, char *config,
1131 char *str, u64 num) 1165 char *str, u64 num)
1132{ 1166{
1133 struct parse_events__term *term; 1167 struct parse_events_term *term;
1134 1168
1135 term = zalloc(sizeof(*term)); 1169 term = zalloc(sizeof(*term));
1136 if (!term) 1170 if (!term)
@@ -1156,21 +1190,21 @@ static int new_term(struct parse_events__term **_term, int type_val,
1156 return 0; 1190 return 0;
1157} 1191}
1158 1192
1159int parse_events__term_num(struct parse_events__term **term, 1193int parse_events_term__num(struct parse_events_term **term,
1160 int type_term, char *config, u64 num) 1194 int type_term, char *config, u64 num)
1161{ 1195{
1162 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, 1196 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1163 config, NULL, num); 1197 config, NULL, num);
1164} 1198}
1165 1199
1166int parse_events__term_str(struct parse_events__term **term, 1200int parse_events_term__str(struct parse_events_term **term,
1167 int type_term, char *config, char *str) 1201 int type_term, char *config, char *str)
1168{ 1202{
1169 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, 1203 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1170 config, str, 0); 1204 config, str, 0);
1171} 1205}
1172 1206
1173int parse_events__term_sym_hw(struct parse_events__term **term, 1207int parse_events_term__sym_hw(struct parse_events_term **term,
1174 char *config, unsigned idx) 1208 char *config, unsigned idx)
1175{ 1209{
1176 struct event_symbol *sym; 1210 struct event_symbol *sym;
@@ -1188,8 +1222,8 @@ int parse_events__term_sym_hw(struct parse_events__term **term,
1188 (char *) "event", (char *) sym->symbol, 0); 1222 (char *) "event", (char *) sym->symbol, 0);
1189} 1223}
1190 1224
1191int parse_events__term_clone(struct parse_events__term **new, 1225int parse_events_term__clone(struct parse_events_term **new,
1192 struct parse_events__term *term) 1226 struct parse_events_term *term)
1193{ 1227{
1194 return new_term(new, term->type_val, term->type_term, term->config, 1228 return new_term(new, term->type_val, term->type_term, term->config,
1195 term->val.str, term->val.num); 1229 term->val.str, term->val.num);
@@ -1197,7 +1231,7 @@ int parse_events__term_clone(struct parse_events__term **new,
1197 1231
1198void parse_events__free_terms(struct list_head *terms) 1232void parse_events__free_terms(struct list_head *terms)
1199{ 1233{
1200 struct parse_events__term *term, *h; 1234 struct parse_events_term *term, *h;
1201 1235
1202 list_for_each_entry_safe(term, h, terms, list) 1236 list_for_each_entry_safe(term, h, terms, list)
1203 free(term); 1237 free(term);
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index b7af80b8bdda..8a4859315fd9 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -29,8 +29,7 @@ const char *event_type(int type);
29 29
30extern int parse_events_option(const struct option *opt, const char *str, 30extern int parse_events_option(const struct option *opt, const char *str,
31 int unset); 31 int unset);
32extern int parse_events(struct perf_evlist *evlist, const char *str, 32extern int parse_events(struct perf_evlist *evlist, const char *str);
33 int unset);
34extern int parse_events_terms(struct list_head *terms, const char *str); 33extern int parse_events_terms(struct list_head *terms, const char *str);
35extern int parse_filter(const struct option *opt, const char *str, int unset); 34extern int parse_filter(const struct option *opt, const char *str, int unset);
36 35
@@ -51,7 +50,7 @@ enum {
51 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 50 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
52}; 51};
53 52
54struct parse_events__term { 53struct parse_events_term {
55 char *config; 54 char *config;
56 union { 55 union {
57 char *str; 56 char *str;
@@ -62,24 +61,25 @@ struct parse_events__term {
62 struct list_head list; 61 struct list_head list;
63}; 62};
64 63
65struct parse_events_data__events { 64struct parse_events_evlist {
66 struct list_head list; 65 struct list_head list;
67 int idx; 66 int idx;
67 int nr_groups;
68}; 68};
69 69
70struct parse_events_data__terms { 70struct parse_events_terms {
71 struct list_head *terms; 71 struct list_head *terms;
72}; 72};
73 73
74int parse_events__is_hardcoded_term(struct parse_events__term *term); 74int parse_events__is_hardcoded_term(struct parse_events_term *term);
75int parse_events__term_num(struct parse_events__term **_term, 75int parse_events_term__num(struct parse_events_term **_term,
76 int type_term, char *config, u64 num); 76 int type_term, char *config, u64 num);
77int parse_events__term_str(struct parse_events__term **_term, 77int parse_events_term__str(struct parse_events_term **_term,
78 int type_term, char *config, char *str); 78 int type_term, char *config, char *str);
79int parse_events__term_sym_hw(struct parse_events__term **term, 79int parse_events_term__sym_hw(struct parse_events_term **term,
80 char *config, unsigned idx); 80 char *config, unsigned idx);
81int parse_events__term_clone(struct parse_events__term **new, 81int parse_events_term__clone(struct parse_events_term **new,
82 struct parse_events__term *term); 82 struct parse_events_term *term);
83void parse_events__free_terms(struct list_head *terms); 83void parse_events__free_terms(struct list_head *terms);
84int parse_events__modifier_event(struct list_head *list, char *str, bool add); 84int parse_events__modifier_event(struct list_head *list, char *str, bool add);
85int parse_events__modifier_group(struct list_head *list, char *event_mod); 85int parse_events__modifier_group(struct list_head *list, char *event_mod);
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 0f9914ae6bac..afc44c18dfe1 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,5 +1,4 @@
1%pure-parser 1%pure-parser
2%name-prefix "parse_events_"
3%parse-param {void *_data} 2%parse-param {void *_data}
4%parse-param {void *scanner} 3%parse-param {void *scanner}
5%lex-param {void* scanner} 4%lex-param {void* scanner}
@@ -23,6 +22,14 @@ do { \
23 YYABORT; \ 22 YYABORT; \
24} while (0) 23} while (0)
25 24
25static inc_group_count(struct list_head *list,
26 struct parse_events_evlist *data)
27{
28 /* Count groups only have more than 1 members */
29 if (!list_is_last(list->next, list))
30 data->nr_groups++;
31}
32
26%} 33%}
27 34
28%token PE_START_EVENTS PE_START_TERMS 35%token PE_START_EVENTS PE_START_TERMS
@@ -68,7 +75,7 @@ do { \
68 char *str; 75 char *str;
69 u64 num; 76 u64 num;
70 struct list_head *head; 77 struct list_head *head;
71 struct parse_events__term *term; 78 struct parse_events_term *term;
72} 79}
73%% 80%%
74 81
@@ -79,7 +86,7 @@ PE_START_TERMS start_terms
79 86
80start_events: groups 87start_events: groups
81{ 88{
82 struct parse_events_data__events *data = _data; 89 struct parse_events_evlist *data = _data;
83 90
84 parse_events_update_lists($1, &data->list); 91 parse_events_update_lists($1, &data->list);
85} 92}
@@ -123,6 +130,7 @@ PE_NAME '{' events '}'
123{ 130{
124 struct list_head *list = $3; 131 struct list_head *list = $3;
125 132
133 inc_group_count(list, _data);
126 parse_events__set_leader($1, list); 134 parse_events__set_leader($1, list);
127 $$ = list; 135 $$ = list;
128} 136}
@@ -131,6 +139,7 @@ PE_NAME '{' events '}'
131{ 139{
132 struct list_head *list = $2; 140 struct list_head *list = $2;
133 141
142 inc_group_count(list, _data);
134 parse_events__set_leader(NULL, list); 143 parse_events__set_leader(NULL, list);
135 $$ = list; 144 $$ = list;
136} 145}
@@ -186,7 +195,7 @@ event_def: event_pmu |
186event_pmu: 195event_pmu:
187PE_NAME '/' event_config '/' 196PE_NAME '/' event_config '/'
188{ 197{
189 struct parse_events_data__events *data = _data; 198 struct parse_events_evlist *data = _data;
190 struct list_head *list = NULL; 199 struct list_head *list = NULL;
191 200
192 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); 201 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
@@ -202,7 +211,7 @@ PE_VALUE_SYM_SW
202event_legacy_symbol: 211event_legacy_symbol:
203value_sym '/' event_config '/' 212value_sym '/' event_config '/'
204{ 213{
205 struct parse_events_data__events *data = _data; 214 struct parse_events_evlist *data = _data;
206 struct list_head *list = NULL; 215 struct list_head *list = NULL;
207 int type = $1 >> 16; 216 int type = $1 >> 16;
208 int config = $1 & 255; 217 int config = $1 & 255;
@@ -215,7 +224,7 @@ value_sym '/' event_config '/'
215| 224|
216value_sym sep_slash_dc 225value_sym sep_slash_dc
217{ 226{
218 struct parse_events_data__events *data = _data; 227 struct parse_events_evlist *data = _data;
219 struct list_head *list = NULL; 228 struct list_head *list = NULL;
220 int type = $1 >> 16; 229 int type = $1 >> 16;
221 int config = $1 & 255; 230 int config = $1 & 255;
@@ -228,7 +237,7 @@ value_sym sep_slash_dc
228event_legacy_cache: 237event_legacy_cache:
229PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
230{ 239{
231 struct parse_events_data__events *data = _data; 240 struct parse_events_evlist *data = _data;
232 struct list_head *list = NULL; 241 struct list_head *list = NULL;
233 242
234 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); 243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
@@ -237,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
237| 246|
238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 247PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
239{ 248{
240 struct parse_events_data__events *data = _data; 249 struct parse_events_evlist *data = _data;
241 struct list_head *list = NULL; 250 struct list_head *list = NULL;
242 251
243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); 252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
@@ -246,7 +255,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
246| 255|
247PE_NAME_CACHE_TYPE 256PE_NAME_CACHE_TYPE
248{ 257{
249 struct parse_events_data__events *data = _data; 258 struct parse_events_evlist *data = _data;
250 struct list_head *list = NULL; 259 struct list_head *list = NULL;
251 260
252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); 261 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
@@ -256,7 +265,7 @@ PE_NAME_CACHE_TYPE
256event_legacy_mem: 265event_legacy_mem:
257PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 266PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
258{ 267{
259 struct parse_events_data__events *data = _data; 268 struct parse_events_evlist *data = _data;
260 struct list_head *list = NULL; 269 struct list_head *list = NULL;
261 270
262 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 271 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -266,7 +275,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
266| 275|
267PE_PREFIX_MEM PE_VALUE sep_dc 276PE_PREFIX_MEM PE_VALUE sep_dc
268{ 277{
269 struct parse_events_data__events *data = _data; 278 struct parse_events_evlist *data = _data;
270 struct list_head *list = NULL; 279 struct list_head *list = NULL;
271 280
272 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 281 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -277,7 +286,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
277event_legacy_tracepoint: 286event_legacy_tracepoint:
278PE_NAME ':' PE_NAME 287PE_NAME ':' PE_NAME
279{ 288{
280 struct parse_events_data__events *data = _data; 289 struct parse_events_evlist *data = _data;
281 struct list_head *list = NULL; 290 struct list_head *list = NULL;
282 291
283 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); 292 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
@@ -287,7 +296,7 @@ PE_NAME ':' PE_NAME
287event_legacy_numeric: 296event_legacy_numeric:
288PE_VALUE ':' PE_VALUE 297PE_VALUE ':' PE_VALUE
289{ 298{
290 struct parse_events_data__events *data = _data; 299 struct parse_events_evlist *data = _data;
291 struct list_head *list = NULL; 300 struct list_head *list = NULL;
292 301
293 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); 302 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
@@ -297,7 +306,7 @@ PE_VALUE ':' PE_VALUE
297event_legacy_raw: 306event_legacy_raw:
298PE_RAW 307PE_RAW
299{ 308{
300 struct parse_events_data__events *data = _data; 309 struct parse_events_evlist *data = _data;
301 struct list_head *list = NULL; 310 struct list_head *list = NULL;
302 311
303 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 312 ABORT_ON(parse_events_add_numeric(&list, &data->idx,
@@ -307,7 +316,7 @@ PE_RAW
307 316
308start_terms: event_config 317start_terms: event_config
309{ 318{
310 struct parse_events_data__terms *data = _data; 319 struct parse_events_terms *data = _data;
311 data->terms = $1; 320 data->terms = $1;
312} 321}
313 322
@@ -315,7 +324,7 @@ event_config:
315event_config ',' event_term 324event_config ',' event_term
316{ 325{
317 struct list_head *head = $1; 326 struct list_head *head = $1;
318 struct parse_events__term *term = $3; 327 struct parse_events_term *term = $3;
319 328
320 ABORT_ON(!head); 329 ABORT_ON(!head);
321 list_add_tail(&term->list, head); 330 list_add_tail(&term->list, head);
@@ -325,7 +334,7 @@ event_config ',' event_term
325event_term 334event_term
326{ 335{
327 struct list_head *head = malloc(sizeof(*head)); 336 struct list_head *head = malloc(sizeof(*head));
328 struct parse_events__term *term = $1; 337 struct parse_events_term *term = $1;
329 338
330 ABORT_ON(!head); 339 ABORT_ON(!head);
331 INIT_LIST_HEAD(head); 340 INIT_LIST_HEAD(head);
@@ -336,70 +345,70 @@ event_term
336event_term: 345event_term:
337PE_NAME '=' PE_NAME 346PE_NAME '=' PE_NAME
338{ 347{
339 struct parse_events__term *term; 348 struct parse_events_term *term;
340 349
341 ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER, 350 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
342 $1, $3)); 351 $1, $3));
343 $$ = term; 352 $$ = term;
344} 353}
345| 354|
346PE_NAME '=' PE_VALUE 355PE_NAME '=' PE_VALUE
347{ 356{
348 struct parse_events__term *term; 357 struct parse_events_term *term;
349 358
350 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 359 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
351 $1, $3)); 360 $1, $3));
352 $$ = term; 361 $$ = term;
353} 362}
354| 363|
355PE_NAME '=' PE_VALUE_SYM_HW 364PE_NAME '=' PE_VALUE_SYM_HW
356{ 365{
357 struct parse_events__term *term; 366 struct parse_events_term *term;
358 int config = $3 & 255; 367 int config = $3 & 255;
359 368
360 ABORT_ON(parse_events__term_sym_hw(&term, $1, config)); 369 ABORT_ON(parse_events_term__sym_hw(&term, $1, config));
361 $$ = term; 370 $$ = term;
362} 371}
363| 372|
364PE_NAME 373PE_NAME
365{ 374{
366 struct parse_events__term *term; 375 struct parse_events_term *term;
367 376
368 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 377 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
369 $1, 1)); 378 $1, 1));
370 $$ = term; 379 $$ = term;
371} 380}
372| 381|
373PE_VALUE_SYM_HW 382PE_VALUE_SYM_HW
374{ 383{
375 struct parse_events__term *term; 384 struct parse_events_term *term;
376 int config = $1 & 255; 385 int config = $1 & 255;
377 386
378 ABORT_ON(parse_events__term_sym_hw(&term, NULL, config)); 387 ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
379 $$ = term; 388 $$ = term;
380} 389}
381| 390|
382PE_TERM '=' PE_NAME 391PE_TERM '=' PE_NAME
383{ 392{
384 struct parse_events__term *term; 393 struct parse_events_term *term;
385 394
386 ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3)); 395 ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3));
387 $$ = term; 396 $$ = term;
388} 397}
389| 398|
390PE_TERM '=' PE_VALUE 399PE_TERM '=' PE_VALUE
391{ 400{
392 struct parse_events__term *term; 401 struct parse_events_term *term;
393 402
394 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3)); 403 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3));
395 $$ = term; 404 $$ = term;
396} 405}
397| 406|
398PE_TERM 407PE_TERM
399{ 408{
400 struct parse_events__term *term; 409 struct parse_events_term *term;
401 410
402 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1)); 411 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1));
403 $$ = term; 412 $$ = term;
404} 413}
405 414
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 9bdc60c6f138..4c6f9c490a8d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1,4 +1,3 @@
1
2#include <linux/list.h> 1#include <linux/list.h>
3#include <sys/types.h> 2#include <sys/types.h>
4#include <sys/stat.h> 3#include <sys/stat.h>
@@ -11,6 +10,19 @@
11#include "parse-events.h" 10#include "parse-events.h"
12#include "cpumap.h" 11#include "cpumap.h"
13 12
13struct perf_pmu_alias {
14 char *name;
15 struct list_head terms;
16 struct list_head list;
17};
18
19struct perf_pmu_format {
20 char *name;
21 int value;
22 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
23 struct list_head list;
24};
25
14#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 26#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
15 27
16int perf_pmu_parse(struct list_head *list, char *name); 28int perf_pmu_parse(struct list_head *list, char *name);
@@ -85,7 +97,7 @@ static int pmu_format(char *name, struct list_head *format)
85 97
86static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) 98static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
87{ 99{
88 struct perf_pmu__alias *alias; 100 struct perf_pmu_alias *alias;
89 char buf[256]; 101 char buf[256];
90 int ret; 102 int ret;
91 103
@@ -172,15 +184,15 @@ static int pmu_aliases(char *name, struct list_head *head)
172 return 0; 184 return 0;
173} 185}
174 186
175static int pmu_alias_terms(struct perf_pmu__alias *alias, 187static int pmu_alias_terms(struct perf_pmu_alias *alias,
176 struct list_head *terms) 188 struct list_head *terms)
177{ 189{
178 struct parse_events__term *term, *clone; 190 struct parse_events_term *term, *clone;
179 LIST_HEAD(list); 191 LIST_HEAD(list);
180 int ret; 192 int ret;
181 193
182 list_for_each_entry(term, &alias->terms, list) { 194 list_for_each_entry(term, &alias->terms, list) {
183 ret = parse_events__term_clone(&clone, term); 195 ret = parse_events_term__clone(&clone, term);
184 if (ret) { 196 if (ret) {
185 parse_events__free_terms(&list); 197 parse_events__free_terms(&list);
186 return ret; 198 return ret;
@@ -360,10 +372,10 @@ struct perf_pmu *perf_pmu__find(char *name)
360 return pmu_lookup(name); 372 return pmu_lookup(name);
361} 373}
362 374
363static struct perf_pmu__format* 375static struct perf_pmu_format *
364pmu_find_format(struct list_head *formats, char *name) 376pmu_find_format(struct list_head *formats, char *name)
365{ 377{
366 struct perf_pmu__format *format; 378 struct perf_pmu_format *format;
367 379
368 list_for_each_entry(format, formats, list) 380 list_for_each_entry(format, formats, list)
369 if (!strcmp(format->name, name)) 381 if (!strcmp(format->name, name))
@@ -403,9 +415,9 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
403 */ 415 */
404static int pmu_config_term(struct list_head *formats, 416static int pmu_config_term(struct list_head *formats,
405 struct perf_event_attr *attr, 417 struct perf_event_attr *attr,
406 struct parse_events__term *term) 418 struct parse_events_term *term)
407{ 419{
408 struct perf_pmu__format *format; 420 struct perf_pmu_format *format;
409 __u64 *vp; 421 __u64 *vp;
410 422
411 /* 423 /*
@@ -450,7 +462,7 @@ int perf_pmu__config_terms(struct list_head *formats,
450 struct perf_event_attr *attr, 462 struct perf_event_attr *attr,
451 struct list_head *head_terms) 463 struct list_head *head_terms)
452{ 464{
453 struct parse_events__term *term; 465 struct parse_events_term *term;
454 466
455 list_for_each_entry(term, head_terms, list) 467 list_for_each_entry(term, head_terms, list)
456 if (pmu_config_term(formats, attr, term)) 468 if (pmu_config_term(formats, attr, term))
@@ -471,10 +483,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
471 return perf_pmu__config_terms(&pmu->format, attr, head_terms); 483 return perf_pmu__config_terms(&pmu->format, attr, head_terms);
472} 484}
473 485
474static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, 486static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
475 struct parse_events__term *term) 487 struct parse_events_term *term)
476{ 488{
477 struct perf_pmu__alias *alias; 489 struct perf_pmu_alias *alias;
478 char *name; 490 char *name;
479 491
480 if (parse_events__is_hardcoded_term(term)) 492 if (parse_events__is_hardcoded_term(term))
@@ -507,8 +519,8 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
507 */ 519 */
508int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) 520int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
509{ 521{
510 struct parse_events__term *term, *h; 522 struct parse_events_term *term, *h;
511 struct perf_pmu__alias *alias; 523 struct perf_pmu_alias *alias;
512 int ret; 524 int ret;
513 525
514 list_for_each_entry_safe(term, h, head_terms, list) { 526 list_for_each_entry_safe(term, h, head_terms, list) {
@@ -527,7 +539,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
527int perf_pmu__new_format(struct list_head *list, char *name, 539int perf_pmu__new_format(struct list_head *list, char *name,
528 int config, unsigned long *bits) 540 int config, unsigned long *bits)
529{ 541{
530 struct perf_pmu__format *format; 542 struct perf_pmu_format *format;
531 543
532 format = zalloc(sizeof(*format)); 544 format = zalloc(sizeof(*format));
533 if (!format) 545 if (!format)
@@ -548,7 +560,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
548 if (!to) 560 if (!to)
549 to = from; 561 to = from;
550 562
551 memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS)); 563 memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
552 for (b = from; b <= to; b++) 564 for (b = from; b <= to; b++)
553 set_bit(b, bits); 565 set_bit(b, bits);
554} 566}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index a313ed76a49a..32fe55b659fa 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -12,19 +12,6 @@ enum {
12 12
13#define PERF_PMU_FORMAT_BITS 64 13#define PERF_PMU_FORMAT_BITS 64
14 14
15struct perf_pmu__format {
16 char *name;
17 int value;
18 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
19 struct list_head list;
20};
21
22struct perf_pmu__alias {
23 char *name;
24 struct list_head terms;
25 struct list_head list;
26};
27
28struct perf_pmu { 15struct perf_pmu {
29 char *name; 16 char *name;
30 __u32 type; 17 __u32 type;
@@ -42,7 +29,7 @@ int perf_pmu__config_terms(struct list_head *formats,
42 struct list_head *head_terms); 29 struct list_head *head_terms);
43int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); 30int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
44struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 31struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
45 struct list_head *head_terms); 32 struct list_head *head_terms);
46int perf_pmu_wrap(void); 33int perf_pmu_wrap(void);
47void perf_pmu_error(struct list_head *list, char *name, char const *msg); 34void perf_pmu_error(struct list_head *list, char *name, char const *msg);
48 35
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
index ec898047ebb9..bfd7e8509869 100644
--- a/tools/perf/util/pmu.y
+++ b/tools/perf/util/pmu.y
@@ -1,5 +1,4 @@
1 1
2%name-prefix "perf_pmu_"
3%parse-param {struct list_head *format} 2%parse-param {struct list_head *format}
4%parse-param {char *name} 3%parse-param {char *name}
5 4
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 49a256e6e0a2..aa04bf9c9ad7 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -40,7 +40,7 @@
40#include "color.h" 40#include "color.h"
41#include "symbol.h" 41#include "symbol.h"
42#include "thread.h" 42#include "thread.h"
43#include "debugfs.h" 43#include <lk/debugfs.h>
44#include "trace-event.h" /* For __maybe_unused */ 44#include "trace-event.h" /* For __maybe_unused */
45#include "probe-event.h" 45#include "probe-event.h"
46#include "probe-finder.h" 46#include "probe-finder.h"
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 1daf5c14e751..be0329394d56 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -413,12 +413,12 @@ static int convert_variable_type(Dwarf_Die *vr_die,
413 dwarf_diename(vr_die), dwarf_diename(&type)); 413 dwarf_diename(vr_die), dwarf_diename(&type));
414 return -EINVAL; 414 return -EINVAL;
415 } 415 }
416 if (die_get_real_type(&type, &type) == NULL) {
417 pr_warning("Failed to get a type"
418 " information.\n");
419 return -ENOENT;
420 }
416 if (ret == DW_TAG_pointer_type) { 421 if (ret == DW_TAG_pointer_type) {
417 if (die_get_real_type(&type, &type) == NULL) {
418 pr_warning("Failed to get a type"
419 " information.\n");
420 return -ENOENT;
421 }
422 while (*ref_ptr) 422 while (*ref_ptr)
423 ref_ptr = &(*ref_ptr)->next; 423 ref_ptr = &(*ref_ptr)->next;
424 /* Add new reference with offset +0 */ 424 /* Add new reference with offset +0 */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index c40c2d33199e..f75ae1b9900c 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -15,7 +15,7 @@ util/thread_map.c
15util/util.c 15util/util.c
16util/xyarray.c 16util/xyarray.c
17util/cgroup.c 17util/cgroup.c
18util/debugfs.c
19util/rblist.c 18util/rblist.c
20util/strlist.c 19util/strlist.c
20util/sysfs.c
21../../lib/rbtree.c 21../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index a2657fd96837..925e0c3e6d91 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -1045,3 +1045,12 @@ error:
1045 if (PyErr_Occurred()) 1045 if (PyErr_Occurred())
1046 PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); 1046 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
1047} 1047}
1048
1049/*
1050 * Dummy, to avoid dragging all the test_attr infrastructure in the python
1051 * binding.
1052 */
1053void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
1054 int fd, int group_fd, unsigned long flags)
1055{
1056}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index f80605eb1855..eacec859f299 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -292,6 +292,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
292 ns = nsecs - s * NSECS_PER_SEC; 292 ns = nsecs - s * NSECS_PER_SEC;
293 293
294 scripting_context->event_data = data; 294 scripting_context->event_data = data;
295 scripting_context->pevent = evsel->tp_format->pevent;
295 296
296 ENTER; 297 ENTER;
297 SAVETMPS; 298 SAVETMPS;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 14683dfca2ee..e87aa5d9696b 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -265,6 +265,7 @@ static void python_process_tracepoint(union perf_event *perf_event
265 ns = nsecs - s * NSECS_PER_SEC; 265 ns = nsecs - s * NSECS_PER_SEC;
266 266
267 scripting_context->event_data = data; 267 scripting_context->event_data = data;
268 scripting_context->pevent = evsel->tp_format->pevent;
268 269
269 context = PyCObject_FromVoidPtr(scripting_context, NULL); 270 context = PyCObject_FromVoidPtr(scripting_context, NULL);
270 271
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ce6f51162386..cf1fe01b7e89 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,5 +1,3 @@
1#define _FILE_OFFSET_BITS 64
2
3#include <linux/kernel.h> 1#include <linux/kernel.h>
4 2
5#include <byteswap.h> 3#include <byteswap.h>
@@ -16,7 +14,6 @@
16#include "cpumap.h" 14#include "cpumap.h"
17#include "event-parse.h" 15#include "event-parse.h"
18#include "perf_regs.h" 16#include "perf_regs.h"
19#include "unwind.h"
20#include "vdso.h" 17#include "vdso.h"
21 18
22static int perf_session__open(struct perf_session *self, bool force) 19static int perf_session__open(struct perf_session *self, bool force)
@@ -87,13 +84,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
87{ 84{
88 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); 85 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
89 86
90 session->host_machine.id_hdr_size = id_hdr_size;
91 machines__set_id_hdr_size(&session->machines, id_hdr_size); 87 machines__set_id_hdr_size(&session->machines, id_hdr_size);
92} 88}
93 89
94int perf_session__create_kernel_maps(struct perf_session *self) 90int perf_session__create_kernel_maps(struct perf_session *self)
95{ 91{
96 int ret = machine__create_kernel_maps(&self->host_machine); 92 int ret = machine__create_kernel_maps(&self->machines.host);
97 93
98 if (ret >= 0) 94 if (ret >= 0)
99 ret = machines__create_guest_kernel_maps(&self->machines); 95 ret = machines__create_guest_kernel_maps(&self->machines);
@@ -102,8 +98,7 @@ int perf_session__create_kernel_maps(struct perf_session *self)
102 98
103static void perf_session__destroy_kernel_maps(struct perf_session *self) 99static void perf_session__destroy_kernel_maps(struct perf_session *self)
104{ 100{
105 machine__destroy_kernel_maps(&self->host_machine); 101 machines__destroy_kernel_maps(&self->machines);
106 machines__destroy_guest_kernel_maps(&self->machines);
107} 102}
108 103
109struct perf_session *perf_session__new(const char *filename, int mode, 104struct perf_session *perf_session__new(const char *filename, int mode,
@@ -128,22 +123,11 @@ struct perf_session *perf_session__new(const char *filename, int mode,
128 goto out; 123 goto out;
129 124
130 memcpy(self->filename, filename, len); 125 memcpy(self->filename, filename, len);
131 /*
132 * On 64bit we can mmap the data file in one go. No need for tiny mmap
133 * slices. On 32bit we use 32MB.
134 */
135#if BITS_PER_LONG == 64
136 self->mmap_window = ULLONG_MAX;
137#else
138 self->mmap_window = 32 * 1024 * 1024ULL;
139#endif
140 self->machines = RB_ROOT;
141 self->repipe = repipe; 126 self->repipe = repipe;
142 INIT_LIST_HEAD(&self->ordered_samples.samples); 127 INIT_LIST_HEAD(&self->ordered_samples.samples);
143 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 128 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
144 INIT_LIST_HEAD(&self->ordered_samples.to_free); 129 INIT_LIST_HEAD(&self->ordered_samples.to_free);
145 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 130 machines__init(&self->machines);
146 hists__init(&self->hists);
147 131
148 if (mode == O_RDONLY) { 132 if (mode == O_RDONLY) {
149 if (perf_session__open(self, force) < 0) 133 if (perf_session__open(self, force) < 0)
@@ -171,37 +155,30 @@ out_delete:
171 return NULL; 155 return NULL;
172} 156}
173 157
174static void machine__delete_dead_threads(struct machine *machine)
175{
176 struct thread *n, *t;
177
178 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
179 list_del(&t->node);
180 thread__delete(t);
181 }
182}
183
184static void perf_session__delete_dead_threads(struct perf_session *session) 158static void perf_session__delete_dead_threads(struct perf_session *session)
185{ 159{
186 machine__delete_dead_threads(&session->host_machine); 160 machine__delete_dead_threads(&session->machines.host);
187} 161}
188 162
189static void machine__delete_threads(struct machine *self) 163static void perf_session__delete_threads(struct perf_session *session)
190{ 164{
191 struct rb_node *nd = rb_first(&self->threads); 165 machine__delete_threads(&session->machines.host);
192
193 while (nd) {
194 struct thread *t = rb_entry(nd, struct thread, rb_node);
195
196 rb_erase(&t->rb_node, &self->threads);
197 nd = rb_next(nd);
198 thread__delete(t);
199 }
200} 166}
201 167
202static void perf_session__delete_threads(struct perf_session *session) 168static void perf_session_env__delete(struct perf_session_env *env)
203{ 169{
204 machine__delete_threads(&session->host_machine); 170 free(env->hostname);
171 free(env->os_release);
172 free(env->version);
173 free(env->arch);
174 free(env->cpu_desc);
175 free(env->cpuid);
176
177 free(env->cmdline);
178 free(env->sibling_cores);
179 free(env->sibling_threads);
180 free(env->numa_nodes);
181 free(env->pmu_mappings);
205} 182}
206 183
207void perf_session__delete(struct perf_session *self) 184void perf_session__delete(struct perf_session *self)
@@ -209,198 +186,13 @@ void perf_session__delete(struct perf_session *self)
209 perf_session__destroy_kernel_maps(self); 186 perf_session__destroy_kernel_maps(self);
210 perf_session__delete_dead_threads(self); 187 perf_session__delete_dead_threads(self);
211 perf_session__delete_threads(self); 188 perf_session__delete_threads(self);
212 machine__exit(&self->host_machine); 189 perf_session_env__delete(&self->header.env);
190 machines__exit(&self->machines);
213 close(self->fd); 191 close(self->fd);
214 free(self); 192 free(self);
215 vdso__exit(); 193 vdso__exit();
216} 194}
217 195
218void machine__remove_thread(struct machine *self, struct thread *th)
219{
220 self->last_match = NULL;
221 rb_erase(&th->rb_node, &self->threads);
222 /*
223 * We may have references to this thread, for instance in some hist_entry
224 * instances, so just move them to a separate list.
225 */
226 list_add_tail(&th->node, &self->dead_threads);
227}
228
229static bool symbol__match_parent_regex(struct symbol *sym)
230{
231 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
232 return 1;
233
234 return 0;
235}
236
237static const u8 cpumodes[] = {
238 PERF_RECORD_MISC_USER,
239 PERF_RECORD_MISC_KERNEL,
240 PERF_RECORD_MISC_GUEST_USER,
241 PERF_RECORD_MISC_GUEST_KERNEL
242};
243#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
244
245static void ip__resolve_ams(struct machine *self, struct thread *thread,
246 struct addr_map_symbol *ams,
247 u64 ip)
248{
249 struct addr_location al;
250 size_t i;
251 u8 m;
252
253 memset(&al, 0, sizeof(al));
254
255 for (i = 0; i < NCPUMODES; i++) {
256 m = cpumodes[i];
257 /*
258 * We cannot use the header.misc hint to determine whether a
259 * branch stack address is user, kernel, guest, hypervisor.
260 * Branches may straddle the kernel/user/hypervisor boundaries.
261 * Thus, we have to try consecutively until we find a match
262 * or else, the symbol is unknown
263 */
264 thread__find_addr_location(thread, self, m, MAP__FUNCTION,
265 ip, &al, NULL);
266 if (al.sym)
267 goto found;
268 }
269found:
270 ams->addr = ip;
271 ams->al_addr = al.addr;
272 ams->sym = al.sym;
273 ams->map = al.map;
274}
275
276struct branch_info *machine__resolve_bstack(struct machine *self,
277 struct thread *thr,
278 struct branch_stack *bs)
279{
280 struct branch_info *bi;
281 unsigned int i;
282
283 bi = calloc(bs->nr, sizeof(struct branch_info));
284 if (!bi)
285 return NULL;
286
287 for (i = 0; i < bs->nr; i++) {
288 ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
289 ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
290 bi[i].flags = bs->entries[i].flags;
291 }
292 return bi;
293}
294
295static int machine__resolve_callchain_sample(struct machine *machine,
296 struct thread *thread,
297 struct ip_callchain *chain,
298 struct symbol **parent)
299
300{
301 u8 cpumode = PERF_RECORD_MISC_USER;
302 unsigned int i;
303 int err;
304
305 callchain_cursor_reset(&callchain_cursor);
306
307 if (chain->nr > PERF_MAX_STACK_DEPTH) {
308 pr_warning("corrupted callchain. skipping...\n");
309 return 0;
310 }
311
312 for (i = 0; i < chain->nr; i++) {
313 u64 ip;
314 struct addr_location al;
315
316 if (callchain_param.order == ORDER_CALLEE)
317 ip = chain->ips[i];
318 else
319 ip = chain->ips[chain->nr - i - 1];
320
321 if (ip >= PERF_CONTEXT_MAX) {
322 switch (ip) {
323 case PERF_CONTEXT_HV:
324 cpumode = PERF_RECORD_MISC_HYPERVISOR;
325 break;
326 case PERF_CONTEXT_KERNEL:
327 cpumode = PERF_RECORD_MISC_KERNEL;
328 break;
329 case PERF_CONTEXT_USER:
330 cpumode = PERF_RECORD_MISC_USER;
331 break;
332 default:
333 pr_debug("invalid callchain context: "
334 "%"PRId64"\n", (s64) ip);
335 /*
336 * It seems the callchain is corrupted.
337 * Discard all.
338 */
339 callchain_cursor_reset(&callchain_cursor);
340 return 0;
341 }
342 continue;
343 }
344
345 al.filtered = false;
346 thread__find_addr_location(thread, machine, cpumode,
347 MAP__FUNCTION, ip, &al, NULL);
348 if (al.sym != NULL) {
349 if (sort__has_parent && !*parent &&
350 symbol__match_parent_regex(al.sym))
351 *parent = al.sym;
352 if (!symbol_conf.use_callchain)
353 break;
354 }
355
356 err = callchain_cursor_append(&callchain_cursor,
357 ip, al.map, al.sym);
358 if (err)
359 return err;
360 }
361
362 return 0;
363}
364
365static int unwind_entry(struct unwind_entry *entry, void *arg)
366{
367 struct callchain_cursor *cursor = arg;
368 return callchain_cursor_append(cursor, entry->ip,
369 entry->map, entry->sym);
370}
371
372int machine__resolve_callchain(struct machine *machine,
373 struct perf_evsel *evsel,
374 struct thread *thread,
375 struct perf_sample *sample,
376 struct symbol **parent)
377
378{
379 int ret;
380
381 callchain_cursor_reset(&callchain_cursor);
382
383 ret = machine__resolve_callchain_sample(machine, thread,
384 sample->callchain, parent);
385 if (ret)
386 return ret;
387
388 /* Can we do dwarf post unwind? */
389 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
390 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
391 return 0;
392
393 /* Bail out if nothing was captured. */
394 if ((!sample->user_regs.regs) ||
395 (!sample->user_stack.size))
396 return 0;
397
398 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
399 thread, evsel->attr.sample_regs_user,
400 sample);
401
402}
403
404static int process_event_synth_tracing_data_stub(union perf_event *event 196static int process_event_synth_tracing_data_stub(union perf_event *event
405 __maybe_unused, 197 __maybe_unused,
406 struct perf_session *session 198 struct perf_session *session
@@ -1006,6 +798,12 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
1006 798
1007 if (sample_type & PERF_SAMPLE_STACK_USER) 799 if (sample_type & PERF_SAMPLE_STACK_USER)
1008 stack_user__printf(&sample->user_stack); 800 stack_user__printf(&sample->user_stack);
801
802 if (sample_type & PERF_SAMPLE_WEIGHT)
803 printf("... weight: %" PRIu64 "\n", sample->weight);
804
805 if (sample_type & PERF_SAMPLE_DATA_SRC)
806 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
1009} 807}
1010 808
1011static struct machine * 809static struct machine *
@@ -1027,7 +825,7 @@ static struct machine *
1027 return perf_session__findnew_machine(session, pid); 825 return perf_session__findnew_machine(session, pid);
1028 } 826 }
1029 827
1030 return perf_session__find_host_machine(session); 828 return &session->machines.host;
1031} 829}
1032 830
1033static int perf_session_deliver_event(struct perf_session *session, 831static int perf_session_deliver_event(struct perf_session *session,
@@ -1065,11 +863,11 @@ static int perf_session_deliver_event(struct perf_session *session,
1065 case PERF_RECORD_SAMPLE: 863 case PERF_RECORD_SAMPLE:
1066 dump_sample(evsel, event, sample); 864 dump_sample(evsel, event, sample);
1067 if (evsel == NULL) { 865 if (evsel == NULL) {
1068 ++session->hists.stats.nr_unknown_id; 866 ++session->stats.nr_unknown_id;
1069 return 0; 867 return 0;
1070 } 868 }
1071 if (machine == NULL) { 869 if (machine == NULL) {
1072 ++session->hists.stats.nr_unprocessable_samples; 870 ++session->stats.nr_unprocessable_samples;
1073 return 0; 871 return 0;
1074 } 872 }
1075 return tool->sample(tool, event, sample, evsel, machine); 873 return tool->sample(tool, event, sample, evsel, machine);
@@ -1083,7 +881,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1083 return tool->exit(tool, event, sample, machine); 881 return tool->exit(tool, event, sample, machine);
1084 case PERF_RECORD_LOST: 882 case PERF_RECORD_LOST:
1085 if (tool->lost == perf_event__process_lost) 883 if (tool->lost == perf_event__process_lost)
1086 session->hists.stats.total_lost += event->lost.lost; 884 session->stats.total_lost += event->lost.lost;
1087 return tool->lost(tool, event, sample, machine); 885 return tool->lost(tool, event, sample, machine);
1088 case PERF_RECORD_READ: 886 case PERF_RECORD_READ:
1089 return tool->read(tool, event, sample, evsel, machine); 887 return tool->read(tool, event, sample, evsel, machine);
@@ -1092,7 +890,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1092 case PERF_RECORD_UNTHROTTLE: 890 case PERF_RECORD_UNTHROTTLE:
1093 return tool->unthrottle(tool, event, sample, machine); 891 return tool->unthrottle(tool, event, sample, machine);
1094 default: 892 default:
1095 ++session->hists.stats.nr_unknown_events; 893 ++session->stats.nr_unknown_events;
1096 return -1; 894 return -1;
1097 } 895 }
1098} 896}
@@ -1106,8 +904,8 @@ static int perf_session__preprocess_sample(struct perf_session *session,
1106 904
1107 if (!ip_callchain__valid(sample->callchain, event)) { 905 if (!ip_callchain__valid(sample->callchain, event)) {
1108 pr_debug("call-chain problem with event, skipping it.\n"); 906 pr_debug("call-chain problem with event, skipping it.\n");
1109 ++session->hists.stats.nr_invalid_chains; 907 ++session->stats.nr_invalid_chains;
1110 session->hists.stats.total_invalid_chains += sample->period; 908 session->stats.total_invalid_chains += sample->period;
1111 return -EINVAL; 909 return -EINVAL;
1112 } 910 }
1113 return 0; 911 return 0;
@@ -1165,7 +963,7 @@ static int perf_session__process_event(struct perf_session *session,
1165 if (event->header.type >= PERF_RECORD_HEADER_MAX) 963 if (event->header.type >= PERF_RECORD_HEADER_MAX)
1166 return -EINVAL; 964 return -EINVAL;
1167 965
1168 hists__inc_nr_events(&session->hists, event->header.type); 966 events_stats__inc(&session->stats, event->header.type);
1169 967
1170 if (event->header.type >= PERF_RECORD_USER_TYPE_START) 968 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
1171 return perf_session__process_user_event(session, event, tool, file_offset); 969 return perf_session__process_user_event(session, event, tool, file_offset);
@@ -1201,7 +999,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
1201 999
1202struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1000struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1203{ 1001{
1204 return machine__findnew_thread(&session->host_machine, pid); 1002 return machine__findnew_thread(&session->machines.host, pid);
1205} 1003}
1206 1004
1207static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1005static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1220,39 +1018,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1220 const struct perf_tool *tool) 1018 const struct perf_tool *tool)
1221{ 1019{
1222 if (tool->lost == perf_event__process_lost && 1020 if (tool->lost == perf_event__process_lost &&
1223 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { 1021 session->stats.nr_events[PERF_RECORD_LOST] != 0) {
1224 ui__warning("Processed %d events and lost %d chunks!\n\n" 1022 ui__warning("Processed %d events and lost %d chunks!\n\n"
1225 "Check IO/CPU overload!\n\n", 1023 "Check IO/CPU overload!\n\n",
1226 session->hists.stats.nr_events[0], 1024 session->stats.nr_events[0],
1227 session->hists.stats.nr_events[PERF_RECORD_LOST]); 1025 session->stats.nr_events[PERF_RECORD_LOST]);
1228 } 1026 }
1229 1027
1230 if (session->hists.stats.nr_unknown_events != 0) { 1028 if (session->stats.nr_unknown_events != 0) {
1231 ui__warning("Found %u unknown events!\n\n" 1029 ui__warning("Found %u unknown events!\n\n"
1232 "Is this an older tool processing a perf.data " 1030 "Is this an older tool processing a perf.data "
1233 "file generated by a more recent tool?\n\n" 1031 "file generated by a more recent tool?\n\n"
1234 "If that is not the case, consider " 1032 "If that is not the case, consider "
1235 "reporting to linux-kernel@vger.kernel.org.\n\n", 1033 "reporting to linux-kernel@vger.kernel.org.\n\n",
1236 session->hists.stats.nr_unknown_events); 1034 session->stats.nr_unknown_events);
1237 } 1035 }
1238 1036
1239 if (session->hists.stats.nr_unknown_id != 0) { 1037 if (session->stats.nr_unknown_id != 0) {
1240 ui__warning("%u samples with id not present in the header\n", 1038 ui__warning("%u samples with id not present in the header\n",
1241 session->hists.stats.nr_unknown_id); 1039 session->stats.nr_unknown_id);
1242 } 1040 }
1243 1041
1244 if (session->hists.stats.nr_invalid_chains != 0) { 1042 if (session->stats.nr_invalid_chains != 0) {
1245 ui__warning("Found invalid callchains!\n\n" 1043 ui__warning("Found invalid callchains!\n\n"
1246 "%u out of %u events were discarded for this reason.\n\n" 1044 "%u out of %u events were discarded for this reason.\n\n"
1247 "Consider reporting to linux-kernel@vger.kernel.org.\n\n", 1045 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
1248 session->hists.stats.nr_invalid_chains, 1046 session->stats.nr_invalid_chains,
1249 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); 1047 session->stats.nr_events[PERF_RECORD_SAMPLE]);
1250 } 1048 }
1251 1049
1252 if (session->hists.stats.nr_unprocessable_samples != 0) { 1050 if (session->stats.nr_unprocessable_samples != 0) {
1253 ui__warning("%u unprocessable samples recorded.\n" 1051 ui__warning("%u unprocessable samples recorded.\n"
1254 "Do you have a KVM guest running and not using 'perf kvm'?\n", 1052 "Do you have a KVM guest running and not using 'perf kvm'?\n",
1255 session->hists.stats.nr_unprocessable_samples); 1053 session->stats.nr_unprocessable_samples);
1256 } 1054 }
1257} 1055}
1258 1056
@@ -1369,6 +1167,18 @@ fetch_mmaped_event(struct perf_session *session,
1369 return event; 1167 return event;
1370} 1168}
1371 1169
1170/*
1171 * On 64bit we can mmap the data file in one go. No need for tiny mmap
1172 * slices. On 32bit we use 32MB.
1173 */
1174#if BITS_PER_LONG == 64
1175#define MMAP_SIZE ULLONG_MAX
1176#define NUM_MMAPS 1
1177#else
1178#define MMAP_SIZE (32 * 1024 * 1024ULL)
1179#define NUM_MMAPS 128
1180#endif
1181
1372int __perf_session__process_events(struct perf_session *session, 1182int __perf_session__process_events(struct perf_session *session,
1373 u64 data_offset, u64 data_size, 1183 u64 data_offset, u64 data_size,
1374 u64 file_size, struct perf_tool *tool) 1184 u64 file_size, struct perf_tool *tool)
@@ -1376,7 +1186,7 @@ int __perf_session__process_events(struct perf_session *session,
1376 u64 head, page_offset, file_offset, file_pos, progress_next; 1186 u64 head, page_offset, file_offset, file_pos, progress_next;
1377 int err, mmap_prot, mmap_flags, map_idx = 0; 1187 int err, mmap_prot, mmap_flags, map_idx = 0;
1378 size_t mmap_size; 1188 size_t mmap_size;
1379 char *buf, *mmaps[8]; 1189 char *buf, *mmaps[NUM_MMAPS];
1380 union perf_event *event; 1190 union perf_event *event;
1381 uint32_t size; 1191 uint32_t size;
1382 1192
@@ -1391,7 +1201,7 @@ int __perf_session__process_events(struct perf_session *session,
1391 1201
1392 progress_next = file_size / 16; 1202 progress_next = file_size / 16;
1393 1203
1394 mmap_size = session->mmap_window; 1204 mmap_size = MMAP_SIZE;
1395 if (mmap_size > file_size) 1205 if (mmap_size > file_size)
1396 mmap_size = file_size; 1206 mmap_size = file_size;
1397 1207
@@ -1526,16 +1336,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
1526 1336
1527size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) 1337size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
1528{ 1338{
1529 return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) + 1339 return machines__fprintf_dsos(&self->machines, fp);
1530 __dsos__fprintf(&self->host_machine.user_dsos, fp) +
1531 machines__fprintf_dsos(&self->machines, fp);
1532} 1340}
1533 1341
1534size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, 1342size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
1535 bool with_hits) 1343 bool (skip)(struct dso *dso, int parm), int parm)
1536{ 1344{
1537 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); 1345 return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
1538 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
1539} 1346}
1540 1347
1541size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) 1348size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
@@ -1543,11 +1350,11 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1543 struct perf_evsel *pos; 1350 struct perf_evsel *pos;
1544 size_t ret = fprintf(fp, "Aggregated stats:\n"); 1351 size_t ret = fprintf(fp, "Aggregated stats:\n");
1545 1352
1546 ret += hists__fprintf_nr_events(&session->hists, fp); 1353 ret += events_stats__fprintf(&session->stats, fp);
1547 1354
1548 list_for_each_entry(pos, &session->evlist->entries, node) { 1355 list_for_each_entry(pos, &session->evlist->entries, node) {
1549 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); 1356 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1550 ret += hists__fprintf_nr_events(&pos->hists, fp); 1357 ret += events_stats__fprintf(&pos->hists.stats, fp);
1551 } 1358 }
1552 1359
1553 return ret; 1360 return ret;
@@ -1559,19 +1366,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1559 * FIXME: Here we have to actually print all the machines in this 1366 * FIXME: Here we have to actually print all the machines in this
1560 * session, not just the host... 1367 * session, not just the host...
1561 */ 1368 */
1562 return machine__fprintf(&session->host_machine, fp); 1369 return machine__fprintf(&session->machines.host, fp);
1563}
1564
1565void perf_session__remove_thread(struct perf_session *session,
1566 struct thread *th)
1567{
1568 /*
1569 * FIXME: This one makes no sense, we need to remove the thread from
1570 * the machine it belongs to, perf_session can have many machines, so
1571 * doing it always on ->host_machine is wrong. Fix when auditing all
1572 * the 'perf kvm' code.
1573 */
1574 machine__remove_thread(&session->host_machine, th);
1575} 1370}
1576 1371
1577struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 1372struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index cea133a6bdf1..f3b235ec7bf4 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -30,20 +30,13 @@ struct ordered_samples {
30struct perf_session { 30struct perf_session {
31 struct perf_header header; 31 struct perf_header header;
32 unsigned long size; 32 unsigned long size;
33 unsigned long mmap_window; 33 struct machines machines;
34 struct machine host_machine;
35 struct rb_root machines;
36 struct perf_evlist *evlist; 34 struct perf_evlist *evlist;
37 struct pevent *pevent; 35 struct pevent *pevent;
38 /* 36 struct events_stats stats;
39 * FIXME: Need to split this up further, we need global
40 * stats + per event stats.
41 */
42 struct hists hists;
43 int fd; 37 int fd;
44 bool fd_pipe; 38 bool fd_pipe;
45 bool repipe; 39 bool repipe;
46 int cwdlen;
47 char *cwd; 40 char *cwd;
48 struct ordered_samples ordered_samples; 41 struct ordered_samples ordered_samples;
49 char filename[1]; 42 char filename[1];
@@ -54,7 +47,7 @@ struct perf_tool;
54struct perf_session *perf_session__new(const char *filename, int mode, 47struct perf_session *perf_session__new(const char *filename, int mode,
55 bool force, bool repipe, 48 bool force, bool repipe,
56 struct perf_tool *tool); 49 struct perf_tool *tool);
57void perf_session__delete(struct perf_session *self); 50void perf_session__delete(struct perf_session *session);
58 51
59void perf_event_header__bswap(struct perf_event_header *self); 52void perf_event_header__bswap(struct perf_event_header *self);
60 53
@@ -78,46 +71,26 @@ void perf_event__attr_swap(struct perf_event_attr *attr);
78int perf_session__create_kernel_maps(struct perf_session *self); 71int perf_session__create_kernel_maps(struct perf_session *self);
79 72
80void perf_session__set_id_hdr_size(struct perf_session *session); 73void perf_session__set_id_hdr_size(struct perf_session *session);
81void perf_session__remove_thread(struct perf_session *self, struct thread *th);
82
83static inline
84struct machine *perf_session__find_host_machine(struct perf_session *self)
85{
86 return &self->host_machine;
87}
88 74
89static inline 75static inline
90struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) 76struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
91{ 77{
92 if (pid == HOST_KERNEL_ID)
93 return &self->host_machine;
94 return machines__find(&self->machines, pid); 78 return machines__find(&self->machines, pid);
95} 79}
96 80
97static inline 81static inline
98struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) 82struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
99{ 83{
100 if (pid == HOST_KERNEL_ID)
101 return &self->host_machine;
102 return machines__findnew(&self->machines, pid); 84 return machines__findnew(&self->machines, pid);
103} 85}
104 86
105static inline
106void perf_session__process_machines(struct perf_session *self,
107 struct perf_tool *tool,
108 machine__process_t process)
109{
110 process(&self->host_machine, tool);
111 return machines__process(&self->machines, process, tool);
112}
113
114struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 87struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
115size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 88size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
116 89
117size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 90size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
118 91
119size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 92size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
120 FILE *fp, bool with_hits); 93 bool (fn)(struct dso *dso, int parm), int parm);
121 94
122size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); 95size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
123 96
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 73d510269784..58ea5ca6c255 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -18,12 +18,14 @@ class install_lib(_install_lib):
18 self.build_dir = build_lib 18 self.build_dir = build_lib
19 19
20 20
21cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] 21cflags = getenv('CFLAGS', '').split()
22cflags += getenv('CFLAGS', '').split() 22# switch off several checks (need to be at the end of cflags list)
23cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ]
23 24
24build_lib = getenv('PYTHON_EXTBUILD_LIB') 25build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP') 26build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26libtraceevent = getenv('LIBTRACEEVENT') 27libtraceevent = getenv('LIBTRACEEVENT')
28liblk = getenv('LIBLK')
27 29
28ext_sources = [f.strip() for f in file('util/python-ext-sources') 30ext_sources = [f.strip() for f in file('util/python-ext-sources')
29 if len(f.strip()) > 0 and f[0] != '#'] 31 if len(f.strip()) > 0 and f[0] != '#']
@@ -32,7 +34,7 @@ perf = Extension('perf',
32 sources = ext_sources, 34 sources = ext_sources,
33 include_dirs = ['util/include'], 35 include_dirs = ['util/include'],
34 extra_compile_args = cflags, 36 extra_compile_args = cflags,
35 extra_objects = [libtraceevent], 37 extra_objects = [libtraceevent, liblk],
36 ) 38 )
37 39
38setup(name='perf', 40setup(name='perf',
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cfd1c0feb32d..313a5a730112 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,5 +1,6 @@
1#include "sort.h" 1#include "sort.h"
2#include "hist.h" 2#include "hist.h"
3#include "symbol.h"
3 4
4regex_t parent_regex; 5regex_t parent_regex;
5const char default_parent_pattern[] = "^sys_|^do_page_fault"; 6const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -9,7 +10,7 @@ const char *sort_order = default_sort_order;
9int sort__need_collapse = 0; 10int sort__need_collapse = 0;
10int sort__has_parent = 0; 11int sort__has_parent = 0;
11int sort__has_sym = 0; 12int sort__has_sym = 0;
12int sort__branch_mode = -1; /* -1 = means not set */ 13enum sort_mode sort__mode = SORT_MODE__NORMAL;
13 14
14enum sort_type sort__first_dimension; 15enum sort_type sort__first_dimension;
15 16
@@ -60,7 +61,7 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
60static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 61static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
61 size_t size, unsigned int width) 62 size_t size, unsigned int width)
62{ 63{
63 return repsep_snprintf(bf, size, "%*s:%5d", width, 64 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
64 self->thread->comm ?: "", self->thread->pid); 65 self->thread->comm ?: "", self->thread->pid);
65} 66}
66 67
@@ -97,6 +98,16 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
97 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 98 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
98} 99}
99 100
101struct sort_entry sort_comm = {
102 .se_header = "Command",
103 .se_cmp = sort__comm_cmp,
104 .se_collapse = sort__comm_collapse,
105 .se_snprintf = hist_entry__comm_snprintf,
106 .se_width_idx = HISTC_COMM,
107};
108
109/* --sort dso */
110
100static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) 111static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
101{ 112{
102 struct dso *dso_l = map_l ? map_l->dso : NULL; 113 struct dso *dso_l = map_l ? map_l->dso : NULL;
@@ -117,40 +128,12 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
117 return strcmp(dso_name_l, dso_name_r); 128 return strcmp(dso_name_l, dso_name_r);
118} 129}
119 130
120struct sort_entry sort_comm = {
121 .se_header = "Command",
122 .se_cmp = sort__comm_cmp,
123 .se_collapse = sort__comm_collapse,
124 .se_snprintf = hist_entry__comm_snprintf,
125 .se_width_idx = HISTC_COMM,
126};
127
128/* --sort dso */
129
130static int64_t 131static int64_t
131sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
132{ 133{
133 return _sort__dso_cmp(left->ms.map, right->ms.map); 134 return _sort__dso_cmp(left->ms.map, right->ms.map);
134} 135}
135 136
136
137static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
138 u64 ip_l, u64 ip_r)
139{
140 if (!sym_l || !sym_r)
141 return cmp_null(sym_l, sym_r);
142
143 if (sym_l == sym_r)
144 return 0;
145
146 if (sym_l)
147 ip_l = sym_l->start;
148 if (sym_r)
149 ip_r = sym_r->start;
150
151 return (int64_t)(ip_r - ip_l);
152}
153
154static int _hist_entry__dso_snprintf(struct map *map, char *bf, 137static int _hist_entry__dso_snprintf(struct map *map, char *bf,
155 size_t size, unsigned int width) 138 size_t size, unsigned int width)
156{ 139{
@@ -169,24 +152,66 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
169 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); 152 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
170} 153}
171 154
155struct sort_entry sort_dso = {
156 .se_header = "Shared Object",
157 .se_cmp = sort__dso_cmp,
158 .se_snprintf = hist_entry__dso_snprintf,
159 .se_width_idx = HISTC_DSO,
160};
161
162/* --sort symbol */
163
164static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
165{
166 u64 ip_l, ip_r;
167
168 if (!sym_l || !sym_r)
169 return cmp_null(sym_l, sym_r);
170
171 if (sym_l == sym_r)
172 return 0;
173
174 ip_l = sym_l->start;
175 ip_r = sym_r->start;
176
177 return (int64_t)(ip_r - ip_l);
178}
179
180static int64_t
181sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
182{
183 if (!left->ms.sym && !right->ms.sym)
184 return right->level - left->level;
185
186 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
187}
188
172static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 189static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
173 u64 ip, char level, char *bf, size_t size, 190 u64 ip, char level, char *bf, size_t size,
174 unsigned int width __maybe_unused) 191 unsigned int width)
175{ 192{
176 size_t ret = 0; 193 size_t ret = 0;
177 194
178 if (verbose) { 195 if (verbose) {
179 char o = map ? dso__symtab_origin(map->dso) : '!'; 196 char o = map ? dso__symtab_origin(map->dso) : '!';
180 ret += repsep_snprintf(bf, size, "%-#*llx %c ", 197 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
181 BITS_PER_LONG / 4, ip, o); 198 BITS_PER_LONG / 4 + 2, ip, o);
182 } 199 }
183 200
184 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); 201 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
185 if (sym) 202 if (sym && map) {
186 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 203 if (map->type == MAP__VARIABLE) {
187 width - ret, 204 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
188 sym->name); 205 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
189 else { 206 ip - map->unmap_ip(map, sym->start));
207 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
208 width - ret, "");
209 } else {
210 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
211 width - ret,
212 sym->name);
213 }
214 } else {
190 size_t len = BITS_PER_LONG / 4; 215 size_t len = BITS_PER_LONG / 4;
191 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 216 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
192 len, ip); 217 len, ip);
@@ -197,43 +222,13 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
197 return ret; 222 return ret;
198} 223}
199 224
200
201struct sort_entry sort_dso = {
202 .se_header = "Shared Object",
203 .se_cmp = sort__dso_cmp,
204 .se_snprintf = hist_entry__dso_snprintf,
205 .se_width_idx = HISTC_DSO,
206};
207
208static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, 225static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
209 size_t size, 226 size_t size, unsigned int width)
210 unsigned int width __maybe_unused)
211{ 227{
212 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, 228 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
213 self->level, bf, size, width); 229 self->level, bf, size, width);
214} 230}
215 231
216/* --sort symbol */
217static int64_t
218sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
219{
220 u64 ip_l, ip_r;
221
222 if (!left->ms.sym && !right->ms.sym)
223 return right->level - left->level;
224
225 if (!left->ms.sym || !right->ms.sym)
226 return cmp_null(left->ms.sym, right->ms.sym);
227
228 if (left->ms.sym == right->ms.sym)
229 return 0;
230
231 ip_l = left->ms.sym->start;
232 ip_r = right->ms.sym->start;
233
234 return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
235}
236
237struct sort_entry sort_sym = { 232struct sort_entry sort_sym = {
238 .se_header = "Symbol", 233 .se_header = "Symbol",
239 .se_cmp = sort__sym_cmp, 234 .se_cmp = sort__sym_cmp,
@@ -253,7 +248,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
253 size_t size, 248 size_t size,
254 unsigned int width __maybe_unused) 249 unsigned int width __maybe_unused)
255{ 250{
256 FILE *fp; 251 FILE *fp = NULL;
257 char cmd[PATH_MAX + 2], *path = self->srcline, *nl; 252 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
258 size_t line_len; 253 size_t line_len;
259 254
@@ -274,7 +269,6 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
274 269
275 if (getline(&path, &line_len, fp) < 0 || !line_len) 270 if (getline(&path, &line_len, fp) < 0 || !line_len)
276 goto out_ip; 271 goto out_ip;
277 fclose(fp);
278 self->srcline = strdup(path); 272 self->srcline = strdup(path);
279 if (self->srcline == NULL) 273 if (self->srcline == NULL)
280 goto out_ip; 274 goto out_ip;
@@ -284,8 +278,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
284 *nl = '\0'; 278 *nl = '\0';
285 path = self->srcline; 279 path = self->srcline;
286out_path: 280out_path:
281 if (fp)
282 pclose(fp);
287 return repsep_snprintf(bf, size, "%s", path); 283 return repsep_snprintf(bf, size, "%s", path);
288out_ip: 284out_ip:
285 if (fp)
286 pclose(fp);
289 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip); 287 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
290} 288}
291 289
@@ -335,7 +333,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
335static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, 333static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
336 size_t size, unsigned int width) 334 size_t size, unsigned int width)
337{ 335{
338 return repsep_snprintf(bf, size, "%-*d", width, self->cpu); 336 return repsep_snprintf(bf, size, "%*d", width, self->cpu);
339} 337}
340 338
341struct sort_entry sort_cpu = { 339struct sort_entry sort_cpu = {
@@ -345,6 +343,8 @@ struct sort_entry sort_cpu = {
345 .se_width_idx = HISTC_CPU, 343 .se_width_idx = HISTC_CPU,
346}; 344};
347 345
346/* sort keys for branch stacks */
347
348static int64_t 348static int64_t
349sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) 349sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
350{ 350{
@@ -359,13 +359,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
359 bf, size, width); 359 bf, size, width);
360} 360}
361 361
362struct sort_entry sort_dso_from = {
363 .se_header = "Source Shared Object",
364 .se_cmp = sort__dso_from_cmp,
365 .se_snprintf = hist_entry__dso_from_snprintf,
366 .se_width_idx = HISTC_DSO_FROM,
367};
368
369static int64_t 362static int64_t
370sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 363sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
371{ 364{
@@ -389,8 +382,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
389 if (!from_l->sym && !from_r->sym) 382 if (!from_l->sym && !from_r->sym)
390 return right->level - left->level; 383 return right->level - left->level;
391 384
392 return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr, 385 return _sort__sym_cmp(from_l->sym, from_r->sym);
393 from_r->addr);
394} 386}
395 387
396static int64_t 388static int64_t
@@ -402,12 +394,11 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
402 if (!to_l->sym && !to_r->sym) 394 if (!to_l->sym && !to_r->sym)
403 return right->level - left->level; 395 return right->level - left->level;
404 396
405 return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr); 397 return _sort__sym_cmp(to_l->sym, to_r->sym);
406} 398}
407 399
408static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, 400static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
409 size_t size, 401 size_t size, unsigned int width)
410 unsigned int width __maybe_unused)
411{ 402{
412 struct addr_map_symbol *from = &self->branch_info->from; 403 struct addr_map_symbol *from = &self->branch_info->from;
413 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, 404 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
@@ -416,8 +407,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
416} 407}
417 408
418static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, 409static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
419 size_t size, 410 size_t size, unsigned int width)
420 unsigned int width __maybe_unused)
421{ 411{
422 struct addr_map_symbol *to = &self->branch_info->to; 412 struct addr_map_symbol *to = &self->branch_info->to;
423 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, 413 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
@@ -425,6 +415,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
425 415
426} 416}
427 417
418struct sort_entry sort_dso_from = {
419 .se_header = "Source Shared Object",
420 .se_cmp = sort__dso_from_cmp,
421 .se_snprintf = hist_entry__dso_from_snprintf,
422 .se_width_idx = HISTC_DSO_FROM,
423};
424
428struct sort_entry sort_dso_to = { 425struct sort_entry sort_dso_to = {
429 .se_header = "Target Shared Object", 426 .se_header = "Target Shared Object",
430 .se_cmp = sort__dso_to_cmp, 427 .se_cmp = sort__dso_to_cmp,
@@ -469,6 +466,304 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
469 return repsep_snprintf(bf, size, "%-*s", width, out); 466 return repsep_snprintf(bf, size, "%-*s", width, out);
470} 467}
471 468
469/* --sort daddr_sym */
470static int64_t
471sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
472{
473 uint64_t l = 0, r = 0;
474
475 if (left->mem_info)
476 l = left->mem_info->daddr.addr;
477 if (right->mem_info)
478 r = right->mem_info->daddr.addr;
479
480 return (int64_t)(r - l);
481}
482
483static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf,
484 size_t size, unsigned int width)
485{
486 uint64_t addr = 0;
487 struct map *map = NULL;
488 struct symbol *sym = NULL;
489
490 if (self->mem_info) {
491 addr = self->mem_info->daddr.addr;
492 map = self->mem_info->daddr.map;
493 sym = self->mem_info->daddr.sym;
494 }
495 return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size,
496 width);
497}
498
499static int64_t
500sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
501{
502 struct map *map_l = NULL;
503 struct map *map_r = NULL;
504
505 if (left->mem_info)
506 map_l = left->mem_info->daddr.map;
507 if (right->mem_info)
508 map_r = right->mem_info->daddr.map;
509
510 return _sort__dso_cmp(map_l, map_r);
511}
512
513static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf,
514 size_t size, unsigned int width)
515{
516 struct map *map = NULL;
517
518 if (self->mem_info)
519 map = self->mem_info->daddr.map;
520
521 return _hist_entry__dso_snprintf(map, bf, size, width);
522}
523
524static int64_t
525sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
526{
527 union perf_mem_data_src data_src_l;
528 union perf_mem_data_src data_src_r;
529
530 if (left->mem_info)
531 data_src_l = left->mem_info->data_src;
532 else
533 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
534
535 if (right->mem_info)
536 data_src_r = right->mem_info->data_src;
537 else
538 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
539
540 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
541}
542
543static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf,
544 size_t size, unsigned int width)
545{
546 const char *out;
547 u64 mask = PERF_MEM_LOCK_NA;
548
549 if (self->mem_info)
550 mask = self->mem_info->data_src.mem_lock;
551
552 if (mask & PERF_MEM_LOCK_NA)
553 out = "N/A";
554 else if (mask & PERF_MEM_LOCK_LOCKED)
555 out = "Yes";
556 else
557 out = "No";
558
559 return repsep_snprintf(bf, size, "%-*s", width, out);
560}
561
562static int64_t
563sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
564{
565 union perf_mem_data_src data_src_l;
566 union perf_mem_data_src data_src_r;
567
568 if (left->mem_info)
569 data_src_l = left->mem_info->data_src;
570 else
571 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
572
573 if (right->mem_info)
574 data_src_r = right->mem_info->data_src;
575 else
576 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
577
578 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
579}
580
581static const char * const tlb_access[] = {
582 "N/A",
583 "HIT",
584 "MISS",
585 "L1",
586 "L2",
587 "Walker",
588 "Fault",
589};
590#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
591
592static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
593 size_t size, unsigned int width)
594{
595 char out[64];
596 size_t sz = sizeof(out) - 1; /* -1 for null termination */
597 size_t l = 0, i;
598 u64 m = PERF_MEM_TLB_NA;
599 u64 hit, miss;
600
601 out[0] = '\0';
602
603 if (self->mem_info)
604 m = self->mem_info->data_src.mem_dtlb;
605
606 hit = m & PERF_MEM_TLB_HIT;
607 miss = m & PERF_MEM_TLB_MISS;
608
609 /* already taken care of */
610 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
611
612 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
613 if (!(m & 0x1))
614 continue;
615 if (l) {
616 strcat(out, " or ");
617 l += 4;
618 }
619 strncat(out, tlb_access[i], sz - l);
620 l += strlen(tlb_access[i]);
621 }
622 if (*out == '\0')
623 strcpy(out, "N/A");
624 if (hit)
625 strncat(out, " hit", sz - l);
626 if (miss)
627 strncat(out, " miss", sz - l);
628
629 return repsep_snprintf(bf, size, "%-*s", width, out);
630}
631
632static int64_t
633sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
634{
635 union perf_mem_data_src data_src_l;
636 union perf_mem_data_src data_src_r;
637
638 if (left->mem_info)
639 data_src_l = left->mem_info->data_src;
640 else
641 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
642
643 if (right->mem_info)
644 data_src_r = right->mem_info->data_src;
645 else
646 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
647
648 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
649}
650
651static const char * const mem_lvl[] = {
652 "N/A",
653 "HIT",
654 "MISS",
655 "L1",
656 "LFB",
657 "L2",
658 "L3",
659 "Local RAM",
660 "Remote RAM (1 hop)",
661 "Remote RAM (2 hops)",
662 "Remote Cache (1 hop)",
663 "Remote Cache (2 hops)",
664 "I/O",
665 "Uncached",
666};
667#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
668
669static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
670 size_t size, unsigned int width)
671{
672 char out[64];
673 size_t sz = sizeof(out) - 1; /* -1 for null termination */
674 size_t i, l = 0;
675 u64 m = PERF_MEM_LVL_NA;
676 u64 hit, miss;
677
678 if (self->mem_info)
679 m = self->mem_info->data_src.mem_lvl;
680
681 out[0] = '\0';
682
683 hit = m & PERF_MEM_LVL_HIT;
684 miss = m & PERF_MEM_LVL_MISS;
685
686 /* already taken care of */
687 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
688
689 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
690 if (!(m & 0x1))
691 continue;
692 if (l) {
693 strcat(out, " or ");
694 l += 4;
695 }
696 strncat(out, mem_lvl[i], sz - l);
697 l += strlen(mem_lvl[i]);
698 }
699 if (*out == '\0')
700 strcpy(out, "N/A");
701 if (hit)
702 strncat(out, " hit", sz - l);
703 if (miss)
704 strncat(out, " miss", sz - l);
705
706 return repsep_snprintf(bf, size, "%-*s", width, out);
707}
708
709static int64_t
710sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
711{
712 union perf_mem_data_src data_src_l;
713 union perf_mem_data_src data_src_r;
714
715 if (left->mem_info)
716 data_src_l = left->mem_info->data_src;
717 else
718 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
719
720 if (right->mem_info)
721 data_src_r = right->mem_info->data_src;
722 else
723 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
724
725 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
726}
727
728static const char * const snoop_access[] = {
729 "N/A",
730 "None",
731 "Miss",
732 "Hit",
733 "HitM",
734};
735#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
736
737static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
738 size_t size, unsigned int width)
739{
740 char out[64];
741 size_t sz = sizeof(out) - 1; /* -1 for null termination */
742 size_t i, l = 0;
743 u64 m = PERF_MEM_SNOOP_NA;
744
745 out[0] = '\0';
746
747 if (self->mem_info)
748 m = self->mem_info->data_src.mem_snoop;
749
750 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
751 if (!(m & 0x1))
752 continue;
753 if (l) {
754 strcat(out, " or ");
755 l += 4;
756 }
757 strncat(out, snoop_access[i], sz - l);
758 l += strlen(snoop_access[i]);
759 }
760
761 if (*out == '\0')
762 strcpy(out, "N/A");
763
764 return repsep_snprintf(bf, size, "%-*s", width, out);
765}
766
472struct sort_entry sort_mispredict = { 767struct sort_entry sort_mispredict = {
473 .se_header = "Branch Mispredicted", 768 .se_header = "Branch Mispredicted",
474 .se_cmp = sort__mispredict_cmp, 769 .se_cmp = sort__mispredict_cmp,
@@ -476,6 +771,91 @@ struct sort_entry sort_mispredict = {
476 .se_width_idx = HISTC_MISPREDICT, 771 .se_width_idx = HISTC_MISPREDICT,
477}; 772};
478 773
774static u64 he_weight(struct hist_entry *he)
775{
776 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
777}
778
779static int64_t
780sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
781{
782 return he_weight(left) - he_weight(right);
783}
784
785static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf,
786 size_t size, unsigned int width)
787{
788 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self));
789}
790
791struct sort_entry sort_local_weight = {
792 .se_header = "Local Weight",
793 .se_cmp = sort__local_weight_cmp,
794 .se_snprintf = hist_entry__local_weight_snprintf,
795 .se_width_idx = HISTC_LOCAL_WEIGHT,
796};
797
798static int64_t
799sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
800{
801 return left->stat.weight - right->stat.weight;
802}
803
804static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf,
805 size_t size, unsigned int width)
806{
807 return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight);
808}
809
810struct sort_entry sort_global_weight = {
811 .se_header = "Weight",
812 .se_cmp = sort__global_weight_cmp,
813 .se_snprintf = hist_entry__global_weight_snprintf,
814 .se_width_idx = HISTC_GLOBAL_WEIGHT,
815};
816
817struct sort_entry sort_mem_daddr_sym = {
818 .se_header = "Data Symbol",
819 .se_cmp = sort__daddr_cmp,
820 .se_snprintf = hist_entry__daddr_snprintf,
821 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
822};
823
824struct sort_entry sort_mem_daddr_dso = {
825 .se_header = "Data Object",
826 .se_cmp = sort__dso_daddr_cmp,
827 .se_snprintf = hist_entry__dso_daddr_snprintf,
828 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
829};
830
831struct sort_entry sort_mem_locked = {
832 .se_header = "Locked",
833 .se_cmp = sort__locked_cmp,
834 .se_snprintf = hist_entry__locked_snprintf,
835 .se_width_idx = HISTC_MEM_LOCKED,
836};
837
838struct sort_entry sort_mem_tlb = {
839 .se_header = "TLB access",
840 .se_cmp = sort__tlb_cmp,
841 .se_snprintf = hist_entry__tlb_snprintf,
842 .se_width_idx = HISTC_MEM_TLB,
843};
844
845struct sort_entry sort_mem_lvl = {
846 .se_header = "Memory access",
847 .se_cmp = sort__lvl_cmp,
848 .se_snprintf = hist_entry__lvl_snprintf,
849 .se_width_idx = HISTC_MEM_LVL,
850};
851
852struct sort_entry sort_mem_snoop = {
853 .se_header = "Snoop",
854 .se_cmp = sort__snoop_cmp,
855 .se_snprintf = hist_entry__snoop_snprintf,
856 .se_width_idx = HISTC_MEM_SNOOP,
857};
858
479struct sort_dimension { 859struct sort_dimension {
480 const char *name; 860 const char *name;
481 struct sort_entry *entry; 861 struct sort_entry *entry;
@@ -484,30 +864,70 @@ struct sort_dimension {
484 864
485#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } 865#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
486 866
487static struct sort_dimension sort_dimensions[] = { 867static struct sort_dimension common_sort_dimensions[] = {
488 DIM(SORT_PID, "pid", sort_thread), 868 DIM(SORT_PID, "pid", sort_thread),
489 DIM(SORT_COMM, "comm", sort_comm), 869 DIM(SORT_COMM, "comm", sort_comm),
490 DIM(SORT_DSO, "dso", sort_dso), 870 DIM(SORT_DSO, "dso", sort_dso),
491 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
492 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
493 DIM(SORT_SYM, "symbol", sort_sym), 871 DIM(SORT_SYM, "symbol", sort_sym),
494 DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
495 DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
496 DIM(SORT_PARENT, "parent", sort_parent), 872 DIM(SORT_PARENT, "parent", sort_parent),
497 DIM(SORT_CPU, "cpu", sort_cpu), 873 DIM(SORT_CPU, "cpu", sort_cpu),
498 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
499 DIM(SORT_SRCLINE, "srcline", sort_srcline), 874 DIM(SORT_SRCLINE, "srcline", sort_srcline),
500}; 875};
501 876
877#undef DIM
878
879#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
880
881static struct sort_dimension bstack_sort_dimensions[] = {
882 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
883 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
884 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
885 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
886 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
887};
888
889#undef DIM
890
891#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
892
893static struct sort_dimension memory_sort_dimensions[] = {
894 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
895 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
896 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
897 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
898 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
899 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
900 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
901 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
902};
903
904#undef DIM
905
906static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
907{
908 if (sd->taken)
909 return;
910
911 if (sd->entry->se_collapse)
912 sort__need_collapse = 1;
913
914 if (list_empty(&hist_entry__sort_list))
915 sort__first_dimension = idx;
916
917 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
918 sd->taken = 1;
919}
920
502int sort_dimension__add(const char *tok) 921int sort_dimension__add(const char *tok)
503{ 922{
504 unsigned int i; 923 unsigned int i;
505 924
506 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 925 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
507 struct sort_dimension *sd = &sort_dimensions[i]; 926 struct sort_dimension *sd = &common_sort_dimensions[i];
508 927
509 if (strncasecmp(tok, sd->name, strlen(tok))) 928 if (strncasecmp(tok, sd->name, strlen(tok)))
510 continue; 929 continue;
930
511 if (sd->entry == &sort_parent) { 931 if (sd->entry == &sort_parent) {
512 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 932 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
513 if (ret) { 933 if (ret) {
@@ -518,68 +938,78 @@ int sort_dimension__add(const char *tok)
518 return -EINVAL; 938 return -EINVAL;
519 } 939 }
520 sort__has_parent = 1; 940 sort__has_parent = 1;
521 } else if (sd->entry == &sort_sym || 941 } else if (sd->entry == &sort_sym) {
522 sd->entry == &sort_sym_from ||
523 sd->entry == &sort_sym_to) {
524 sort__has_sym = 1; 942 sort__has_sym = 1;
525 } 943 }
526 944
527 if (sd->taken) 945 __sort_dimension__add(sd, i);
528 return 0; 946 return 0;
529 947 }
530 if (sd->entry->se_collapse) 948
531 sort__need_collapse = 1; 949 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
532 950 struct sort_dimension *sd = &bstack_sort_dimensions[i];
533 if (list_empty(&hist_entry__sort_list)) { 951
534 if (!strcmp(sd->name, "pid")) 952 if (strncasecmp(tok, sd->name, strlen(tok)))
535 sort__first_dimension = SORT_PID; 953 continue;
536 else if (!strcmp(sd->name, "comm")) 954
537 sort__first_dimension = SORT_COMM; 955 if (sort__mode != SORT_MODE__BRANCH)
538 else if (!strcmp(sd->name, "dso")) 956 return -EINVAL;
539 sort__first_dimension = SORT_DSO; 957
540 else if (!strcmp(sd->name, "symbol")) 958 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
541 sort__first_dimension = SORT_SYM; 959 sort__has_sym = 1;
542 else if (!strcmp(sd->name, "parent")) 960
543 sort__first_dimension = SORT_PARENT; 961 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
544 else if (!strcmp(sd->name, "cpu")) 962 return 0;
545 sort__first_dimension = SORT_CPU; 963 }
546 else if (!strcmp(sd->name, "symbol_from")) 964
547 sort__first_dimension = SORT_SYM_FROM; 965 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
548 else if (!strcmp(sd->name, "symbol_to")) 966 struct sort_dimension *sd = &memory_sort_dimensions[i];
549 sort__first_dimension = SORT_SYM_TO;
550 else if (!strcmp(sd->name, "dso_from"))
551 sort__first_dimension = SORT_DSO_FROM;
552 else if (!strcmp(sd->name, "dso_to"))
553 sort__first_dimension = SORT_DSO_TO;
554 else if (!strcmp(sd->name, "mispredict"))
555 sort__first_dimension = SORT_MISPREDICT;
556 }
557 967
558 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 968 if (strncasecmp(tok, sd->name, strlen(tok)))
559 sd->taken = 1; 969 continue;
970
971 if (sort__mode != SORT_MODE__MEMORY)
972 return -EINVAL;
973
974 if (sd->entry == &sort_mem_daddr_sym)
975 sort__has_sym = 1;
560 976
977 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
561 return 0; 978 return 0;
562 } 979 }
980
563 return -ESRCH; 981 return -ESRCH;
564} 982}
565 983
566void setup_sorting(const char * const usagestr[], const struct option *opts) 984int setup_sorting(void)
567{ 985{
568 char *tmp, *tok, *str = strdup(sort_order); 986 char *tmp, *tok, *str = strdup(sort_order);
987 int ret = 0;
988
989 if (str == NULL) {
990 error("Not enough memory to setup sort keys");
991 return -ENOMEM;
992 }
569 993
570 for (tok = strtok_r(str, ", ", &tmp); 994 for (tok = strtok_r(str, ", ", &tmp);
571 tok; tok = strtok_r(NULL, ", ", &tmp)) { 995 tok; tok = strtok_r(NULL, ", ", &tmp)) {
572 if (sort_dimension__add(tok) < 0) { 996 ret = sort_dimension__add(tok);
997 if (ret == -EINVAL) {
998 error("Invalid --sort key: `%s'", tok);
999 break;
1000 } else if (ret == -ESRCH) {
573 error("Unknown --sort key: `%s'", tok); 1001 error("Unknown --sort key: `%s'", tok);
574 usage_with_options(usagestr, opts); 1002 break;
575 } 1003 }
576 } 1004 }
577 1005
578 free(str); 1006 free(str);
1007 return ret;
579} 1008}
580 1009
581void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 1010static void sort_entry__setup_elide(struct sort_entry *self,
582 const char *list_name, FILE *fp) 1011 struct strlist *list,
1012 const char *list_name, FILE *fp)
583{ 1013{
584 if (list && strlist__nr_entries(list) == 1) { 1014 if (list && strlist__nr_entries(list) == 1) {
585 if (fp != NULL) 1015 if (fp != NULL)
@@ -588,3 +1018,42 @@ void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
588 self->elide = true; 1018 self->elide = true;
589 } 1019 }
590} 1020}
1021
1022void sort__setup_elide(FILE *output)
1023{
1024 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1025 "dso", output);
1026 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1027 "comm", output);
1028 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1029 "symbol", output);
1030
1031 if (sort__mode == SORT_MODE__BRANCH) {
1032 sort_entry__setup_elide(&sort_dso_from,
1033 symbol_conf.dso_from_list,
1034 "dso_from", output);
1035 sort_entry__setup_elide(&sort_dso_to,
1036 symbol_conf.dso_to_list,
1037 "dso_to", output);
1038 sort_entry__setup_elide(&sort_sym_from,
1039 symbol_conf.sym_from_list,
1040 "sym_from", output);
1041 sort_entry__setup_elide(&sort_sym_to,
1042 symbol_conf.sym_to_list,
1043 "sym_to", output);
1044 } else if (sort__mode == SORT_MODE__MEMORY) {
1045 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1046 "symbol_daddr", output);
1047 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1048 "dso_daddr", output);
1049 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1050 "mem", output);
1051 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1052 "local_weight", output);
1053 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1054 "tlb", output);
1055 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1056 "snoop", output);
1057 }
1058
1059}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index b4e8c3ba559d..45ac84c1e037 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -32,7 +32,7 @@ extern const char default_sort_order[];
32extern int sort__need_collapse; 32extern int sort__need_collapse;
33extern int sort__has_parent; 33extern int sort__has_parent;
34extern int sort__has_sym; 34extern int sort__has_sym;
35extern int sort__branch_mode; 35extern enum sort_mode sort__mode;
36extern struct sort_entry sort_comm; 36extern struct sort_entry sort_comm;
37extern struct sort_entry sort_dso; 37extern struct sort_entry sort_dso;
38extern struct sort_entry sort_sym; 38extern struct sort_entry sort_sym;
@@ -49,15 +49,13 @@ struct he_stat {
49 u64 period_us; 49 u64 period_us;
50 u64 period_guest_sys; 50 u64 period_guest_sys;
51 u64 period_guest_us; 51 u64 period_guest_us;
52 u64 weight;
52 u32 nr_events; 53 u32 nr_events;
53}; 54};
54 55
55struct hist_entry_diff { 56struct hist_entry_diff {
56 bool computed; 57 bool computed;
57 58
58 /* PERF_HPP__DISPL */
59 int displacement;
60
61 /* PERF_HPP__DELTA */ 59 /* PERF_HPP__DELTA */
62 double period_ratio_delta; 60 double period_ratio_delta;
63 61
@@ -103,7 +101,8 @@ struct hist_entry {
103 struct rb_root sorted_chain; 101 struct rb_root sorted_chain;
104 struct branch_info *branch_info; 102 struct branch_info *branch_info;
105 struct hists *hists; 103 struct hists *hists;
106 struct callchain_root callchain[0]; 104 struct mem_info *mem_info;
105 struct callchain_root callchain[0]; /* must be last member */
107}; 106};
108 107
109static inline bool hist_entry__has_pairs(struct hist_entry *he) 108static inline bool hist_entry__has_pairs(struct hist_entry *he)
@@ -118,25 +117,46 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
118 return NULL; 117 return NULL;
119} 118}
120 119
121static inline void hist__entry_add_pair(struct hist_entry *he, 120static inline void hist_entry__add_pair(struct hist_entry *pair,
122 struct hist_entry *pair) 121 struct hist_entry *he)
123{ 122{
124 list_add_tail(&he->pairs.head, &pair->pairs.node); 123 list_add_tail(&pair->pairs.node, &he->pairs.head);
125} 124}
126 125
126enum sort_mode {
127 SORT_MODE__NORMAL,
128 SORT_MODE__BRANCH,
129 SORT_MODE__MEMORY,
130};
131
127enum sort_type { 132enum sort_type {
133 /* common sort keys */
128 SORT_PID, 134 SORT_PID,
129 SORT_COMM, 135 SORT_COMM,
130 SORT_DSO, 136 SORT_DSO,
131 SORT_SYM, 137 SORT_SYM,
132 SORT_PARENT, 138 SORT_PARENT,
133 SORT_CPU, 139 SORT_CPU,
134 SORT_DSO_FROM, 140 SORT_SRCLINE,
141
142 /* branch stack specific sort keys */
143 __SORT_BRANCH_STACK,
144 SORT_DSO_FROM = __SORT_BRANCH_STACK,
135 SORT_DSO_TO, 145 SORT_DSO_TO,
136 SORT_SYM_FROM, 146 SORT_SYM_FROM,
137 SORT_SYM_TO, 147 SORT_SYM_TO,
138 SORT_MISPREDICT, 148 SORT_MISPREDICT,
139 SORT_SRCLINE, 149
150 /* memory mode specific sort keys */
151 __SORT_MEMORY_MODE,
152 SORT_LOCAL_WEIGHT = __SORT_MEMORY_MODE,
153 SORT_GLOBAL_WEIGHT,
154 SORT_MEM_DADDR_SYMBOL,
155 SORT_MEM_DADDR_DSO,
156 SORT_MEM_LOCKED,
157 SORT_MEM_TLB,
158 SORT_MEM_LVL,
159 SORT_MEM_SNOOP,
140}; 160};
141 161
142/* 162/*
@@ -159,9 +179,8 @@ struct sort_entry {
159extern struct sort_entry sort_thread; 179extern struct sort_entry sort_thread;
160extern struct list_head hist_entry__sort_list; 180extern struct list_head hist_entry__sort_list;
161 181
162void setup_sorting(const char * const usagestr[], const struct option *opts); 182int setup_sorting(void);
163extern int sort_dimension__add(const char *); 183extern int sort_dimension__add(const char *);
164void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 184void sort__setup_elide(FILE *fp);
165 const char *list_name, FILE *fp);
166 185
167#endif /* __PERF_SORT_H */ 186#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 23742126f47c..7c59c28afcc5 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -37,7 +37,7 @@ double stddev_stats(struct stats *stats)
37{ 37{
38 double variance, variance_mean; 38 double variance, variance_mean;
39 39
40 if (!stats->n) 40 if (stats->n < 2)
41 return 0.0; 41 return 0.0;
42 42
43 variance = stats->M2 / (stats->n - 1); 43 variance = stats->M2 / (stats->n - 1);
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 346707df04b9..29c7b2cb2521 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -332,6 +332,24 @@ char *strxfrchar(char *s, char from, char to)
332} 332}
333 333
334/** 334/**
335 * ltrim - Removes leading whitespace from @s.
336 * @s: The string to be stripped.
337 *
338 * Return pointer to the first non-whitespace character in @s.
339 */
340char *ltrim(char *s)
341{
342 int len = strlen(s);
343
344 while (len && isspace(*s)) {
345 len--;
346 s++;
347 }
348
349 return s;
350}
351
352/**
335 * rtrim - Removes trailing whitespace from @s. 353 * rtrim - Removes trailing whitespace from @s.
336 * @s: The string to be stripped. 354 * @s: The string to be stripped.
337 * 355 *
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 155d8b7078a7..eabdce0a2daa 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -35,11 +35,11 @@ out_delete:
35 return NULL; 35 return NULL;
36} 36}
37 37
38static void str_node__delete(struct str_node *self, bool dupstr) 38static void str_node__delete(struct str_node *snode, bool dupstr)
39{ 39{
40 if (dupstr) 40 if (dupstr)
41 free((void *)self->s); 41 free((void *)snode->s);
42 free(self); 42 free(snode);
43} 43}
44 44
45static 45static
@@ -59,12 +59,12 @@ static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
59 return strcmp(snode->s, str); 59 return strcmp(snode->s, str);
60} 60}
61 61
62int strlist__add(struct strlist *self, const char *new_entry) 62int strlist__add(struct strlist *slist, const char *new_entry)
63{ 63{
64 return rblist__add_node(&self->rblist, new_entry); 64 return rblist__add_node(&slist->rblist, new_entry);
65} 65}
66 66
67int strlist__load(struct strlist *self, const char *filename) 67int strlist__load(struct strlist *slist, const char *filename)
68{ 68{
69 char entry[1024]; 69 char entry[1024];
70 int err; 70 int err;
@@ -80,7 +80,7 @@ int strlist__load(struct strlist *self, const char *filename)
80 continue; 80 continue;
81 entry[len - 1] = '\0'; 81 entry[len - 1] = '\0';
82 82
83 err = strlist__add(self, entry); 83 err = strlist__add(slist, entry);
84 if (err != 0) 84 if (err != 0)
85 goto out; 85 goto out;
86 } 86 }
@@ -107,56 +107,56 @@ struct str_node *strlist__find(struct strlist *slist, const char *entry)
107 return snode; 107 return snode;
108} 108}
109 109
110static int strlist__parse_list_entry(struct strlist *self, const char *s) 110static int strlist__parse_list_entry(struct strlist *slist, const char *s)
111{ 111{
112 if (strncmp(s, "file://", 7) == 0) 112 if (strncmp(s, "file://", 7) == 0)
113 return strlist__load(self, s + 7); 113 return strlist__load(slist, s + 7);
114 114
115 return strlist__add(self, s); 115 return strlist__add(slist, s);
116} 116}
117 117
118int strlist__parse_list(struct strlist *self, const char *s) 118int strlist__parse_list(struct strlist *slist, const char *s)
119{ 119{
120 char *sep; 120 char *sep;
121 int err; 121 int err;
122 122
123 while ((sep = strchr(s, ',')) != NULL) { 123 while ((sep = strchr(s, ',')) != NULL) {
124 *sep = '\0'; 124 *sep = '\0';
125 err = strlist__parse_list_entry(self, s); 125 err = strlist__parse_list_entry(slist, s);
126 *sep = ','; 126 *sep = ',';
127 if (err != 0) 127 if (err != 0)
128 return err; 128 return err;
129 s = sep + 1; 129 s = sep + 1;
130 } 130 }
131 131
132 return *s ? strlist__parse_list_entry(self, s) : 0; 132 return *s ? strlist__parse_list_entry(slist, s) : 0;
133} 133}
134 134
135struct strlist *strlist__new(bool dupstr, const char *slist) 135struct strlist *strlist__new(bool dupstr, const char *list)
136{ 136{
137 struct strlist *self = malloc(sizeof(*self)); 137 struct strlist *slist = malloc(sizeof(*slist));
138 138
139 if (self != NULL) { 139 if (slist != NULL) {
140 rblist__init(&self->rblist); 140 rblist__init(&slist->rblist);
141 self->rblist.node_cmp = strlist__node_cmp; 141 slist->rblist.node_cmp = strlist__node_cmp;
142 self->rblist.node_new = strlist__node_new; 142 slist->rblist.node_new = strlist__node_new;
143 self->rblist.node_delete = strlist__node_delete; 143 slist->rblist.node_delete = strlist__node_delete;
144 144
145 self->dupstr = dupstr; 145 slist->dupstr = dupstr;
146 if (slist && strlist__parse_list(self, slist) != 0) 146 if (list && strlist__parse_list(slist, list) != 0)
147 goto out_error; 147 goto out_error;
148 } 148 }
149 149
150 return self; 150 return slist;
151out_error: 151out_error:
152 free(self); 152 free(slist);
153 return NULL; 153 return NULL;
154} 154}
155 155
156void strlist__delete(struct strlist *self) 156void strlist__delete(struct strlist *slist)
157{ 157{
158 if (self != NULL) 158 if (slist != NULL)
159 rblist__delete(&self->rblist); 159 rblist__delete(&slist->rblist);
160} 160}
161 161
162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx) 162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index dd9f922ec67c..5c7f87069d9c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -17,34 +17,34 @@ struct strlist {
17}; 17};
18 18
19struct strlist *strlist__new(bool dupstr, const char *slist); 19struct strlist *strlist__new(bool dupstr, const char *slist);
20void strlist__delete(struct strlist *self); 20void strlist__delete(struct strlist *slist);
21 21
22void strlist__remove(struct strlist *self, struct str_node *sn); 22void strlist__remove(struct strlist *slist, struct str_node *sn);
23int strlist__load(struct strlist *self, const char *filename); 23int strlist__load(struct strlist *slist, const char *filename);
24int strlist__add(struct strlist *self, const char *str); 24int strlist__add(struct strlist *slist, const char *str);
25 25
26struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 26struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx);
27struct str_node *strlist__find(struct strlist *self, const char *entry); 27struct str_node *strlist__find(struct strlist *slist, const char *entry);
28 28
29static inline bool strlist__has_entry(struct strlist *self, const char *entry) 29static inline bool strlist__has_entry(struct strlist *slist, const char *entry)
30{ 30{
31 return strlist__find(self, entry) != NULL; 31 return strlist__find(slist, entry) != NULL;
32} 32}
33 33
34static inline bool strlist__empty(const struct strlist *self) 34static inline bool strlist__empty(const struct strlist *slist)
35{ 35{
36 return rblist__empty(&self->rblist); 36 return rblist__empty(&slist->rblist);
37} 37}
38 38
39static inline unsigned int strlist__nr_entries(const struct strlist *self) 39static inline unsigned int strlist__nr_entries(const struct strlist *slist)
40{ 40{
41 return rblist__nr_entries(&self->rblist); 41 return rblist__nr_entries(&slist->rblist);
42} 42}
43 43
44/* For strlist iteration */ 44/* For strlist iteration */
45static inline struct str_node *strlist__first(struct strlist *self) 45static inline struct str_node *strlist__first(struct strlist *slist)
46{ 46{
47 struct rb_node *rn = rb_first(&self->rblist.entries); 47 struct rb_node *rn = rb_first(&slist->rblist.entries);
48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; 48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
49} 49}
50static inline struct str_node *strlist__next(struct str_node *sn) 50static inline struct str_node *strlist__next(struct str_node *sn)
@@ -59,21 +59,21 @@ static inline struct str_node *strlist__next(struct str_node *sn)
59/** 59/**
60 * strlist_for_each - iterate over a strlist 60 * strlist_for_each - iterate over a strlist
61 * @pos: the &struct str_node to use as a loop cursor. 61 * @pos: the &struct str_node to use as a loop cursor.
62 * @self: the &struct strlist for loop. 62 * @slist: the &struct strlist for loop.
63 */ 63 */
64#define strlist__for_each(pos, self) \ 64#define strlist__for_each(pos, slist) \
65 for (pos = strlist__first(self); pos; pos = strlist__next(pos)) 65 for (pos = strlist__first(slist); pos; pos = strlist__next(pos))
66 66
67/** 67/**
68 * strlist_for_each_safe - iterate over a strlist safe against removal of 68 * strlist_for_each_safe - iterate over a strlist safe against removal of
69 * str_node 69 * str_node
70 * @pos: the &struct str_node to use as a loop cursor. 70 * @pos: the &struct str_node to use as a loop cursor.
71 * @n: another &struct str_node to use as temporary storage. 71 * @n: another &struct str_node to use as temporary storage.
72 * @self: the &struct strlist for loop. 72 * @slist: the &struct strlist for loop.
73 */ 73 */
74#define strlist__for_each_safe(pos, n, self) \ 74#define strlist__for_each_safe(pos, n, slist) \
75 for (pos = strlist__first(self), n = strlist__next(pos); pos;\ 75 for (pos = strlist__first(slist), n = strlist__next(pos); pos;\
76 pos = n, n = strlist__next(n)) 76 pos = n, n = strlist__next(n))
77 77
78int strlist__parse_list(struct strlist *self, const char *s); 78int strlist__parse_list(struct strlist *slist, const char *s);
79#endif /* __PERF_STRLIST_H */ 79#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index db0cc92cf2ea..4b12bf850325 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1,6 +1,3 @@
1#include <libelf.h>
2#include <gelf.h>
3#include <elf.h>
4#include <fcntl.h> 1#include <fcntl.h>
5#include <stdio.h> 2#include <stdio.h>
6#include <errno.h> 3#include <errno.h>
@@ -718,6 +715,17 @@ int dso__load_sym(struct dso *dso, struct map *map,
718 sym.st_value); 715 sym.st_value);
719 used_opd = true; 716 used_opd = true;
720 } 717 }
718 /*
719 * When loading symbols in a data mapping, ABS symbols (which
720 * has a value of SHN_ABS in its st_shndx) failed at
721 * elf_getscn(). And it marks the loading as a failure so
722 * already loaded symbols cannot be fixed up.
723 *
724 * I'm not sure what should be done. Just ignore them for now.
725 * - Namhyung Kim
726 */
727 if (sym.st_shndx == SHN_ABS)
728 continue;
721 729
722 sec = elf_getscn(runtime_ss->elf, sym.st_shndx); 730 sec = elf_getscn(runtime_ss->elf, sym.st_shndx);
723 if (!sec) 731 if (!sec)
@@ -798,9 +806,12 @@ int dso__load_sym(struct dso *dso, struct map *map,
798 * DWARF DW_compile_unit has this, but we don't always have access 806 * DWARF DW_compile_unit has this, but we don't always have access
799 * to it... 807 * to it...
800 */ 808 */
801 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 809 if (symbol_conf.demangle) {
802 if (demangled != NULL) 810 demangled = bfd_demangle(NULL, elf_name,
803 elf_name = demangled; 811 DMGL_PARAMS | DMGL_ANSI);
812 if (demangled != NULL)
813 elf_name = demangled;
814 }
804new_symbol: 815new_symbol:
805 f = symbol__new(sym.st_value, sym.st_size, 816 f = symbol__new(sym.st_value, sym.st_size,
806 GELF_ST_BIND(sym.st_info), elf_name); 817 GELF_ST_BIND(sym.st_info), elf_name);
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 259f8f2ea9c9..a7390cde63bc 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -1,6 +1,5 @@
1#include "symbol.h" 1#include "symbol.h"
2 2
3#include <elf.h>
4#include <stdio.h> 3#include <stdio.h>
5#include <fcntl.h> 4#include <fcntl.h>
6#include <string.h> 5#include <string.h>
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 295f8d4feedf..8cf3b5426a9a 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -28,14 +28,15 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 28 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
30 symbol_filter_t filter); 30 symbol_filter_t filter);
31static int vmlinux_path__nr_entries; 31int vmlinux_path__nr_entries;
32static char **vmlinux_path; 32char **vmlinux_path;
33 33
34struct symbol_conf symbol_conf = { 34struct symbol_conf symbol_conf = {
35 .exclude_other = true, 35 .exclude_other = true,
36 .use_modules = true, 36 .use_modules = true,
37 .try_vmlinux_path = true, 37 .try_vmlinux_path = true,
38 .annotate_src = true, 38 .annotate_src = true,
39 .demangle = true,
39 .symfs = "", 40 .symfs = "",
40}; 41};
41 42
@@ -202,13 +203,6 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
202 curr->end = ~0ULL; 203 curr->end = ~0ULL;
203} 204}
204 205
205static void map_groups__fixup_end(struct map_groups *mg)
206{
207 int i;
208 for (i = 0; i < MAP__NR_TYPES; ++i)
209 __map_groups__fixup_end(mg, i);
210}
211
212struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 206struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
213{ 207{
214 size_t namelen = strlen(name) + 1; 208 size_t namelen = strlen(name) + 1;
@@ -652,8 +646,8 @@ discard_symbol: rb_erase(&pos->rb_node, root);
652 return count + moved; 646 return count + moved;
653} 647}
654 648
655static bool symbol__restricted_filename(const char *filename, 649bool symbol__restricted_filename(const char *filename,
656 const char *restricted_filename) 650 const char *restricted_filename)
657{ 651{
658 bool restricted = false; 652 bool restricted = false;
659 653
@@ -775,10 +769,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
775 else 769 else
776 machine = NULL; 770 machine = NULL;
777 771
778 name = malloc(PATH_MAX);
779 if (!name)
780 return -1;
781
782 dso->adjust_symbols = 0; 772 dso->adjust_symbols = 0;
783 773
784 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 774 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
@@ -802,6 +792,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
802 if (machine) 792 if (machine)
803 root_dir = machine->root_dir; 793 root_dir = machine->root_dir;
804 794
795 name = malloc(PATH_MAX);
796 if (!name)
797 return -1;
798
805 /* Iterate over candidate debug images. 799 /* Iterate over candidate debug images.
806 * Keep track of "interesting" ones (those which have a symtab, dynsym, 800 * Keep track of "interesting" ones (those which have a symtab, dynsym,
807 * and/or opd section) for processing. 801 * and/or opd section) for processing.
@@ -887,200 +881,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
887 return NULL; 881 return NULL;
888} 882}
889 883
890static int map_groups__set_modules_path_dir(struct map_groups *mg,
891 const char *dir_name)
892{
893 struct dirent *dent;
894 DIR *dir = opendir(dir_name);
895 int ret = 0;
896
897 if (!dir) {
898 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
899 return -1;
900 }
901
902 while ((dent = readdir(dir)) != NULL) {
903 char path[PATH_MAX];
904 struct stat st;
905
906 /*sshfs might return bad dent->d_type, so we have to stat*/
907 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
908 if (stat(path, &st))
909 continue;
910
911 if (S_ISDIR(st.st_mode)) {
912 if (!strcmp(dent->d_name, ".") ||
913 !strcmp(dent->d_name, ".."))
914 continue;
915
916 ret = map_groups__set_modules_path_dir(mg, path);
917 if (ret < 0)
918 goto out;
919 } else {
920 char *dot = strrchr(dent->d_name, '.'),
921 dso_name[PATH_MAX];
922 struct map *map;
923 char *long_name;
924
925 if (dot == NULL || strcmp(dot, ".ko"))
926 continue;
927 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
928 (int)(dot - dent->d_name), dent->d_name);
929
930 strxfrchar(dso_name, '-', '_');
931 map = map_groups__find_by_name(mg, MAP__FUNCTION,
932 dso_name);
933 if (map == NULL)
934 continue;
935
936 long_name = strdup(path);
937 if (long_name == NULL) {
938 ret = -1;
939 goto out;
940 }
941 dso__set_long_name(map->dso, long_name);
942 map->dso->lname_alloc = 1;
943 dso__kernel_module_get_build_id(map->dso, "");
944 }
945 }
946
947out:
948 closedir(dir);
949 return ret;
950}
951
952static char *get_kernel_version(const char *root_dir)
953{
954 char version[PATH_MAX];
955 FILE *file;
956 char *name, *tmp;
957 const char *prefix = "Linux version ";
958
959 sprintf(version, "%s/proc/version", root_dir);
960 file = fopen(version, "r");
961 if (!file)
962 return NULL;
963
964 version[0] = '\0';
965 tmp = fgets(version, sizeof(version), file);
966 fclose(file);
967
968 name = strstr(version, prefix);
969 if (!name)
970 return NULL;
971 name += strlen(prefix);
972 tmp = strchr(name, ' ');
973 if (tmp)
974 *tmp = '\0';
975
976 return strdup(name);
977}
978
979static int machine__set_modules_path(struct machine *machine)
980{
981 char *version;
982 char modules_path[PATH_MAX];
983
984 version = get_kernel_version(machine->root_dir);
985 if (!version)
986 return -1;
987
988 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
989 machine->root_dir, version);
990 free(version);
991
992 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
993}
994
995struct map *machine__new_module(struct machine *machine, u64 start,
996 const char *filename)
997{
998 struct map *map;
999 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
1000
1001 if (dso == NULL)
1002 return NULL;
1003
1004 map = map__new2(start, dso, MAP__FUNCTION);
1005 if (map == NULL)
1006 return NULL;
1007
1008 if (machine__is_host(machine))
1009 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
1010 else
1011 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
1012 map_groups__insert(&machine->kmaps, map);
1013 return map;
1014}
1015
1016static int machine__create_modules(struct machine *machine)
1017{
1018 char *line = NULL;
1019 size_t n;
1020 FILE *file;
1021 struct map *map;
1022 const char *modules;
1023 char path[PATH_MAX];
1024
1025 if (machine__is_default_guest(machine))
1026 modules = symbol_conf.default_guest_modules;
1027 else {
1028 sprintf(path, "%s/proc/modules", machine->root_dir);
1029 modules = path;
1030 }
1031
1032 if (symbol__restricted_filename(path, "/proc/modules"))
1033 return -1;
1034
1035 file = fopen(modules, "r");
1036 if (file == NULL)
1037 return -1;
1038
1039 while (!feof(file)) {
1040 char name[PATH_MAX];
1041 u64 start;
1042 char *sep;
1043 int line_len;
1044
1045 line_len = getline(&line, &n, file);
1046 if (line_len < 0)
1047 break;
1048
1049 if (!line)
1050 goto out_failure;
1051
1052 line[--line_len] = '\0'; /* \n */
1053
1054 sep = strrchr(line, 'x');
1055 if (sep == NULL)
1056 continue;
1057
1058 hex2u64(sep + 1, &start);
1059
1060 sep = strchr(line, ' ');
1061 if (sep == NULL)
1062 continue;
1063
1064 *sep = '\0';
1065
1066 snprintf(name, sizeof(name), "[%s]", line);
1067 map = machine__new_module(machine, start, name);
1068 if (map == NULL)
1069 goto out_delete_line;
1070 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
1071 }
1072
1073 free(line);
1074 fclose(file);
1075
1076 return machine__set_modules_path(machine);
1077
1078out_delete_line:
1079 free(line);
1080out_failure:
1081 return -1;
1082}
1083
1084int dso__load_vmlinux(struct dso *dso, struct map *map, 884int dso__load_vmlinux(struct dso *dso, struct map *map,
1085 const char *vmlinux, symbol_filter_t filter) 885 const char *vmlinux, symbol_filter_t filter)
1086{ 886{
@@ -1124,8 +924,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1124 filename = dso__build_id_filename(dso, NULL, 0); 924 filename = dso__build_id_filename(dso, NULL, 0);
1125 if (filename != NULL) { 925 if (filename != NULL) {
1126 err = dso__load_vmlinux(dso, map, filename, filter); 926 err = dso__load_vmlinux(dso, map, filename, filter);
1127 if (err > 0) 927 if (err > 0) {
928 dso->lname_alloc = 1;
1128 goto out; 929 goto out;
930 }
1129 free(filename); 931 free(filename);
1130 } 932 }
1131 933
@@ -1133,6 +935,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1133 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 935 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
1134 if (err > 0) { 936 if (err > 0) {
1135 dso__set_long_name(dso, strdup(vmlinux_path[i])); 937 dso__set_long_name(dso, strdup(vmlinux_path[i]));
938 dso->lname_alloc = 1;
1136 break; 939 break;
1137 } 940 }
1138 } 941 }
@@ -1172,6 +975,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1172 if (err > 0) { 975 if (err > 0) {
1173 dso__set_long_name(dso, 976 dso__set_long_name(dso,
1174 strdup(symbol_conf.vmlinux_name)); 977 strdup(symbol_conf.vmlinux_name));
978 dso->lname_alloc = 1;
1175 goto out_fixup; 979 goto out_fixup;
1176 } 980 }
1177 return err; 981 return err;
@@ -1300,195 +1104,6 @@ out_try_fixup:
1300 return err; 1104 return err;
1301} 1105}
1302 1106
1303size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
1304{
1305 struct rb_node *nd;
1306 size_t ret = 0;
1307
1308 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
1309 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1310 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
1311 ret += __dsos__fprintf(&pos->user_dsos, fp);
1312 }
1313
1314 return ret;
1315}
1316
1317size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
1318 bool with_hits)
1319{
1320 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
1321 __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
1322}
1323
1324size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
1325 FILE *fp, bool with_hits)
1326{
1327 struct rb_node *nd;
1328 size_t ret = 0;
1329
1330 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
1331 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1332 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
1333 }
1334 return ret;
1335}
1336
1337static struct dso *machine__get_kernel(struct machine *machine)
1338{
1339 const char *vmlinux_name = NULL;
1340 struct dso *kernel;
1341
1342 if (machine__is_host(machine)) {
1343 vmlinux_name = symbol_conf.vmlinux_name;
1344 if (!vmlinux_name)
1345 vmlinux_name = "[kernel.kallsyms]";
1346
1347 kernel = dso__kernel_findnew(machine, vmlinux_name,
1348 "[kernel]",
1349 DSO_TYPE_KERNEL);
1350 } else {
1351 char bf[PATH_MAX];
1352
1353 if (machine__is_default_guest(machine))
1354 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
1355 if (!vmlinux_name)
1356 vmlinux_name = machine__mmap_name(machine, bf,
1357 sizeof(bf));
1358
1359 kernel = dso__kernel_findnew(machine, vmlinux_name,
1360 "[guest.kernel]",
1361 DSO_TYPE_GUEST_KERNEL);
1362 }
1363
1364 if (kernel != NULL && (!kernel->has_build_id))
1365 dso__read_running_kernel_build_id(kernel, machine);
1366
1367 return kernel;
1368}
1369
1370struct process_args {
1371 u64 start;
1372};
1373
1374static int symbol__in_kernel(void *arg, const char *name,
1375 char type __maybe_unused, u64 start)
1376{
1377 struct process_args *args = arg;
1378
1379 if (strchr(name, '['))
1380 return 0;
1381
1382 args->start = start;
1383 return 1;
1384}
1385
1386/* Figure out the start address of kernel map from /proc/kallsyms */
1387static u64 machine__get_kernel_start_addr(struct machine *machine)
1388{
1389 const char *filename;
1390 char path[PATH_MAX];
1391 struct process_args args;
1392
1393 if (machine__is_host(machine)) {
1394 filename = "/proc/kallsyms";
1395 } else {
1396 if (machine__is_default_guest(machine))
1397 filename = (char *)symbol_conf.default_guest_kallsyms;
1398 else {
1399 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1400 filename = path;
1401 }
1402 }
1403
1404 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1405 return 0;
1406
1407 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
1408 return 0;
1409
1410 return args.start;
1411}
1412
1413int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
1414{
1415 enum map_type type;
1416 u64 start = machine__get_kernel_start_addr(machine);
1417
1418 for (type = 0; type < MAP__NR_TYPES; ++type) {
1419 struct kmap *kmap;
1420
1421 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
1422 if (machine->vmlinux_maps[type] == NULL)
1423 return -1;
1424
1425 machine->vmlinux_maps[type]->map_ip =
1426 machine->vmlinux_maps[type]->unmap_ip =
1427 identity__map_ip;
1428 kmap = map__kmap(machine->vmlinux_maps[type]);
1429 kmap->kmaps = &machine->kmaps;
1430 map_groups__insert(&machine->kmaps,
1431 machine->vmlinux_maps[type]);
1432 }
1433
1434 return 0;
1435}
1436
1437void machine__destroy_kernel_maps(struct machine *machine)
1438{
1439 enum map_type type;
1440
1441 for (type = 0; type < MAP__NR_TYPES; ++type) {
1442 struct kmap *kmap;
1443
1444 if (machine->vmlinux_maps[type] == NULL)
1445 continue;
1446
1447 kmap = map__kmap(machine->vmlinux_maps[type]);
1448 map_groups__remove(&machine->kmaps,
1449 machine->vmlinux_maps[type]);
1450 if (kmap->ref_reloc_sym) {
1451 /*
1452 * ref_reloc_sym is shared among all maps, so free just
1453 * on one of them.
1454 */
1455 if (type == MAP__FUNCTION) {
1456 free((char *)kmap->ref_reloc_sym->name);
1457 kmap->ref_reloc_sym->name = NULL;
1458 free(kmap->ref_reloc_sym);
1459 }
1460 kmap->ref_reloc_sym = NULL;
1461 }
1462
1463 map__delete(machine->vmlinux_maps[type]);
1464 machine->vmlinux_maps[type] = NULL;
1465 }
1466}
1467
1468int machine__create_kernel_maps(struct machine *machine)
1469{
1470 struct dso *kernel = machine__get_kernel(machine);
1471
1472 if (kernel == NULL ||
1473 __machine__create_kernel_maps(machine, kernel) < 0)
1474 return -1;
1475
1476 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
1477 if (machine__is_host(machine))
1478 pr_debug("Problems creating module maps, "
1479 "continuing anyway...\n");
1480 else
1481 pr_debug("Problems creating module maps for guest %d, "
1482 "continuing anyway...\n", machine->pid);
1483 }
1484
1485 /*
1486 * Now that we have all the maps created, just set the ->end of them:
1487 */
1488 map_groups__fixup_end(&machine->kmaps);
1489 return 0;
1490}
1491
1492static void vmlinux_path__exit(void) 1107static void vmlinux_path__exit(void)
1493{ 1108{
1494 while (--vmlinux_path__nr_entries >= 0) { 1109 while (--vmlinux_path__nr_entries >= 0) {
@@ -1549,25 +1164,6 @@ out_fail:
1549 return -1; 1164 return -1;
1550} 1165}
1551 1166
1552size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
1553{
1554 int i;
1555 size_t printed = 0;
1556 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
1557
1558 if (kdso->has_build_id) {
1559 char filename[PATH_MAX];
1560 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
1561 printed += fprintf(fp, "[0] %s\n", filename);
1562 }
1563
1564 for (i = 0; i < vmlinux_path__nr_entries; ++i)
1565 printed += fprintf(fp, "[%d] %s\n",
1566 i + kdso->has_build_id, vmlinux_path[i]);
1567
1568 return printed;
1569}
1570
1571static int setup_list(struct strlist **list, const char *list_str, 1167static int setup_list(struct strlist **list, const char *list_str,
1572 const char *list_name) 1168 const char *list_name)
1573{ 1169{
@@ -1671,108 +1267,3 @@ void symbol__exit(void)
1671 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 1267 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
1672 symbol_conf.initialized = false; 1268 symbol_conf.initialized = false;
1673} 1269}
1674
1675int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
1676{
1677 struct machine *machine = machines__findnew(machines, pid);
1678
1679 if (machine == NULL)
1680 return -1;
1681
1682 return machine__create_kernel_maps(machine);
1683}
1684
1685int machines__create_guest_kernel_maps(struct rb_root *machines)
1686{
1687 int ret = 0;
1688 struct dirent **namelist = NULL;
1689 int i, items = 0;
1690 char path[PATH_MAX];
1691 pid_t pid;
1692 char *endp;
1693
1694 if (symbol_conf.default_guest_vmlinux_name ||
1695 symbol_conf.default_guest_modules ||
1696 symbol_conf.default_guest_kallsyms) {
1697 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
1698 }
1699
1700 if (symbol_conf.guestmount) {
1701 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
1702 if (items <= 0)
1703 return -ENOENT;
1704 for (i = 0; i < items; i++) {
1705 if (!isdigit(namelist[i]->d_name[0])) {
1706 /* Filter out . and .. */
1707 continue;
1708 }
1709 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
1710 if ((*endp != '\0') ||
1711 (endp == namelist[i]->d_name) ||
1712 (errno == ERANGE)) {
1713 pr_debug("invalid directory (%s). Skipping.\n",
1714 namelist[i]->d_name);
1715 continue;
1716 }
1717 sprintf(path, "%s/%s/proc/kallsyms",
1718 symbol_conf.guestmount,
1719 namelist[i]->d_name);
1720 ret = access(path, R_OK);
1721 if (ret) {
1722 pr_debug("Can't access file %s\n", path);
1723 goto failure;
1724 }
1725 machines__create_kernel_maps(machines, pid);
1726 }
1727failure:
1728 free(namelist);
1729 }
1730
1731 return ret;
1732}
1733
1734void machines__destroy_guest_kernel_maps(struct rb_root *machines)
1735{
1736 struct rb_node *next = rb_first(machines);
1737
1738 while (next) {
1739 struct machine *pos = rb_entry(next, struct machine, rb_node);
1740
1741 next = rb_next(&pos->rb_node);
1742 rb_erase(&pos->rb_node, machines);
1743 machine__delete(pos);
1744 }
1745}
1746
1747int machine__load_kallsyms(struct machine *machine, const char *filename,
1748 enum map_type type, symbol_filter_t filter)
1749{
1750 struct map *map = machine->vmlinux_maps[type];
1751 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
1752
1753 if (ret > 0) {
1754 dso__set_loaded(map->dso, type);
1755 /*
1756 * Since /proc/kallsyms will have multiple sessions for the
1757 * kernel, with modules between them, fixup the end of all
1758 * sections.
1759 */
1760 __map_groups__fixup_end(&machine->kmaps, type);
1761 }
1762
1763 return ret;
1764}
1765
1766int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
1767 symbol_filter_t filter)
1768{
1769 struct map *map = machine->vmlinux_maps[type];
1770 int ret = dso__load_vmlinux_path(map->dso, map, filter);
1771
1772 if (ret > 0) {
1773 dso__set_loaded(map->dso, type);
1774 map__reloc_vmlinux(map);
1775 }
1776
1777 return ret;
1778}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index de68f98b236d..5f720dc076da 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -16,8 +16,8 @@
16#ifdef LIBELF_SUPPORT 16#ifdef LIBELF_SUPPORT
17#include <libelf.h> 17#include <libelf.h>
18#include <gelf.h> 18#include <gelf.h>
19#include <elf.h>
20#endif 19#endif
20#include <elf.h>
21 21
22#include "dso.h" 22#include "dso.h"
23 23
@@ -96,7 +96,9 @@ struct symbol_conf {
96 initialized, 96 initialized,
97 kptr_restrict, 97 kptr_restrict,
98 annotate_asm_raw, 98 annotate_asm_raw,
99 annotate_src; 99 annotate_src,
100 event_group,
101 demangle;
100 const char *vmlinux_name, 102 const char *vmlinux_name,
101 *kallsyms_name, 103 *kallsyms_name,
102 *source_prefix, 104 *source_prefix,
@@ -120,6 +122,8 @@ struct symbol_conf {
120}; 122};
121 123
122extern struct symbol_conf symbol_conf; 124extern struct symbol_conf symbol_conf;
125extern int vmlinux_path__nr_entries;
126extern char **vmlinux_path;
123 127
124static inline void *symbol__priv(struct symbol *sym) 128static inline void *symbol__priv(struct symbol *sym)
125{ 129{
@@ -152,6 +156,12 @@ struct branch_info {
152 struct branch_flags flags; 156 struct branch_flags flags;
153}; 157};
154 158
159struct mem_info {
160 struct addr_map_symbol iaddr;
161 struct addr_map_symbol daddr;
162 union perf_mem_data_src data_src;
163};
164
155struct addr_location { 165struct addr_location {
156 struct thread *thread; 166 struct thread *thread;
157 struct map *map; 167 struct map *map;
@@ -223,6 +233,8 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym,
223size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); 233size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
224size_t symbol__fprintf(struct symbol *sym, FILE *fp); 234size_t symbol__fprintf(struct symbol *sym, FILE *fp);
225bool symbol_type__is_a(char symbol_type, enum map_type map_type); 235bool symbol_type__is_a(char symbol_type, enum map_type map_type);
236bool symbol__restricted_filename(const char *filename,
237 const char *restricted_filename);
226 238
227int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 239int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
228 struct symsrc *runtime_ss, symbol_filter_t filter, 240 struct symsrc *runtime_ss, symbol_filter_t filter,
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
index 48c6902e749f..f71e9eafe15a 100644
--- a/tools/perf/util/sysfs.c
+++ b/tools/perf/util/sysfs.c
@@ -8,7 +8,7 @@ static const char * const sysfs_known_mountpoints[] = {
8}; 8};
9 9
10static int sysfs_found; 10static int sysfs_found;
11char sysfs_mountpoint[PATH_MAX]; 11char sysfs_mountpoint[PATH_MAX + 1];
12 12
13static int sysfs_valid_mountpoint(const char *sysfs) 13static int sysfs_valid_mountpoint(const char *sysfs)
14{ 14{
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index df59623ac763..40399cbcca77 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -14,6 +14,7 @@ struct thread *thread__new(pid_t pid)
14 if (self != NULL) { 14 if (self != NULL) {
15 map_groups__init(&self->mg); 15 map_groups__init(&self->mg);
16 self->pid = pid; 16 self->pid = pid;
17 self->ppid = -1;
17 self->comm = malloc(32); 18 self->comm = malloc(32);
18 if (self->comm) 19 if (self->comm)
19 snprintf(self->comm, 32, ":%d", self->pid); 20 snprintf(self->comm, 32, ":%d", self->pid);
@@ -54,10 +55,10 @@ int thread__comm_len(struct thread *self)
54 return self->comm_len; 55 return self->comm_len;
55} 56}
56 57
57static size_t thread__fprintf(struct thread *self, FILE *fp) 58size_t thread__fprintf(struct thread *thread, FILE *fp)
58{ 59{
59 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + 60 return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) +
60 map_groups__fprintf(&self->mg, verbose, fp); 61 map_groups__fprintf(&thread->mg, verbose, fp);
61} 62}
62 63
63void thread__insert_map(struct thread *self, struct map *map) 64void thread__insert_map(struct thread *self, struct map *map)
@@ -82,19 +83,8 @@ int thread__fork(struct thread *self, struct thread *parent)
82 for (i = 0; i < MAP__NR_TYPES; ++i) 83 for (i = 0; i < MAP__NR_TYPES; ++i)
83 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 84 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
84 return -ENOMEM; 85 return -ENOMEM;
85 return 0;
86}
87
88size_t machine__fprintf(struct machine *machine, FILE *fp)
89{
90 size_t ret = 0;
91 struct rb_node *nd;
92 86
93 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { 87 self->ppid = parent->pid;
94 struct thread *pos = rb_entry(nd, struct thread, rb_node);
95 88
96 ret += thread__fprintf(pos, fp); 89 return 0;
97 }
98
99 return ret;
100} 90}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index f2fa17caa7d5..eeb7ac62b9e3 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -13,6 +13,7 @@ struct thread {
13 }; 13 };
14 struct map_groups mg; 14 struct map_groups mg;
15 pid_t pid; 15 pid_t pid;
16 pid_t ppid;
16 char shortname[3]; 17 char shortname[3];
17 bool comm_set; 18 bool comm_set;
18 char *comm; 19 char *comm;
@@ -30,6 +31,7 @@ int thread__set_comm(struct thread *self, const char *comm);
30int thread__comm_len(struct thread *self); 31int thread__comm_len(struct thread *self);
31void thread__insert_map(struct thread *self, struct map *map); 32void thread__insert_map(struct thread *self, struct map *map);
32int thread__fork(struct thread *self, struct thread *parent); 33int thread__fork(struct thread *self, struct thread *parent);
34size_t thread__fprintf(struct thread *thread, FILE *fp);
33 35
34static inline struct map *thread__find_map(struct thread *self, 36static inline struct map *thread__find_map(struct thread *self,
35 enum map_type type, u64 addr) 37 enum map_type type, u64 addr)
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index f718df8a3c59..0cd8b3108084 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -21,4 +21,9 @@ void thread_map__delete(struct thread_map *threads);
21 21
22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); 22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
23 23
24static inline int thread_map__nr(struct thread_map *threads)
25{
26 return threads ? threads->nr : 1;
27}
28
24#endif /* __PERF_THREAD_MAP_H */ 29#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 884dde9b9bc1..f857b51b6bde 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -23,18 +23,31 @@
23 23
24size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) 24size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
25{ 25{
26 float samples_per_sec = top->samples / top->delay_secs; 26 float samples_per_sec;
27 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 27 float ksamples_per_sec;
28 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 28 float esamples_percent;
29 struct perf_record_opts *opts = &top->record_opts;
30 struct perf_target *target = &opts->target;
29 size_t ret = 0; 31 size_t ret = 0;
30 32
33 if (top->samples) {
34 samples_per_sec = top->samples / top->delay_secs;
35 ksamples_per_sec = top->kernel_samples / top->delay_secs;
36 esamples_percent = (100.0 * top->exact_samples) / top->samples;
37 } else {
38 samples_per_sec = ksamples_per_sec = esamples_percent = 0.0;
39 }
40
31 if (!perf_guest) { 41 if (!perf_guest) {
42 float ksamples_percent = 0.0;
43
44 if (samples_per_sec)
45 ksamples_percent = (100.0 * ksamples_per_sec) /
46 samples_per_sec;
32 ret = SNPRINTF(bf, size, 47 ret = SNPRINTF(bf, size,
33 " PerfTop:%8.0f irqs/sec kernel:%4.1f%%" 48 " PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
34 " exact: %4.1f%% [", samples_per_sec, 49 " exact: %4.1f%% [", samples_per_sec,
35 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / 50 ksamples_percent, esamples_percent);
36 samples_per_sec)),
37 esamples_percent);
38 } else { 51 } else {
39 float us_samples_per_sec = top->us_samples / top->delay_secs; 52 float us_samples_per_sec = top->us_samples / top->delay_secs;
40 float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs; 53 float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs;
@@ -61,31 +74,31 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
61 struct perf_evsel *first = perf_evlist__first(top->evlist); 74 struct perf_evsel *first = perf_evlist__first(top->evlist);
62 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 75 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
63 (uint64_t)first->attr.sample_period, 76 (uint64_t)first->attr.sample_period,
64 top->freq ? "Hz" : ""); 77 opts->freq ? "Hz" : "");
65 } 78 }
66 79
67 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); 80 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel));
68 81
69 ret += SNPRINTF(bf + ret, size - ret, "], "); 82 ret += SNPRINTF(bf + ret, size - ret, "], ");
70 83
71 if (top->target.pid) 84 if (target->pid)
72 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", 85 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
73 top->target.pid); 86 target->pid);
74 else if (top->target.tid) 87 else if (target->tid)
75 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", 88 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
76 top->target.tid); 89 target->tid);
77 else if (top->target.uid_str != NULL) 90 else if (target->uid_str != NULL)
78 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", 91 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
79 top->target.uid_str); 92 target->uid_str);
80 else 93 else
81 ret += SNPRINTF(bf + ret, size - ret, " (all"); 94 ret += SNPRINTF(bf + ret, size - ret, " (all");
82 95
83 if (top->target.cpu_list) 96 if (target->cpu_list)
84 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 97 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
85 top->evlist->cpus->nr > 1 ? "s" : "", 98 top->evlist->cpus->nr > 1 ? "s" : "",
86 top->target.cpu_list); 99 target->cpu_list);
87 else { 100 else {
88 if (top->target.tid) 101 if (target->tid)
89 ret += SNPRINTF(bf + ret, size - ret, ")"); 102 ret += SNPRINTF(bf + ret, size - ret, ")");
90 else 103 else
91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 104 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 86ff1b15059b..df46be93d902 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -14,7 +14,7 @@ struct perf_session;
14struct perf_top { 14struct perf_top {
15 struct perf_tool tool; 15 struct perf_tool tool;
16 struct perf_evlist *evlist; 16 struct perf_evlist *evlist;
17 struct perf_target target; 17 struct perf_record_opts record_opts;
18 /* 18 /*
19 * Symbols will be added here in perf_event__process_sample and will 19 * Symbols will be added here in perf_event__process_sample and will
20 * get out after decayed. 20 * get out after decayed.
@@ -24,27 +24,19 @@ struct perf_top {
24 u64 exact_samples; 24 u64 exact_samples;
25 u64 guest_us_samples, guest_kernel_samples; 25 u64 guest_us_samples, guest_kernel_samples;
26 int print_entries, count_filter, delay_secs; 26 int print_entries, count_filter, delay_secs;
27 int freq;
28 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
29 bool use_tui, use_stdio; 28 bool use_tui, use_stdio;
30 bool sort_has_symbols;
31 bool dont_use_callchains;
32 bool kptr_restrict_warned; 29 bool kptr_restrict_warned;
33 bool vmlinux_warned; 30 bool vmlinux_warned;
34 bool inherit;
35 bool group;
36 bool sample_id_all_missing;
37 bool exclude_guest_missing;
38 bool dump_symtab; 31 bool dump_symtab;
39 struct hist_entry *sym_filter_entry; 32 struct hist_entry *sym_filter_entry;
40 struct perf_evsel *sym_evsel; 33 struct perf_evsel *sym_evsel;
41 struct perf_session *session; 34 struct perf_session *session;
42 struct winsize winsize; 35 struct winsize winsize;
43 unsigned int mmap_pages;
44 int default_interval;
45 int realtime_prio; 36 int realtime_prio;
46 int sym_pcnt_filter; 37 int sym_pcnt_filter;
47 const char *sym_filter; 38 const char *sym_filter;
39 float min_percent;
48}; 40};
49 41
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 42size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index a8d81c35ef66..3917eb9a8479 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -38,52 +38,20 @@
38 38
39#include "../perf.h" 39#include "../perf.h"
40#include "trace-event.h" 40#include "trace-event.h"
41#include "debugfs.h" 41#include <lk/debugfs.h>
42#include "evsel.h" 42#include "evsel.h"
43 43
44#define VERSION "0.5" 44#define VERSION "0.5"
45 45
46#define TRACE_CTRL "tracing_on"
47#define TRACE "trace"
48#define AVAILABLE "available_tracers"
49#define CURRENT "current_tracer"
50#define ITER_CTRL "trace_options"
51#define MAX_LATENCY "tracing_max_latency"
52
53unsigned int page_size;
54
55static const char *output_file = "trace.info";
56static int output_fd; 46static int output_fd;
57 47
58struct event_list {
59 struct event_list *next;
60 const char *event;
61};
62
63struct events {
64 struct events *sibling;
65 struct events *children;
66 struct events *next;
67 char *name;
68};
69
70
71static void *malloc_or_die(unsigned int size)
72{
73 void *data;
74
75 data = malloc(size);
76 if (!data)
77 die("malloc");
78 return data;
79}
80 48
81static const char *find_debugfs(void) 49static const char *find_debugfs(void)
82{ 50{
83 const char *path = debugfs_mount(NULL); 51 const char *path = perf_debugfs_mount(NULL);
84 52
85 if (!path) 53 if (!path)
86 die("Your kernel not support debugfs filesystem"); 54 pr_debug("Your kernel does not support the debugfs filesystem");
87 55
88 return path; 56 return path;
89} 57}
@@ -102,8 +70,12 @@ static const char *find_tracing_dir(void)
102 return tracing; 70 return tracing;
103 71
104 debugfs = find_debugfs(); 72 debugfs = find_debugfs();
73 if (!debugfs)
74 return NULL;
105 75
106 tracing = malloc_or_die(strlen(debugfs) + 9); 76 tracing = malloc(strlen(debugfs) + 9);
77 if (!tracing)
78 return NULL;
107 79
108 sprintf(tracing, "%s/tracing", debugfs); 80 sprintf(tracing, "%s/tracing", debugfs);
109 81
@@ -120,7 +92,9 @@ static char *get_tracing_file(const char *name)
120 if (!tracing) 92 if (!tracing)
121 return NULL; 93 return NULL;
122 94
123 file = malloc_or_die(strlen(tracing) + strlen(name) + 2); 95 file = malloc(strlen(tracing) + strlen(name) + 2);
96 if (!file)
97 return NULL;
124 98
125 sprintf(file, "%s/%s", tracing, name); 99 sprintf(file, "%s/%s", tracing, name);
126 return file; 100 return file;
@@ -131,24 +105,6 @@ static void put_tracing_file(char *file)
131 free(file); 105 free(file);
132} 106}
133 107
134static ssize_t calc_data_size;
135
136static ssize_t write_or_die(const void *buf, size_t len)
137{
138 int ret;
139
140 if (calc_data_size) {
141 calc_data_size += len;
142 return len;
143 }
144
145 ret = write(output_fd, buf, len);
146 if (ret < 0)
147 die("writing to '%s'", output_file);
148
149 return ret;
150}
151
152int bigendian(void) 108int bigendian(void)
153{ 109{
154 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; 110 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
@@ -159,59 +115,106 @@ int bigendian(void)
159} 115}
160 116
161/* unfortunately, you can not stat debugfs or proc files for size */ 117/* unfortunately, you can not stat debugfs or proc files for size */
162static void record_file(const char *file, size_t hdr_sz) 118static int record_file(const char *file, ssize_t hdr_sz)
163{ 119{
164 unsigned long long size = 0; 120 unsigned long long size = 0;
165 char buf[BUFSIZ], *sizep; 121 char buf[BUFSIZ], *sizep;
166 off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR); 122 off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
167 int r, fd; 123 int r, fd;
124 int err = -EIO;
168 125
169 fd = open(file, O_RDONLY); 126 fd = open(file, O_RDONLY);
170 if (fd < 0) 127 if (fd < 0) {
171 die("Can't read '%s'", file); 128 pr_debug("Can't read '%s'", file);
129 return -errno;
130 }
172 131
173 /* put in zeros for file size, then fill true size later */ 132 /* put in zeros for file size, then fill true size later */
174 if (hdr_sz) 133 if (hdr_sz) {
175 write_or_die(&size, hdr_sz); 134 if (write(output_fd, &size, hdr_sz) != hdr_sz)
135 goto out;
136 }
176 137
177 do { 138 do {
178 r = read(fd, buf, BUFSIZ); 139 r = read(fd, buf, BUFSIZ);
179 if (r > 0) { 140 if (r > 0) {
180 size += r; 141 size += r;
181 write_or_die(buf, r); 142 if (write(output_fd, buf, r) != r)
143 goto out;
182 } 144 }
183 } while (r > 0); 145 } while (r > 0);
184 close(fd);
185 146
186 /* ugh, handle big-endian hdr_size == 4 */ 147 /* ugh, handle big-endian hdr_size == 4 */
187 sizep = (char*)&size; 148 sizep = (char*)&size;
188 if (bigendian()) 149 if (bigendian())
189 sizep += sizeof(u64) - hdr_sz; 150 sizep += sizeof(u64) - hdr_sz;
190 151
191 if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) 152 if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) {
192 die("writing to %s", output_file); 153 pr_debug("writing file size failed\n");
154 goto out;
155 }
156
157 err = 0;
158out:
159 close(fd);
160 return err;
193} 161}
194 162
195static void read_header_files(void) 163static int read_header_files(void)
196{ 164{
197 char *path; 165 char *path;
198 struct stat st; 166 struct stat st;
167 int err = -EIO;
199 168
200 path = get_tracing_file("events/header_page"); 169 path = get_tracing_file("events/header_page");
201 if (stat(path, &st) < 0) 170 if (!path) {
202 die("can't read '%s'", path); 171 pr_debug("can't get tracing/events/header_page");
172 return -ENOMEM;
173 }
174
175 if (stat(path, &st) < 0) {
176 pr_debug("can't read '%s'", path);
177 goto out;
178 }
179
180 if (write(output_fd, "header_page", 12) != 12) {
181 pr_debug("can't write header_page\n");
182 goto out;
183 }
184
185 if (record_file(path, 8) < 0) {
186 pr_debug("can't record header_page file\n");
187 goto out;
188 }
203 189
204 write_or_die("header_page", 12);
205 record_file(path, 8);
206 put_tracing_file(path); 190 put_tracing_file(path);
207 191
208 path = get_tracing_file("events/header_event"); 192 path = get_tracing_file("events/header_event");
209 if (stat(path, &st) < 0) 193 if (!path) {
210 die("can't read '%s'", path); 194 pr_debug("can't get tracing/events/header_event");
195 err = -ENOMEM;
196 goto out;
197 }
198
199 if (stat(path, &st) < 0) {
200 pr_debug("can't read '%s'", path);
201 goto out;
202 }
211 203
212 write_or_die("header_event", 13); 204 if (write(output_fd, "header_event", 13) != 13) {
213 record_file(path, 8); 205 pr_debug("can't write header_event\n");
206 goto out;
207 }
208
209 if (record_file(path, 8) < 0) {
210 pr_debug("can't record header_event file\n");
211 goto out;
212 }
213
214 err = 0;
215out:
214 put_tracing_file(path); 216 put_tracing_file(path);
217 return err;
215} 218}
216 219
217static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 220static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -225,7 +228,7 @@ static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
225 return false; 228 return false;
226} 229}
227 230
228static void copy_event_system(const char *sys, struct tracepoint_path *tps) 231static int copy_event_system(const char *sys, struct tracepoint_path *tps)
229{ 232{
230 struct dirent *dent; 233 struct dirent *dent;
231 struct stat st; 234 struct stat st;
@@ -233,10 +236,13 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
233 DIR *dir; 236 DIR *dir;
234 int count = 0; 237 int count = 0;
235 int ret; 238 int ret;
239 int err;
236 240
237 dir = opendir(sys); 241 dir = opendir(sys);
238 if (!dir) 242 if (!dir) {
239 die("can't read directory '%s'", sys); 243 pr_debug("can't read directory '%s'", sys);
244 return -errno;
245 }
240 246
241 while ((dent = readdir(dir))) { 247 while ((dent = readdir(dir))) {
242 if (dent->d_type != DT_DIR || 248 if (dent->d_type != DT_DIR ||
@@ -244,7 +250,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
244 strcmp(dent->d_name, "..") == 0 || 250 strcmp(dent->d_name, "..") == 0 ||
245 !name_in_tp_list(dent->d_name, tps)) 251 !name_in_tp_list(dent->d_name, tps))
246 continue; 252 continue;
247 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 253 format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
254 if (!format) {
255 err = -ENOMEM;
256 goto out;
257 }
248 sprintf(format, "%s/%s/format", sys, dent->d_name); 258 sprintf(format, "%s/%s/format", sys, dent->d_name);
249 ret = stat(format, &st); 259 ret = stat(format, &st);
250 free(format); 260 free(format);
@@ -253,7 +263,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
253 count++; 263 count++;
254 } 264 }
255 265
256 write_or_die(&count, 4); 266 if (write(output_fd, &count, 4) != 4) {
267 err = -EIO;
268 pr_debug("can't write count\n");
269 goto out;
270 }
257 271
258 rewinddir(dir); 272 rewinddir(dir);
259 while ((dent = readdir(dir))) { 273 while ((dent = readdir(dir))) {
@@ -262,27 +276,45 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
262 strcmp(dent->d_name, "..") == 0 || 276 strcmp(dent->d_name, "..") == 0 ||
263 !name_in_tp_list(dent->d_name, tps)) 277 !name_in_tp_list(dent->d_name, tps))
264 continue; 278 continue;
265 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 279 format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
280 if (!format) {
281 err = -ENOMEM;
282 goto out;
283 }
266 sprintf(format, "%s/%s/format", sys, dent->d_name); 284 sprintf(format, "%s/%s/format", sys, dent->d_name);
267 ret = stat(format, &st); 285 ret = stat(format, &st);
268 286
269 if (ret >= 0) 287 if (ret >= 0) {
270 record_file(format, 8); 288 err = record_file(format, 8);
271 289 if (err) {
290 free(format);
291 goto out;
292 }
293 }
272 free(format); 294 free(format);
273 } 295 }
296 err = 0;
297out:
274 closedir(dir); 298 closedir(dir);
299 return err;
275} 300}
276 301
277static void read_ftrace_files(struct tracepoint_path *tps) 302static int read_ftrace_files(struct tracepoint_path *tps)
278{ 303{
279 char *path; 304 char *path;
305 int ret;
280 306
281 path = get_tracing_file("events/ftrace"); 307 path = get_tracing_file("events/ftrace");
308 if (!path) {
309 pr_debug("can't get tracing/events/ftrace");
310 return -ENOMEM;
311 }
282 312
283 copy_event_system(path, tps); 313 ret = copy_event_system(path, tps);
284 314
285 put_tracing_file(path); 315 put_tracing_file(path);
316
317 return ret;
286} 318}
287 319
288static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) 320static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -296,7 +328,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
296 return false; 328 return false;
297} 329}
298 330
299static void read_event_files(struct tracepoint_path *tps) 331static int read_event_files(struct tracepoint_path *tps)
300{ 332{
301 struct dirent *dent; 333 struct dirent *dent;
302 struct stat st; 334 struct stat st;
@@ -305,12 +337,20 @@ static void read_event_files(struct tracepoint_path *tps)
305 DIR *dir; 337 DIR *dir;
306 int count = 0; 338 int count = 0;
307 int ret; 339 int ret;
340 int err;
308 341
309 path = get_tracing_file("events"); 342 path = get_tracing_file("events");
343 if (!path) {
344 pr_debug("can't get tracing/events");
345 return -ENOMEM;
346 }
310 347
311 dir = opendir(path); 348 dir = opendir(path);
312 if (!dir) 349 if (!dir) {
313 die("can't read directory '%s'", path); 350 err = -errno;
351 pr_debug("can't read directory '%s'", path);
352 goto out;
353 }
314 354
315 while ((dent = readdir(dir))) { 355 while ((dent = readdir(dir))) {
316 if (dent->d_type != DT_DIR || 356 if (dent->d_type != DT_DIR ||
@@ -322,7 +362,11 @@ static void read_event_files(struct tracepoint_path *tps)
322 count++; 362 count++;
323 } 363 }
324 364
325 write_or_die(&count, 4); 365 if (write(output_fd, &count, 4) != 4) {
366 err = -EIO;
367 pr_debug("can't write count\n");
368 goto out;
369 }
326 370
327 rewinddir(dir); 371 rewinddir(dir);
328 while ((dent = readdir(dir))) { 372 while ((dent = readdir(dir))) {
@@ -332,56 +376,90 @@ static void read_event_files(struct tracepoint_path *tps)
332 strcmp(dent->d_name, "ftrace") == 0 || 376 strcmp(dent->d_name, "ftrace") == 0 ||
333 !system_in_tp_list(dent->d_name, tps)) 377 !system_in_tp_list(dent->d_name, tps))
334 continue; 378 continue;
335 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 379 sys = malloc(strlen(path) + strlen(dent->d_name) + 2);
380 if (!sys) {
381 err = -ENOMEM;
382 goto out;
383 }
336 sprintf(sys, "%s/%s", path, dent->d_name); 384 sprintf(sys, "%s/%s", path, dent->d_name);
337 ret = stat(sys, &st); 385 ret = stat(sys, &st);
338 if (ret >= 0) { 386 if (ret >= 0) {
339 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 387 ssize_t size = strlen(dent->d_name) + 1;
340 copy_event_system(sys, tps); 388
389 if (write(output_fd, dent->d_name, size) != size ||
390 copy_event_system(sys, tps) < 0) {
391 err = -EIO;
392 free(sys);
393 goto out;
394 }
341 } 395 }
342 free(sys); 396 free(sys);
343 } 397 }
344 398 err = 0;
399out:
345 closedir(dir); 400 closedir(dir);
346 put_tracing_file(path); 401 put_tracing_file(path);
402
403 return err;
347} 404}
348 405
349static void read_proc_kallsyms(void) 406static int read_proc_kallsyms(void)
350{ 407{
351 unsigned int size; 408 unsigned int size;
352 const char *path = "/proc/kallsyms"; 409 const char *path = "/proc/kallsyms";
353 struct stat st; 410 struct stat st;
354 int ret; 411 int ret, err = 0;
355 412
356 ret = stat(path, &st); 413 ret = stat(path, &st);
357 if (ret < 0) { 414 if (ret < 0) {
358 /* not found */ 415 /* not found */
359 size = 0; 416 size = 0;
360 write_or_die(&size, 4); 417 if (write(output_fd, &size, 4) != 4)
361 return; 418 err = -EIO;
419 return err;
362 } 420 }
363 record_file(path, 4); 421 return record_file(path, 4);
364} 422}
365 423
366static void read_ftrace_printk(void) 424static int read_ftrace_printk(void)
367{ 425{
368 unsigned int size; 426 unsigned int size;
369 char *path; 427 char *path;
370 struct stat st; 428 struct stat st;
371 int ret; 429 int ret, err = 0;
372 430
373 path = get_tracing_file("printk_formats"); 431 path = get_tracing_file("printk_formats");
432 if (!path) {
433 pr_debug("can't get tracing/printk_formats");
434 return -ENOMEM;
435 }
436
374 ret = stat(path, &st); 437 ret = stat(path, &st);
375 if (ret < 0) { 438 if (ret < 0) {
376 /* not found */ 439 /* not found */
377 size = 0; 440 size = 0;
378 write_or_die(&size, 4); 441 if (write(output_fd, &size, 4) != 4)
442 err = -EIO;
379 goto out; 443 goto out;
380 } 444 }
381 record_file(path, 4); 445 err = record_file(path, 4);
382 446
383out: 447out:
384 put_tracing_file(path); 448 put_tracing_file(path);
449 return err;
450}
451
452static void
453put_tracepoints_path(struct tracepoint_path *tps)
454{
455 while (tps) {
456 struct tracepoint_path *t = tps;
457
458 tps = tps->next;
459 free(t->name);
460 free(t->system);
461 free(t);
462 }
385} 463}
386 464
387static struct tracepoint_path * 465static struct tracepoint_path *
@@ -396,27 +474,17 @@ get_tracepoints_path(struct list_head *pattrs)
396 continue; 474 continue;
397 ++nr_tracepoints; 475 ++nr_tracepoints;
398 ppath->next = tracepoint_id_to_path(pos->attr.config); 476 ppath->next = tracepoint_id_to_path(pos->attr.config);
399 if (!ppath->next) 477 if (!ppath->next) {
400 die("%s\n", "No memory to alloc tracepoints list"); 478 pr_debug("No memory to alloc tracepoints list\n");
479 put_tracepoints_path(&path);
480 return NULL;
481 }
401 ppath = ppath->next; 482 ppath = ppath->next;
402 } 483 }
403 484
404 return nr_tracepoints > 0 ? path.next : NULL; 485 return nr_tracepoints > 0 ? path.next : NULL;
405} 486}
406 487
407static void
408put_tracepoints_path(struct tracepoint_path *tps)
409{
410 while (tps) {
411 struct tracepoint_path *t = tps;
412
413 tps = tps->next;
414 free(t->name);
415 free(t->system);
416 free(t);
417 }
418}
419
420bool have_tracepoints(struct list_head *pattrs) 488bool have_tracepoints(struct list_head *pattrs)
421{ 489{
422 struct perf_evsel *pos; 490 struct perf_evsel *pos;
@@ -428,9 +496,10 @@ bool have_tracepoints(struct list_head *pattrs)
428 return false; 496 return false;
429} 497}
430 498
431static void tracing_data_header(void) 499static int tracing_data_header(void)
432{ 500{
433 char buf[20]; 501 char buf[20];
502 ssize_t size;
434 503
435 /* just guessing this is someone's birthday.. ;) */ 504 /* just guessing this is someone's birthday.. ;) */
436 buf[0] = 23; 505 buf[0] = 23;
@@ -438,9 +507,12 @@ static void tracing_data_header(void)
438 buf[2] = 68; 507 buf[2] = 68;
439 memcpy(buf + 3, "tracing", 7); 508 memcpy(buf + 3, "tracing", 7);
440 509
441 write_or_die(buf, 10); 510 if (write(output_fd, buf, 10) != 10)
511 return -1;
442 512
443 write_or_die(VERSION, strlen(VERSION) + 1); 513 size = strlen(VERSION) + 1;
514 if (write(output_fd, VERSION, size) != size)
515 return -1;
444 516
445 /* save endian */ 517 /* save endian */
446 if (bigendian()) 518 if (bigendian())
@@ -450,15 +522,19 @@ static void tracing_data_header(void)
450 522
451 read_trace_init(buf[0], buf[0]); 523 read_trace_init(buf[0], buf[0]);
452 524
453 write_or_die(buf, 1); 525 if (write(output_fd, buf, 1) != 1)
526 return -1;
454 527
455 /* save size of long */ 528 /* save size of long */
456 buf[0] = sizeof(long); 529 buf[0] = sizeof(long);
457 write_or_die(buf, 1); 530 if (write(output_fd, buf, 1) != 1)
531 return -1;
458 532
459 /* save page_size */ 533 /* save page_size */
460 page_size = sysconf(_SC_PAGESIZE); 534 if (write(output_fd, &page_size, 4) != 4)
461 write_or_die(&page_size, 4); 535 return -1;
536
537 return 0;
462} 538}
463 539
464struct tracing_data *tracing_data_get(struct list_head *pattrs, 540struct tracing_data *tracing_data_get(struct list_head *pattrs,
@@ -466,6 +542,7 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
466{ 542{
467 struct tracepoint_path *tps; 543 struct tracepoint_path *tps;
468 struct tracing_data *tdata; 544 struct tracing_data *tdata;
545 int err;
469 546
470 output_fd = fd; 547 output_fd = fd;
471 548
@@ -473,7 +550,10 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
473 if (!tps) 550 if (!tps)
474 return NULL; 551 return NULL;
475 552
476 tdata = malloc_or_die(sizeof(*tdata)); 553 tdata = malloc(sizeof(*tdata));
554 if (!tdata)
555 return NULL;
556
477 tdata->temp = temp; 557 tdata->temp = temp;
478 tdata->size = 0; 558 tdata->size = 0;
479 559
@@ -482,12 +562,16 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
482 562
483 snprintf(tdata->temp_file, sizeof(tdata->temp_file), 563 snprintf(tdata->temp_file, sizeof(tdata->temp_file),
484 "/tmp/perf-XXXXXX"); 564 "/tmp/perf-XXXXXX");
485 if (!mkstemp(tdata->temp_file)) 565 if (!mkstemp(tdata->temp_file)) {
486 die("Can't make temp file"); 566 pr_debug("Can't make temp file");
567 return NULL;
568 }
487 569
488 temp_fd = open(tdata->temp_file, O_RDWR); 570 temp_fd = open(tdata->temp_file, O_RDWR);
489 if (temp_fd < 0) 571 if (temp_fd < 0) {
490 die("Can't read '%s'", tdata->temp_file); 572 pr_debug("Can't read '%s'", tdata->temp_file);
573 return NULL;
574 }
491 575
492 /* 576 /*
493 * Set the temp file the default output, so all the 577 * Set the temp file the default output, so all the
@@ -496,13 +580,24 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
496 output_fd = temp_fd; 580 output_fd = temp_fd;
497 } 581 }
498 582
499 tracing_data_header(); 583 err = tracing_data_header();
500 read_header_files(); 584 if (err)
501 read_ftrace_files(tps); 585 goto out;
502 read_event_files(tps); 586 err = read_header_files();
503 read_proc_kallsyms(); 587 if (err)
504 read_ftrace_printk(); 588 goto out;
589 err = read_ftrace_files(tps);
590 if (err)
591 goto out;
592 err = read_event_files(tps);
593 if (err)
594 goto out;
595 err = read_proc_kallsyms();
596 if (err)
597 goto out;
598 err = read_ftrace_printk();
505 599
600out:
506 /* 601 /*
507 * All tracing data are stored by now, we can restore 602 * All tracing data are stored by now, we can restore
508 * the default output file in case we used temp file. 603 * the default output file in case we used temp file.
@@ -513,22 +608,31 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
513 output_fd = fd; 608 output_fd = fd;
514 } 609 }
515 610
611 if (err) {
612 free(tdata);
613 tdata = NULL;
614 }
615
516 put_tracepoints_path(tps); 616 put_tracepoints_path(tps);
517 return tdata; 617 return tdata;
518} 618}
519 619
520void tracing_data_put(struct tracing_data *tdata) 620int tracing_data_put(struct tracing_data *tdata)
521{ 621{
622 int err = 0;
623
522 if (tdata->temp) { 624 if (tdata->temp) {
523 record_file(tdata->temp_file, 0); 625 err = record_file(tdata->temp_file, 0);
524 unlink(tdata->temp_file); 626 unlink(tdata->temp_file);
525 } 627 }
526 628
527 free(tdata); 629 free(tdata);
630 return err;
528} 631}
529 632
530int read_tracing_data(int fd, struct list_head *pattrs) 633int read_tracing_data(int fd, struct list_head *pattrs)
531{ 634{
635 int err;
532 struct tracing_data *tdata; 636 struct tracing_data *tdata;
533 637
534 /* 638 /*
@@ -539,6 +643,6 @@ int read_tracing_data(int fd, struct list_head *pattrs)
539 if (!tdata) 643 if (!tdata)
540 return -ENOMEM; 644 return -ENOMEM;
541 645
542 tracing_data_put(tdata); 646 err = tracing_data_put(tdata);
543 return 0; 647 return err;
544} 648}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 3aabcd687cd5..4454835a9ebc 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -183,43 +183,6 @@ void event_format__print(struct event_format *event,
183 trace_seq_do_printf(&s); 183 trace_seq_do_printf(&s);
184} 184}
185 185
186void print_trace_event(struct pevent *pevent, int cpu, void *data, int size)
187{
188 int type = trace_parse_common_type(pevent, data);
189 struct event_format *event = pevent_find_event(pevent, type);
190
191 if (!event) {
192 warning("ug! no event found for type %d", type);
193 return;
194 }
195
196 event_format__print(event, cpu, data, size);
197}
198
199void print_event(struct pevent *pevent, int cpu, void *data, int size,
200 unsigned long long nsecs, char *comm)
201{
202 struct pevent_record record;
203 struct trace_seq s;
204 int pid;
205
206 pevent->latency_format = latency_format;
207
208 record.ts = nsecs;
209 record.cpu = cpu;
210 record.size = size;
211 record.data = data;
212 pid = pevent_data_pid(pevent, &record);
213
214 if (!pevent_pid_is_registered(pevent, pid))
215 pevent_register_comm(pevent, comm, pid);
216
217 trace_seq_init(&s);
218 pevent_print_event(pevent, &s, &record);
219 trace_seq_do_printf(&s);
220 printf("\n");
221}
222
223void parse_proc_kallsyms(struct pevent *pevent, 186void parse_proc_kallsyms(struct pevent *pevent,
224 char *file, unsigned int size __maybe_unused) 187 char *file, unsigned int size __maybe_unused)
225{ 188{
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 3741572696af..af215c0d2379 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -18,8 +18,6 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _FILE_OFFSET_BITS 64
22
23#include <dirent.h> 21#include <dirent.h>
24#include <stdio.h> 22#include <stdio.h>
25#include <stdlib.h> 23#include <stdlib.h>
@@ -41,26 +39,14 @@
41 39
42static int input_fd; 40static int input_fd;
43 41
44static int read_page;
45
46int file_bigendian; 42int file_bigendian;
47int host_bigendian; 43int host_bigendian;
48static int long_size; 44static int long_size;
49 45
50static ssize_t calc_data_size; 46static ssize_t trace_data_size;
51static bool repipe; 47static bool repipe;
52 48
53static void *malloc_or_die(int size) 49static int __do_read(int fd, void *buf, int size)
54{
55 void *ret;
56
57 ret = malloc(size);
58 if (!ret)
59 die("malloc");
60 return ret;
61}
62
63static int do_read(int fd, void *buf, int size)
64{ 50{
65 int rsize = size; 51 int rsize = size;
66 52
@@ -73,8 +59,10 @@ static int do_read(int fd, void *buf, int size)
73 if (repipe) { 59 if (repipe) {
74 int retw = write(STDOUT_FILENO, buf, ret); 60 int retw = write(STDOUT_FILENO, buf, ret);
75 61
76 if (retw <= 0 || retw != ret) 62 if (retw <= 0 || retw != ret) {
77 die("repiping input file"); 63 pr_debug("repiping input file");
64 return -1;
65 }
78 } 66 }
79 67
80 size -= ret; 68 size -= ret;
@@ -84,17 +72,18 @@ static int do_read(int fd, void *buf, int size)
84 return rsize; 72 return rsize;
85} 73}
86 74
87static int read_or_die(void *data, int size) 75static int do_read(void *data, int size)
88{ 76{
89 int r; 77 int r;
90 78
91 r = do_read(input_fd, data, size); 79 r = __do_read(input_fd, data, size);
92 if (r <= 0) 80 if (r <= 0) {
93 die("reading input file (size expected=%d received=%d)", 81 pr_debug("reading input file (size expected=%d received=%d)",
94 size, r); 82 size, r);
83 return -1;
84 }
95 85
96 if (calc_data_size) 86 trace_data_size += r;
97 calc_data_size += r;
98 87
99 return r; 88 return r;
100} 89}
@@ -107,7 +96,7 @@ static void skip(int size)
107 96
108 while (size) { 97 while (size) {
109 r = size > BUFSIZ ? BUFSIZ : size; 98 r = size > BUFSIZ ? BUFSIZ : size;
110 read_or_die(buf, r); 99 do_read(buf, r);
111 size -= r; 100 size -= r;
112 }; 101 };
113} 102}
@@ -116,7 +105,8 @@ static unsigned int read4(struct pevent *pevent)
116{ 105{
117 unsigned int data; 106 unsigned int data;
118 107
119 read_or_die(&data, 4); 108 if (do_read(&data, 4) < 0)
109 return 0;
120 return __data2host4(pevent, data); 110 return __data2host4(pevent, data);
121} 111}
122 112
@@ -124,7 +114,8 @@ static unsigned long long read8(struct pevent *pevent)
124{ 114{
125 unsigned long long data; 115 unsigned long long data;
126 116
127 read_or_die(&data, 8); 117 if (do_read(&data, 8) < 0)
118 return 0;
128 return __data2host8(pevent, data); 119 return __data2host8(pevent, data);
129} 120}
130 121
@@ -138,17 +129,23 @@ static char *read_string(void)
138 129
139 for (;;) { 130 for (;;) {
140 r = read(input_fd, &c, 1); 131 r = read(input_fd, &c, 1);
141 if (r < 0) 132 if (r < 0) {
142 die("reading input file"); 133 pr_debug("reading input file");
134 goto out;
135 }
143 136
144 if (!r) 137 if (!r) {
145 die("no data"); 138 pr_debug("no data");
139 goto out;
140 }
146 141
147 if (repipe) { 142 if (repipe) {
148 int retw = write(STDOUT_FILENO, &c, 1); 143 int retw = write(STDOUT_FILENO, &c, 1);
149 144
150 if (retw <= 0 || retw != r) 145 if (retw <= 0 || retw != r) {
151 die("repiping input file string"); 146 pr_debug("repiping input file string");
147 goto out;
148 }
152 } 149 }
153 150
154 buf[size++] = c; 151 buf[size++] = c;
@@ -157,60 +154,79 @@ static char *read_string(void)
157 break; 154 break;
158 } 155 }
159 156
160 if (calc_data_size) 157 trace_data_size += size;
161 calc_data_size += size;
162
163 str = malloc_or_die(size);
164 memcpy(str, buf, size);
165 158
159 str = malloc(size);
160 if (str)
161 memcpy(str, buf, size);
162out:
166 return str; 163 return str;
167} 164}
168 165
169static void read_proc_kallsyms(struct pevent *pevent) 166static int read_proc_kallsyms(struct pevent *pevent)
170{ 167{
171 unsigned int size; 168 unsigned int size;
172 char *buf; 169 char *buf;
173 170
174 size = read4(pevent); 171 size = read4(pevent);
175 if (!size) 172 if (!size)
176 return; 173 return 0;
174
175 buf = malloc(size + 1);
176 if (buf == NULL)
177 return -1;
177 178
178 buf = malloc_or_die(size + 1); 179 if (do_read(buf, size) < 0) {
179 read_or_die(buf, size); 180 free(buf);
181 return -1;
182 }
180 buf[size] = '\0'; 183 buf[size] = '\0';
181 184
182 parse_proc_kallsyms(pevent, buf, size); 185 parse_proc_kallsyms(pevent, buf, size);
183 186
184 free(buf); 187 free(buf);
188 return 0;
185} 189}
186 190
187static void read_ftrace_printk(struct pevent *pevent) 191static int read_ftrace_printk(struct pevent *pevent)
188{ 192{
189 unsigned int size; 193 unsigned int size;
190 char *buf; 194 char *buf;
191 195
196 /* it can have 0 size */
192 size = read4(pevent); 197 size = read4(pevent);
193 if (!size) 198 if (!size)
194 return; 199 return 0;
200
201 buf = malloc(size);
202 if (buf == NULL)
203 return -1;
195 204
196 buf = malloc_or_die(size); 205 if (do_read(buf, size) < 0) {
197 read_or_die(buf, size); 206 free(buf);
207 return -1;
208 }
198 209
199 parse_ftrace_printk(pevent, buf, size); 210 parse_ftrace_printk(pevent, buf, size);
200 211
201 free(buf); 212 free(buf);
213 return 0;
202} 214}
203 215
204static void read_header_files(struct pevent *pevent) 216static int read_header_files(struct pevent *pevent)
205{ 217{
206 unsigned long long size; 218 unsigned long long size;
207 char *header_event; 219 char *header_event;
208 char buf[BUFSIZ]; 220 char buf[BUFSIZ];
221 int ret = 0;
209 222
210 read_or_die(buf, 12); 223 if (do_read(buf, 12) < 0)
224 return -1;
211 225
212 if (memcmp(buf, "header_page", 12) != 0) 226 if (memcmp(buf, "header_page", 12) != 0) {
213 die("did not read header page"); 227 pr_debug("did not read header page");
228 return -1;
229 }
214 230
215 size = read8(pevent); 231 size = read8(pevent);
216 skip(size); 232 skip(size);
@@ -221,269 +237,107 @@ static void read_header_files(struct pevent *pevent)
221 */ 237 */
222 long_size = header_page_size_size; 238 long_size = header_page_size_size;
223 239
224 read_or_die(buf, 13); 240 if (do_read(buf, 13) < 0)
225 if (memcmp(buf, "header_event", 13) != 0) 241 return -1;
226 die("did not read header event"); 242
243 if (memcmp(buf, "header_event", 13) != 0) {
244 pr_debug("did not read header event");
245 return -1;
246 }
227 247
228 size = read8(pevent); 248 size = read8(pevent);
229 header_event = malloc_or_die(size); 249 header_event = malloc(size);
230 read_or_die(header_event, size); 250 if (header_event == NULL)
251 return -1;
252
253 if (do_read(header_event, size) < 0)
254 ret = -1;
255
231 free(header_event); 256 free(header_event);
257 return ret;
232} 258}
233 259
234static void read_ftrace_file(struct pevent *pevent, unsigned long long size) 260static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
235{ 261{
236 char *buf; 262 char *buf;
237 263
238 buf = malloc_or_die(size); 264 buf = malloc(size);
239 read_or_die(buf, size); 265 if (buf == NULL)
266 return -1;
267
268 if (do_read(buf, size) < 0) {
269 free(buf);
270 return -1;
271 }
272
240 parse_ftrace_file(pevent, buf, size); 273 parse_ftrace_file(pevent, buf, size);
241 free(buf); 274 free(buf);
275 return 0;
242} 276}
243 277
244static void read_event_file(struct pevent *pevent, char *sys, 278static int read_event_file(struct pevent *pevent, char *sys,
245 unsigned long long size) 279 unsigned long long size)
246{ 280{
247 char *buf; 281 char *buf;
248 282
249 buf = malloc_or_die(size); 283 buf = malloc(size);
250 read_or_die(buf, size); 284 if (buf == NULL)
285 return -1;
286
287 if (do_read(buf, size) < 0) {
288 free(buf);
289 return -1;
290 }
291
251 parse_event_file(pevent, buf, size, sys); 292 parse_event_file(pevent, buf, size, sys);
252 free(buf); 293 free(buf);
294 return 0;
253} 295}
254 296
255static void read_ftrace_files(struct pevent *pevent) 297static int read_ftrace_files(struct pevent *pevent)
256{ 298{
257 unsigned long long size; 299 unsigned long long size;
258 int count; 300 int count;
259 int i; 301 int i;
302 int ret;
260 303
261 count = read4(pevent); 304 count = read4(pevent);
262 305
263 for (i = 0; i < count; i++) { 306 for (i = 0; i < count; i++) {
264 size = read8(pevent); 307 size = read8(pevent);
265 read_ftrace_file(pevent, size); 308 ret = read_ftrace_file(pevent, size);
309 if (ret)
310 return ret;
266 } 311 }
312 return 0;
267} 313}
268 314
269static void read_event_files(struct pevent *pevent) 315static int read_event_files(struct pevent *pevent)
270{ 316{
271 unsigned long long size; 317 unsigned long long size;
272 char *sys; 318 char *sys;
273 int systems; 319 int systems;
274 int count; 320 int count;
275 int i,x; 321 int i,x;
322 int ret;
276 323
277 systems = read4(pevent); 324 systems = read4(pevent);
278 325
279 for (i = 0; i < systems; i++) { 326 for (i = 0; i < systems; i++) {
280 sys = read_string(); 327 sys = read_string();
328 if (sys == NULL)
329 return -1;
281 330
282 count = read4(pevent); 331 count = read4(pevent);
332
283 for (x=0; x < count; x++) { 333 for (x=0; x < count; x++) {
284 size = read8(pevent); 334 size = read8(pevent);
285 read_event_file(pevent, sys, size); 335 ret = read_event_file(pevent, sys, size);
336 if (ret)
337 return ret;
286 } 338 }
287 } 339 }
288} 340 return 0;
289
290struct cpu_data {
291 unsigned long long offset;
292 unsigned long long size;
293 unsigned long long timestamp;
294 struct pevent_record *next;
295 char *page;
296 int cpu;
297 int index;
298 int page_size;
299};
300
301static struct cpu_data *cpu_data;
302
303static void update_cpu_data_index(int cpu)
304{
305 cpu_data[cpu].offset += page_size;
306 cpu_data[cpu].size -= page_size;
307 cpu_data[cpu].index = 0;
308}
309
310static void get_next_page(int cpu)
311{
312 off_t save_seek;
313 off_t ret;
314
315 if (!cpu_data[cpu].page)
316 return;
317
318 if (read_page) {
319 if (cpu_data[cpu].size <= page_size) {
320 free(cpu_data[cpu].page);
321 cpu_data[cpu].page = NULL;
322 return;
323 }
324
325 update_cpu_data_index(cpu);
326
327 /* other parts of the code may expect the pointer to not move */
328 save_seek = lseek(input_fd, 0, SEEK_CUR);
329
330 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
331 if (ret == (off_t)-1)
332 die("failed to lseek");
333 ret = read(input_fd, cpu_data[cpu].page, page_size);
334 if (ret < 0)
335 die("failed to read page");
336
337 /* reset the file pointer back */
338 lseek(input_fd, save_seek, SEEK_SET);
339
340 return;
341 }
342
343 munmap(cpu_data[cpu].page, page_size);
344 cpu_data[cpu].page = NULL;
345
346 if (cpu_data[cpu].size <= page_size)
347 return;
348
349 update_cpu_data_index(cpu);
350
351 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
352 input_fd, cpu_data[cpu].offset);
353 if (cpu_data[cpu].page == MAP_FAILED)
354 die("failed to mmap cpu %d at offset 0x%llx",
355 cpu, cpu_data[cpu].offset);
356}
357
358static unsigned int type_len4host(unsigned int type_len_ts)
359{
360 if (file_bigendian)
361 return (type_len_ts >> 27) & ((1 << 5) - 1);
362 else
363 return type_len_ts & ((1 << 5) - 1);
364}
365
366static unsigned int ts4host(unsigned int type_len_ts)
367{
368 if (file_bigendian)
369 return type_len_ts & ((1 << 27) - 1);
370 else
371 return type_len_ts >> 5;
372}
373
374static int calc_index(void *ptr, int cpu)
375{
376 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
377}
378
379struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu)
380{
381 struct pevent_record *data;
382 void *page = cpu_data[cpu].page;
383 int idx = cpu_data[cpu].index;
384 void *ptr = page + idx;
385 unsigned long long extend;
386 unsigned int type_len_ts;
387 unsigned int type_len;
388 unsigned int delta;
389 unsigned int length = 0;
390
391 if (cpu_data[cpu].next)
392 return cpu_data[cpu].next;
393
394 if (!page)
395 return NULL;
396
397 if (!idx) {
398 /* FIXME: handle header page */
399 if (header_page_ts_size != 8)
400 die("expected a long long type for timestamp");
401 cpu_data[cpu].timestamp = data2host8(pevent, ptr);
402 ptr += 8;
403 switch (header_page_size_size) {
404 case 4:
405 cpu_data[cpu].page_size = data2host4(pevent, ptr);
406 ptr += 4;
407 break;
408 case 8:
409 cpu_data[cpu].page_size = data2host8(pevent, ptr);
410 ptr += 8;
411 break;
412 default:
413 die("bad long size");
414 }
415 ptr = cpu_data[cpu].page + header_page_data_offset;
416 }
417
418read_again:
419 idx = calc_index(ptr, cpu);
420
421 if (idx >= cpu_data[cpu].page_size) {
422 get_next_page(cpu);
423 return trace_peek_data(pevent, cpu);
424 }
425
426 type_len_ts = data2host4(pevent, ptr);
427 ptr += 4;
428
429 type_len = type_len4host(type_len_ts);
430 delta = ts4host(type_len_ts);
431
432 switch (type_len) {
433 case RINGBUF_TYPE_PADDING:
434 if (!delta)
435 die("error, hit unexpected end of page");
436 length = data2host4(pevent, ptr);
437 ptr += 4;
438 length *= 4;
439 ptr += length;
440 goto read_again;
441
442 case RINGBUF_TYPE_TIME_EXTEND:
443 extend = data2host4(pevent, ptr);
444 ptr += 4;
445 extend <<= TS_SHIFT;
446 extend += delta;
447 cpu_data[cpu].timestamp += extend;
448 goto read_again;
449
450 case RINGBUF_TYPE_TIME_STAMP:
451 ptr += 12;
452 break;
453 case 0:
454 length = data2host4(pevent, ptr);
455 ptr += 4;
456 die("here! length=%d", length);
457 break;
458 default:
459 length = type_len * 4;
460 break;
461 }
462
463 cpu_data[cpu].timestamp += delta;
464
465 data = malloc_or_die(sizeof(*data));
466 memset(data, 0, sizeof(*data));
467
468 data->ts = cpu_data[cpu].timestamp;
469 data->size = length;
470 data->data = ptr;
471 ptr += length;
472
473 cpu_data[cpu].index = calc_index(ptr, cpu);
474 cpu_data[cpu].next = data;
475
476 return data;
477}
478
479struct pevent_record *trace_read_data(struct pevent *pevent, int cpu)
480{
481 struct pevent_record *data;
482
483 data = trace_peek_data(pevent, cpu);
484 cpu_data[cpu].next = NULL;
485
486 return data;
487} 341}
488 342
489ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) 343ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
@@ -494,58 +348,85 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
494 int show_version = 0; 348 int show_version = 0;
495 int show_funcs = 0; 349 int show_funcs = 0;
496 int show_printk = 0; 350 int show_printk = 0;
497 ssize_t size; 351 ssize_t size = -1;
352 struct pevent *pevent;
353 int err;
498 354
499 calc_data_size = 1; 355 *ppevent = NULL;
500 repipe = __repipe;
501 356
357 repipe = __repipe;
502 input_fd = fd; 358 input_fd = fd;
503 359
504 read_or_die(buf, 3); 360 if (do_read(buf, 3) < 0)
505 if (memcmp(buf, test, 3) != 0) 361 return -1;
506 die("no trace data in the file"); 362 if (memcmp(buf, test, 3) != 0) {
363 pr_debug("no trace data in the file");
364 return -1;
365 }
507 366
508 read_or_die(buf, 7); 367 if (do_read(buf, 7) < 0)
509 if (memcmp(buf, "tracing", 7) != 0) 368 return -1;
510 die("not a trace file (missing 'tracing' tag)"); 369 if (memcmp(buf, "tracing", 7) != 0) {
370 pr_debug("not a trace file (missing 'tracing' tag)");
371 return -1;
372 }
511 373
512 version = read_string(); 374 version = read_string();
375 if (version == NULL)
376 return -1;
513 if (show_version) 377 if (show_version)
514 printf("version = %s\n", version); 378 printf("version = %s\n", version);
515 free(version); 379 free(version);
516 380
517 read_or_die(buf, 1); 381 if (do_read(buf, 1) < 0)
382 return -1;
518 file_bigendian = buf[0]; 383 file_bigendian = buf[0];
519 host_bigendian = bigendian(); 384 host_bigendian = bigendian();
520 385
521 *ppevent = read_trace_init(file_bigendian, host_bigendian); 386 pevent = read_trace_init(file_bigendian, host_bigendian);
522 if (*ppevent == NULL) 387 if (pevent == NULL) {
523 die("read_trace_init failed"); 388 pr_debug("read_trace_init failed");
389 goto out;
390 }
524 391
525 read_or_die(buf, 1); 392 if (do_read(buf, 1) < 0)
393 goto out;
526 long_size = buf[0]; 394 long_size = buf[0];
527 395
528 page_size = read4(*ppevent); 396 page_size = read4(pevent);
529 397 if (!page_size)
530 read_header_files(*ppevent); 398 goto out;
531 399
532 read_ftrace_files(*ppevent); 400 err = read_header_files(pevent);
533 read_event_files(*ppevent); 401 if (err)
534 read_proc_kallsyms(*ppevent); 402 goto out;
535 read_ftrace_printk(*ppevent); 403 err = read_ftrace_files(pevent);
536 404 if (err)
537 size = calc_data_size - 1; 405 goto out;
538 calc_data_size = 0; 406 err = read_event_files(pevent);
407 if (err)
408 goto out;
409 err = read_proc_kallsyms(pevent);
410 if (err)
411 goto out;
412 err = read_ftrace_printk(pevent);
413 if (err)
414 goto out;
415
416 size = trace_data_size;
539 repipe = false; 417 repipe = false;
540 418
541 if (show_funcs) { 419 if (show_funcs) {
542 pevent_print_funcs(*ppevent); 420 pevent_print_funcs(pevent);
543 return size; 421 } else if (show_printk) {
544 } 422 pevent_print_printk(pevent);
545 if (show_printk) {
546 pevent_print_printk(*ppevent);
547 return size;
548 } 423 }
549 424
425 *ppevent = pevent;
426 pevent = NULL;
427
428out:
429 if (pevent)
430 pevent_free(pevent);
550 return size; 431 return size;
551} 432}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index a55fd37ffea1..1978c398ad87 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -30,13 +30,9 @@ enum {
30int bigendian(void); 30int bigendian(void);
31 31
32struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 32struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
33void print_trace_event(struct pevent *pevent, int cpu, void *data, int size);
34void event_format__print(struct event_format *event, 33void event_format__print(struct event_format *event,
35 int cpu, void *data, int size); 34 int cpu, void *data, int size);
36 35
37void print_event(struct pevent *pevent, int cpu, void *data, int size,
38 unsigned long long nsecs, char *comm);
39
40int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); 36int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
41int parse_event_file(struct pevent *pevent, 37int parse_event_file(struct pevent *pevent,
42 char *buf, unsigned long size, char *sys); 38 char *buf, unsigned long size, char *sys);
@@ -72,7 +68,7 @@ struct tracing_data {
72 68
73struct tracing_data *tracing_data_get(struct list_head *pattrs, 69struct tracing_data *tracing_data_get(struct list_head *pattrs,
74 int fd, bool temp); 70 int fd, bool temp);
75void tracing_data_put(struct tracing_data *tdata); 71int tracing_data_put(struct tracing_data *tdata);
76 72
77 73
78struct addr_location; 74struct addr_location;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 5906e8426cc7..59d868add275 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -12,9 +12,13 @@
12 */ 12 */
13unsigned int page_size; 13unsigned int page_size;
14 14
15bool test_attr__enabled;
16
15bool perf_host = true; 17bool perf_host = true;
16bool perf_guest = false; 18bool perf_guest = false;
17 19
20char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
21
18void event_attr_init(struct perf_event_attr *attr) 22void event_attr_init(struct perf_event_attr *attr)
19{ 23{
20 if (!perf_host) 24 if (!perf_host)
@@ -218,3 +222,50 @@ void dump_stack(void)
218#else 222#else
219void dump_stack(void) {} 223void dump_stack(void) {}
220#endif 224#endif
225
226void get_term_dimensions(struct winsize *ws)
227{
228 char *s = getenv("LINES");
229
230 if (s != NULL) {
231 ws->ws_row = atoi(s);
232 s = getenv("COLUMNS");
233 if (s != NULL) {
234 ws->ws_col = atoi(s);
235 if (ws->ws_row && ws->ws_col)
236 return;
237 }
238 }
239#ifdef TIOCGWINSZ
240 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
241 ws->ws_row && ws->ws_col)
242 return;
243#endif
244 ws->ws_row = 25;
245 ws->ws_col = 80;
246}
247
248static void set_tracing_events_path(const char *mountpoint)
249{
250 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
251 mountpoint, "tracing/events");
252}
253
254const char *perf_debugfs_mount(const char *mountpoint)
255{
256 const char *mnt;
257
258 mnt = debugfs_mount(mountpoint);
259 if (!mnt)
260 return NULL;
261
262 set_tracing_events_path(mnt);
263
264 return mnt;
265}
266
267void perf_debugfs_set_path(const char *mntpt)
268{
269 snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
270 set_tracing_events_path(mntpt);
271}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c2330918110c..7a484c97e500 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -1,8 +1,6 @@
1#ifndef GIT_COMPAT_UTIL_H 1#ifndef GIT_COMPAT_UTIL_H
2#define GIT_COMPAT_UTIL_H 2#define GIT_COMPAT_UTIL_H
3 3
4#define _FILE_OFFSET_BITS 64
5
6#ifndef FLEX_ARRAY 4#ifndef FLEX_ARRAY
7/* 5/*
8 * See if our compiler is known to support flexible array members. 6 * See if our compiler is known to support flexible array members.
@@ -73,10 +71,14 @@
73#include <linux/magic.h> 71#include <linux/magic.h>
74#include "types.h" 72#include "types.h"
75#include <sys/ttydefaults.h> 73#include <sys/ttydefaults.h>
74#include <lk/debugfs.h>
76 75
77extern const char *graph_line; 76extern const char *graph_line;
78extern const char *graph_dotted_line; 77extern const char *graph_dotted_line;
79extern char buildid_dir[]; 78extern char buildid_dir[];
79extern char tracing_events_path[];
80extern void perf_debugfs_set_path(const char *mountpoint);
81const char *perf_debugfs_mount(const char *mountpoint);
80 82
81/* On most systems <limits.h> would have given us this, but 83/* On most systems <limits.h> would have given us this, but
82 * not on some systems (e.g. GNU/Hurd). 84 * not on some systems (e.g. GNU/Hurd).
@@ -219,8 +221,8 @@ extern unsigned char sane_ctype[256];
219#define isalpha(x) sane_istest(x,GIT_ALPHA) 221#define isalpha(x) sane_istest(x,GIT_ALPHA)
220#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 222#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
221#define isprint(x) sane_istest(x,GIT_PRINT) 223#define isprint(x) sane_istest(x,GIT_PRINT)
222#define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20)) 224#define islower(x) (sane_istest(x,GIT_ALPHA) && (x & 0x20))
223#define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20)) 225#define isupper(x) (sane_istest(x,GIT_ALPHA) && !(x & 0x20))
224#define tolower(x) sane_case((unsigned char)(x), 0x20) 226#define tolower(x) sane_case((unsigned char)(x), 0x20)
225#define toupper(x) sane_case((unsigned char)(x), 0) 227#define toupper(x) sane_case((unsigned char)(x), 0)
226 228
@@ -265,10 +267,13 @@ bool is_power_of_2(unsigned long n)
265size_t hex_width(u64 v); 267size_t hex_width(u64 v);
266int hex2u64(const char *ptr, u64 *val); 268int hex2u64(const char *ptr, u64 *val);
267 269
270char *ltrim(char *s);
268char *rtrim(char *s); 271char *rtrim(char *s);
269 272
270void dump_stack(void); 273void dump_stack(void);
271 274
272extern unsigned int page_size; 275extern unsigned int page_size;
273 276
274#endif 277struct winsize;
278void get_term_dimensions(struct winsize *ws);
279#endif /* GIT_COMPAT_UTIL_H */