aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-10-06 11:01:27 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-10-06 11:01:27 -0400
commit907bc6c7fc7071b00083fc11e510e47dd93df45d (patch)
tree0697a608561522c00da9e1814974a2eb051bb96d /tools
parentd2b247a8be57647d1745535acd58169fbcbe431a (diff)
parent2a0f5cb32772e9a9560209e241a80bfbbc31dbc3 (diff)
Merge branch 'for-2.6.32' into for-2.6.33
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/CREDITS30
-rw-r--r--tools/perf/Documentation/Makefile2
-rw-r--r--tools/perf/Documentation/examples.txt225
-rw-r--r--tools/perf/Documentation/perf-record.txt64
-rw-r--r--tools/perf/Documentation/perf-report.txt42
-rw-r--r--tools/perf/Documentation/perf-sched.txt41
-rw-r--r--tools/perf/Documentation/perf-stat.txt6
-rw-r--r--tools/perf/Documentation/perf-timechart.txt38
-rw-r--r--tools/perf/Documentation/perf-top.txt112
-rw-r--r--tools/perf/Documentation/perf-trace.txt25
-rw-r--r--tools/perf/Makefile114
-rw-r--r--tools/perf/builtin-annotate.c579
-rw-r--r--tools/perf/builtin-help.c7
-rw-r--r--tools/perf/builtin-list.c5
-rw-r--r--tools/perf/builtin-record.c344
-rw-r--r--tools/perf/builtin-report.c1423
-rw-r--r--tools/perf/builtin-sched.c2004
-rw-r--r--tools/perf/builtin-stat.c440
-rw-r--r--tools/perf/builtin-timechart.c1158
-rw-r--r--tools/perf/builtin-top.c692
-rw-r--r--tools/perf/builtin-trace.c297
-rw-r--r--tools/perf/builtin.h5
-rw-r--r--tools/perf/command-list.txt3
-rw-r--r--tools/perf/design.txt58
-rw-r--r--tools/perf/perf.c85
-rw-r--r--tools/perf/perf.h53
-rw-r--r--tools/perf/util/abspath.c3
-rw-r--r--tools/perf/util/alias.c2
-rw-r--r--tools/perf/util/cache.h3
-rw-r--r--tools/perf/util/callchain.c345
-rw-r--r--tools/perf/util/callchain.h61
-rw-r--r--tools/perf/util/color.c47
-rw-r--r--tools/perf/util/color.h6
-rw-r--r--tools/perf/util/config.c40
-rw-r--r--tools/perf/util/debug.c95
-rw-r--r--tools/perf/util/debug.h8
-rw-r--r--tools/perf/util/event.h104
-rw-r--r--tools/perf/util/exec_cmd.c6
-rw-r--r--tools/perf/util/header.c339
-rw-r--r--tools/perf/util/header.h47
-rw-r--r--tools/perf/util/help.c41
-rw-r--r--tools/perf/util/help.h6
-rw-r--r--tools/perf/util/include/asm/system.h1
-rw-r--r--tools/perf/util/include/linux/kernel.h29
-rw-r--r--tools/perf/util/include/linux/list.h18
-rw-r--r--tools/perf/util/include/linux/module.h6
-rw-r--r--tools/perf/util/include/linux/poison.h1
-rw-r--r--tools/perf/util/include/linux/prefetch.h6
-rw-r--r--tools/perf/util/include/linux/rbtree.h1
-rw-r--r--tools/perf/util/list.h603
-rw-r--r--tools/perf/util/map.c97
-rw-r--r--tools/perf/util/module.c545
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/pager.c5
-rw-r--r--tools/perf/util/parse-events.c779
-rw-r--r--tools/perf/util/parse-events.h23
-rw-r--r--tools/perf/util/parse-options.c27
-rw-r--r--tools/perf/util/parse-options.h29
-rw-r--r--tools/perf/util/path.c25
-rw-r--r--tools/perf/util/quote.c48
-rw-r--r--tools/perf/util/quote.h2
-rw-r--r--tools/perf/util/rbtree.c383
-rw-r--r--tools/perf/util/rbtree.h171
-rw-r--r--tools/perf/util/run-command.c101
-rw-r--r--tools/perf/util/run-command.h5
-rw-r--r--tools/perf/util/strbuf.c15
-rw-r--r--tools/perf/util/strbuf.h10
-rw-r--r--tools/perf/util/string.h5
-rw-r--r--tools/perf/util/strlist.c200
-rw-r--r--tools/perf/util/strlist.h39
-rw-r--r--tools/perf/util/svghelper.c488
-rw-r--r--tools/perf/util/svghelper.h28
-rw-r--r--tools/perf/util/symbol.c605
-rw-r--r--tools/perf/util/symbol.h55
-rw-r--r--tools/perf/util/thread.c175
-rw-r--r--tools/perf/util/thread.h22
-rw-r--r--tools/perf/util/trace-event-info.c540
-rw-r--r--tools/perf/util/trace-event-parse.c2967
-rw-r--r--tools/perf/util/trace-event-read.c514
-rw-r--r--tools/perf/util/trace-event.h245
-rw-r--r--tools/perf/util/types.h (renamed from tools/perf/types.h)0
-rw-r--r--tools/perf/util/util.h23
-rw-r--r--tools/perf/util/values.c230
-rw-r--r--tools/perf/util/values.h27
-rw-r--r--tools/perf/util/wrapper.c5
86 files changed, 14861 insertions, 3296 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index d69a759a1046..0854f110bf7f 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -10,6 +10,7 @@ perf-stat
10perf-top 10perf-top
11perf*.1 11perf*.1
12perf*.xml 12perf*.xml
13perf*.html
13common-cmds.h 14common-cmds.h
14tags 15tags
15TAGS 16TAGS
diff --git a/tools/perf/CREDITS b/tools/perf/CREDITS
new file mode 100644
index 000000000000..c2ddcb3acbd0
--- /dev/null
+++ b/tools/perf/CREDITS
@@ -0,0 +1,30 @@
1Most of the infrastructure that 'perf' uses here has been reused
2from the Git project, as of version:
3
4 66996ec: Sync with 1.6.2.4
5
6Here is an (incomplete!) list of main contributors to those files
7in util/* and elsewhere:
8
9 Alex Riesen
10 Christian Couder
11 Dmitry Potapov
12 Jeff King
13 Johannes Schindelin
14 Johannes Sixt
15 Junio C Hamano
16 Linus Torvalds
17 Matthias Kestenholz
18 Michal Ostrowski
19 Miklos Vajna
20 Petr Baudis
21 Pierre Habouzit
22 René Scharfe
23 Samuel Tardieu
24 Shawn O. Pearce
25 Steffen Prohaska
26 Steve Haslam
27
28Thanks guys!
29
30The full history of the files can be found in the upstream Git commits.
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index 5457192e1b41..bdd3b7ecad0a 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -35,7 +35,7 @@ man7dir=$(mandir)/man7
35# DESTDIR= 35# DESTDIR=
36 36
37ASCIIDOC=asciidoc 37ASCIIDOC=asciidoc
38ASCIIDOC_EXTRA = 38ASCIIDOC_EXTRA = --unsafe
39MANPAGE_XSL = manpage-normal.xsl 39MANPAGE_XSL = manpage-normal.xsl
40XMLTO_EXTRA = 40XMLTO_EXTRA =
41INSTALL?=install 41INSTALL?=install
diff --git a/tools/perf/Documentation/examples.txt b/tools/perf/Documentation/examples.txt
new file mode 100644
index 000000000000..8eb6c489fb15
--- /dev/null
+++ b/tools/perf/Documentation/examples.txt
@@ -0,0 +1,225 @@
1
2 ------------------------------
3 ****** perf by examples ******
4 ------------------------------
5
6[ From an e-mail by Ingo Molnar, http://lkml.org/lkml/2009/8/4/346 ]
7
8
9First, discovery/enumeration of available counters can be done via
10'perf list':
11
12titan:~> perf list
13 [...]
14 kmem:kmalloc [Tracepoint event]
15 kmem:kmem_cache_alloc [Tracepoint event]
16 kmem:kmalloc_node [Tracepoint event]
17 kmem:kmem_cache_alloc_node [Tracepoint event]
18 kmem:kfree [Tracepoint event]
19 kmem:kmem_cache_free [Tracepoint event]
20 kmem:mm_page_free_direct [Tracepoint event]
21 kmem:mm_pagevec_free [Tracepoint event]
22 kmem:mm_page_alloc [Tracepoint event]
23 kmem:mm_page_alloc_zone_locked [Tracepoint event]
24 kmem:mm_page_pcpu_drain [Tracepoint event]
25 kmem:mm_page_alloc_extfrag [Tracepoint event]
26
27Then any (or all) of the above event sources can be activated and
28measured. For example the page alloc/free properties of a 'hackbench
29run' are:
30
31 titan:~> perf stat -e kmem:mm_page_pcpu_drain -e kmem:mm_page_alloc
32 -e kmem:mm_pagevec_free -e kmem:mm_page_free_direct ./hackbench 10
33 Time: 0.575
34
35 Performance counter stats for './hackbench 10':
36
37 13857 kmem:mm_page_pcpu_drain
38 27576 kmem:mm_page_alloc
39 6025 kmem:mm_pagevec_free
40 20934 kmem:mm_page_free_direct
41
42 0.613972165 seconds time elapsed
43
44You can observe the statistical properties as well, by using the
45'repeat the workload N times' feature of perf stat:
46
47 titan:~> perf stat --repeat 5 -e kmem:mm_page_pcpu_drain -e
48 kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
49 kmem:mm_page_free_direct ./hackbench 10
50 Time: 0.627
51 Time: 0.644
52 Time: 0.564
53 Time: 0.559
54 Time: 0.626
55
56 Performance counter stats for './hackbench 10' (5 runs):
57
58 12920 kmem:mm_page_pcpu_drain ( +- 3.359% )
59 25035 kmem:mm_page_alloc ( +- 3.783% )
60 6104 kmem:mm_pagevec_free ( +- 0.934% )
61 18376 kmem:mm_page_free_direct ( +- 4.941% )
62
63 0.643954516 seconds time elapsed ( +- 2.363% )
64
65Furthermore, these tracepoints can be used to sample the workload as
66well. For example the page allocations done by a 'git gc' can be
67captured the following way:
68
69 titan:~/git> perf record -f -e kmem:mm_page_alloc -c 1 ./git gc
70 Counting objects: 1148, done.
71 Delta compression using up to 2 threads.
72 Compressing objects: 100% (450/450), done.
73 Writing objects: 100% (1148/1148), done.
74 Total 1148 (delta 690), reused 1148 (delta 690)
75 [ perf record: Captured and wrote 0.267 MB perf.data (~11679 samples) ]
76
77To check which functions generated page allocations:
78
79 titan:~/git> perf report
80 # Samples: 10646
81 #
82 # Overhead Command Shared Object
83 # ........ ............... ..........................
84 #
85 23.57% git-repack /lib64/libc-2.5.so
86 21.81% git /lib64/libc-2.5.so
87 14.59% git ./git
88 11.79% git-repack ./git
89 7.12% git /lib64/ld-2.5.so
90 3.16% git-repack /lib64/libpthread-2.5.so
91 2.09% git-repack /bin/bash
92 1.97% rm /lib64/libc-2.5.so
93 1.39% mv /lib64/ld-2.5.so
94 1.37% mv /lib64/libc-2.5.so
95 1.12% git-repack /lib64/ld-2.5.so
96 0.95% rm /lib64/ld-2.5.so
97 0.90% git-update-serv /lib64/libc-2.5.so
98 0.73% git-update-serv /lib64/ld-2.5.so
99 0.68% perf /lib64/libpthread-2.5.so
100 0.64% git-repack /usr/lib64/libz.so.1.2.3
101
102Or to see it on a more finegrained level:
103
104titan:~/git> perf report --sort comm,dso,symbol
105# Samples: 10646
106#
107# Overhead Command Shared Object Symbol
108# ........ ............... .......................... ......
109#
110 9.35% git-repack ./git [.] insert_obj_hash
111 9.12% git ./git [.] insert_obj_hash
112 7.31% git /lib64/libc-2.5.so [.] memcpy
113 6.34% git-repack /lib64/libc-2.5.so [.] _int_malloc
114 6.24% git-repack /lib64/libc-2.5.so [.] memcpy
115 5.82% git-repack /lib64/libc-2.5.so [.] __GI___fork
116 5.47% git /lib64/libc-2.5.so [.] _int_malloc
117 2.99% git /lib64/libc-2.5.so [.] memset
118
119Furthermore, call-graph sampling can be done too, of page
120allocations - to see precisely what kind of page allocations there
121are:
122
123 titan:~/git> perf record -f -g -e kmem:mm_page_alloc -c 1 ./git gc
124 Counting objects: 1148, done.
125 Delta compression using up to 2 threads.
126 Compressing objects: 100% (450/450), done.
127 Writing objects: 100% (1148/1148), done.
128 Total 1148 (delta 690), reused 1148 (delta 690)
129 [ perf record: Captured and wrote 0.963 MB perf.data (~42069 samples) ]
130
131 titan:~/git> perf report -g
132 # Samples: 10686
133 #
134 # Overhead Command Shared Object
135 # ........ ............... ..........................
136 #
137 23.25% git-repack /lib64/libc-2.5.so
138 |
139 |--50.00%-- _int_free
140 |
141 |--37.50%-- __GI___fork
142 | make_child
143 |
144 |--12.50%-- ptmalloc_unlock_all2
145 | make_child
146 |
147 --6.25%-- __GI_strcpy
148 21.61% git /lib64/libc-2.5.so
149 |
150 |--30.00%-- __GI_read
151 | |
152 | --83.33%-- git_config_from_file
153 | git_config
154 | |
155 [...]
156
157Or you can observe the whole system's page allocations for 10
158seconds:
159
160titan:~/git> perf stat -a -e kmem:mm_page_pcpu_drain -e
161kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
162kmem:mm_page_free_direct sleep 10
163
164 Performance counter stats for 'sleep 10':
165
166 171585 kmem:mm_page_pcpu_drain
167 322114 kmem:mm_page_alloc
168 73623 kmem:mm_pagevec_free
169 254115 kmem:mm_page_free_direct
170
171 10.000591410 seconds time elapsed
172
173Or observe how fluctuating the page allocations are, via statistical
174analysis done over ten 1-second intervals:
175
176 titan:~/git> perf stat --repeat 10 -a -e kmem:mm_page_pcpu_drain -e
177 kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
178 kmem:mm_page_free_direct sleep 1
179
180 Performance counter stats for 'sleep 1' (10 runs):
181
182 17254 kmem:mm_page_pcpu_drain ( +- 3.709% )
183 34394 kmem:mm_page_alloc ( +- 4.617% )
184 7509 kmem:mm_pagevec_free ( +- 4.820% )
185 25653 kmem:mm_page_free_direct ( +- 3.672% )
186
187 1.058135029 seconds time elapsed ( +- 3.089% )
188
189Or you can annotate the recorded 'git gc' run on a per symbol basis
190and check which instructions/source-code generated page allocations:
191
192 titan:~/git> perf annotate __GI___fork
193 ------------------------------------------------
194 Percent | Source code & Disassembly of libc-2.5.so
195 ------------------------------------------------
196 :
197 :
198 : Disassembly of section .plt:
199 : Disassembly of section .text:
200 :
201 : 00000031a2e95560 <__fork>:
202 [...]
203 0.00 : 31a2e95602: b8 38 00 00 00 mov $0x38,%eax
204 0.00 : 31a2e95607: 0f 05 syscall
205 83.42 : 31a2e95609: 48 3d 00 f0 ff ff cmp $0xfffffffffffff000,%rax
206 0.00 : 31a2e9560f: 0f 87 4d 01 00 00 ja 31a2e95762 <__fork+0x202>
207 0.00 : 31a2e95615: 85 c0 test %eax,%eax
208
209( this shows that 83.42% of __GI___fork's page allocations come from
210 the 0x38 system call it performs. )
211
212etc. etc. - a lot more is possible. I could list a dozen of
213other different usecases straight away - neither of which is
214possible via /proc/vmstat.
215
216/proc/vmstat is not in the same league really, in terms of
217expressive power of system analysis and performance
218analysis.
219
220All that the above results needed were those new tracepoints
221in include/tracing/events/kmem.h.
222
223 Ingo
224
225
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 1dbc1eeb4c01..0ff23de9e453 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -29,13 +29,71 @@ OPTIONS
29 Select the PMU event. Selection can be a symbolic event name 29 Select the PMU event. Selection can be a symbolic event name
30 (use 'perf list' to list all events) or a raw PMU 30 (use 'perf list' to list all events) or a raw PMU
31 event (eventsel+umask) in the form of rNNN where NNN is a 31 event (eventsel+umask) in the form of rNNN where NNN is a
32 hexadecimal event descriptor. 32 hexadecimal event descriptor.
33 33
34-a:: 34-a::
35 system-wide collection 35 System-wide collection.
36 36
37-l:: 37-l::
38 scale counter values 38 Scale counter values.
39
40-p::
41--pid=::
42 Record events on existing pid.
43
44-r::
45--realtime=::
46 Collect data with this RT SCHED_FIFO priority.
47-A::
48--append::
49 Append to the output file to do incremental profiling.
50
51-f::
52--force::
53 Overwrite existing data file.
54
55-c::
56--count=::
57 Event period to sample.
58
59-o::
60--output=::
61 Output file name.
62
63-i::
64--inherit::
65 Child tasks inherit counters.
66-F::
67--freq=::
68 Profile at this frequency.
69
70-m::
71--mmap-pages=::
72 Number of mmap data pages.
73
74-g::
75--call-graph::
76 Do call-graph (stack chain/backtrace) recording.
77
78-v::
79--verbose::
80 Be more verbose (show counter open errors, etc).
81
82-s::
83--stat::
84 Per thread counts.
85
86-d::
87--data::
88 Sample addresses.
89
90-n::
91--no-samples::
92 Don't sample.
93
94-R::
95--raw-samples::
96Collect raw sample records from all opened counters (typically for tracepoint counters).
39 97
40SEE ALSO 98SEE ALSO
41-------- 99--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 52d3fc6846a9..59f0b846cd71 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -13,13 +13,53 @@ SYNOPSIS
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command displays the performance counter profile information recorded 15This command displays the performance counter profile information recorded
16via perf report. 16via perf record.
17 17
18OPTIONS 18OPTIONS
19------- 19-------
20-i:: 20-i::
21--input=:: 21--input=::
22 Input file name. (default: perf.data) 22 Input file name. (default: perf.data)
23-d::
24--dsos=::
25 Only consider symbols in these dsos. CSV that understands
26 file://filename entries.
27-n
28--show-nr-samples
29 Show the number of samples for each symbol
30-T
31--threads
32 Show per-thread event counters
33-C::
34--comms=::
35 Only consider symbols in these comms. CSV that understands
36 file://filename entries.
37-S::
38--symbols=::
39 Only consider these symbols. CSV that understands
40 file://filename entries.
41
42-w::
43--field-width=::
44 Force each column width to the provided list, for large terminal
45 readability.
46
47-t::
48--field-separator=::
49
50 Use a special separator character and don't pad with spaces, replacing
51 all occurances of this separator in symbol names (and other output)
52 with a '.' character, that thus it's the only non valid separator.
53
54-g [type,min]::
55--call-graph::
56 Display callchains using type and min percent threshold.
57 type can be either:
58 - flat: single column, linear exposure of callchains.
59 - graph: use a graph tree, displaying absolute overhead rates.
60 - fractal: like graph, but displays relative rates. Each branch of
61 the tree is considered as a new profiled object. +
62 Default: fractal,0.5.
23 63
24SEE ALSO 64SEE ALSO
25-------- 65--------
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
new file mode 100644
index 000000000000..1ce79198997b
--- /dev/null
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -0,0 +1,41 @@
1perf-sched(1)
2==============
3
4NAME
5----
6perf-sched - Tool to trace/measure scheduler properties (latencies)
7
8SYNOPSIS
9--------
10[verse]
11'perf sched' {record|latency|replay|trace}
12
13DESCRIPTION
14-----------
15There's four variants of perf sched:
16
17 'perf sched record <command>' to record the scheduling events
18 of an arbitrary workload.
19
20 'perf sched latency' to report the per task scheduling latencies
21 and other scheduling properties of the workload.
22
23 'perf sched trace' to see a detailed trace of the workload that
24 was recorded.
25
26 'perf sched replay' to simulate the workload that was recorded
27 via perf sched record. (this is done by starting up mockup threads
28 that mimic the workload based on the events in the trace. These
29 threads can then replay the timings (CPU runtime and sleep patterns)
30 of the workload as it occured when it was recorded - and can repeat
31 it a number of times, measuring its performance.)
32
33OPTIONS
34-------
35-D::
36--dump-raw-trace=::
37 Display verbose dump of the sched data.
38
39SEE ALSO
40--------
41linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index c368a72721d7..484080dd5b6f 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -8,8 +8,8 @@ perf-stat - Run a command and gather performance counter statistics
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf stat' [-e <EVENT> | --event=EVENT] [-l] [-a] <command> 11'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] <command>
12'perf stat' [-e <EVENT> | --event=EVENT] [-l] [-a] -- <command> [<options>] 12'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] -- <command> [<options>]
13 13
14DESCRIPTION 14DESCRIPTION
15----------- 15-----------
@@ -40,7 +40,7 @@ OPTIONS
40-a:: 40-a::
41 system-wide collection 41 system-wide collection
42 42
43-l:: 43-c::
44 scale counter values 44 scale counter values
45 45
46EXAMPLES 46EXAMPLES
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
new file mode 100644
index 000000000000..1c2ed3090cce
--- /dev/null
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -0,0 +1,38 @@
1perf-timechart(1)
2=================
3
4NAME
5----
6perf-timechart - Tool to visualize total system behavior during a workload
7
8SYNOPSIS
9--------
10[verse]
11'perf timechart' {record}
12
13DESCRIPTION
14-----------
15There are two variants of perf timechart:
16
17 'perf timechart record <command>' to record the system level events
18 of an arbitrary workload.
19
20 'perf timechart' to turn a trace into a Scalable Vector Graphics file,
21 that can be viewed with popular SVG viewers such as 'Inkscape'.
22
23OPTIONS
24-------
25-o::
26--output=::
27 Select the output file (default: output.svg)
28-i::
29--input=::
30 Select the input file (default: perf.data)
31-w::
32--width=::
33 Select the width of the SVG file (default: 1000)
34
35
36SEE ALSO
37--------
38linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 539d01289725..4a7d558dc309 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -3,36 +3,122 @@ perf-top(1)
3 3
4NAME 4NAME
5---- 5----
6perf-top - Run a command and profile it 6perf-top - System profiling tool.
7 7
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf top' [-e <EVENT> | --event=EVENT] [-l] [-a] <command> 11'perf top' [-e <EVENT> | --event=EVENT] [<options>]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command runs a command and gathers a performance counter profile 15This command generates and displays a performance counter profile in realtime.
16from it.
17 16
18 17
19OPTIONS 18OPTIONS
20------- 19-------
21<command>...:: 20-a::
22 Any command you can specify in a shell. 21--all-cpus::
22 System-wide collection. (default)
23
24-c <count>::
25--count=<count>::
26 Event period to sample.
27
28-C <cpu>::
29--CPU=<cpu>::
30 CPU to profile.
31
32-d <seconds>::
33--delay=<seconds>::
34 Number of seconds to delay between refreshes.
23 35
24-e:: 36-e <event>::
25--event=:: 37--event=<event>::
26 Select the PMU event. Selection can be a symbolic event name 38 Select the PMU event. Selection can be a symbolic event name
27 (use 'perf list' to list all events) or a raw PMU 39 (use 'perf list' to list all events) or a raw PMU
28 event (eventsel+umask) in the form of rNNN where NNN is a 40 event (eventsel+umask) in the form of rNNN where NNN is a
29 hexadecimal event descriptor. 41 hexadecimal event descriptor.
30 42
31-a:: 43-E <entries>::
32 system-wide collection 44--entries=<entries>::
45 Display this many functions.
46
47-f <count>::
48--count-filter=<count>::
49 Only display functions with more events than this.
50
51-F <freq>::
52--freq=<freq>::
53 Profile at this frequency.
54
55-i::
56--inherit::
57 Child tasks inherit counters, only makes sens with -p option.
58
59-k <path>::
60--vmlinux=<path>::
61 Path to vmlinux. Required for annotation functionality.
62
63-m <pages>::
64--mmap-pages=<pages>::
65 Number of mmapped data pages.
66
67-p <pid>::
68--pid=<pid>::
69 Profile events on existing pid.
70
71-r <priority>::
72--realtime=<priority>::
73 Collect data with this RT SCHED_FIFO priority.
74
75-s <symbol>::
76--sym-annotate=<symbol>::
77 Annotate this symbol. Requires -k option.
78
79-v::
80--verbose::
81 Be more verbose (show counter open errors, etc).
82
83-z::
84--zero::
85 Zero history across display updates.
86
87INTERACTIVE PROMPTING KEYS
88--------------------------
89
90[d]::
91 Display refresh delay.
92
93[e]::
94 Number of entries to display.
95
96[E]::
97 Event to display when multiple counters are active.
98
99[f]::
100 Profile display filter (>= hit count).
101
102[F]::
103 Annotation display filter (>= % of total).
104
105[s]::
106 Annotate symbol.
107
108[S]::
109 Stop annotation, return to full profile display.
110
111[w]::
112 Toggle between weighted sum and individual count[E]r profile.
113
114[z]::
115 Toggle event count zeroing across display updates.
116
117[qQ]::
118 Quit.
119
120Pressing any unmapped key displays a menu, and prompts for input.
33 121
34-l::
35 scale counter values
36 122
37SEE ALSO 123SEE ALSO
38-------- 124--------
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
new file mode 100644
index 000000000000..41ed75398ca9
--- /dev/null
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -0,0 +1,25 @@
1perf-trace(1)
2==============
3
4NAME
5----
6perf-trace - Read perf.data (created by perf record) and display trace output
7
8SYNOPSIS
9--------
10[verse]
11'perf trace' [-i <file> | --input=file] symbol_name
12
13DESCRIPTION
14-----------
15This command reads the input file and displays the trace recorded.
16
17OPTIONS
18-------
19-D::
20--dump-raw-trace=::
21 Display verbose dump of the trace data.
22
23SEE ALSO
24--------
25linkperf:perf-record[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 36d7eef49913..b5f1953b6144 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -158,13 +158,43 @@ uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
158uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') 158uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
159 159
160# If we're on a 64-bit kernel, use -m64 160# If we're on a 64-bit kernel, use -m64
161ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) 161ifndef NO_64BIT
162 M64 := -m64 162 ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
163 M64 := -m64
164 endif
163endif 165endif
164 166
165# CFLAGS and LDFLAGS are for the users to override from the command line. 167# CFLAGS and LDFLAGS are for the users to override from the command line.
166 168
167CFLAGS = $(M64) -ggdb3 -Wall -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6 169#
170# Include saner warnings here, which can catch bugs:
171#
172
173EXTRA_WARNINGS := -Wcast-align
174EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat
175EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
176EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
177EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
178EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
179EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
180EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
181EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector
182EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
183EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
184EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
185EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
186EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
187EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var
188EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
189EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
190EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
191EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes
192EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs
193EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
194EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
195EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
196
197CFLAGS = $(M64) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
168LDFLAGS = -lpthread -lrt -lelf -lm 198LDFLAGS = -lpthread -lrt -lelf -lm
169ALL_CFLAGS = $(CFLAGS) 199ALL_CFLAGS = $(CFLAGS)
170ALL_LDFLAGS = $(LDFLAGS) 200ALL_LDFLAGS = $(LDFLAGS)
@@ -223,7 +253,7 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
223# Those must not be GNU-specific; they are shared with perl/ which may 253# Those must not be GNU-specific; they are shared with perl/ which may
224# be built by a different compiler. (Note that this is an artifact now 254# be built by a different compiler. (Note that this is an artifact now
225# but it still might be nice to keep that distinction.) 255# but it still might be nice to keep that distinction.)
226BASIC_CFLAGS = 256BASIC_CFLAGS = -Iutil/include
227BASIC_LDFLAGS = 257BASIC_LDFLAGS =
228 258
229# Guard against environment variables 259# Guard against environment variables
@@ -288,11 +318,12 @@ export PERL_PATH
288 318
289LIB_FILE=libperf.a 319LIB_FILE=libperf.a
290 320
291LIB_H += ../../include/linux/perf_counter.h 321LIB_H += ../../include/linux/perf_event.h
322LIB_H += ../../include/linux/rbtree.h
323LIB_H += ../../include/linux/list.h
324LIB_H += util/include/linux/list.h
292LIB_H += perf.h 325LIB_H += perf.h
293LIB_H += types.h 326LIB_H += util/types.h
294LIB_H += util/list.h
295LIB_H += util/rbtree.h
296LIB_H += util/levenshtein.h 327LIB_H += util/levenshtein.h
297LIB_H += util/parse-options.h 328LIB_H += util/parse-options.h
298LIB_H += util/parse-events.h 329LIB_H += util/parse-events.h
@@ -301,10 +332,13 @@ LIB_H += util/util.h
301LIB_H += util/help.h 332LIB_H += util/help.h
302LIB_H += util/strbuf.h 333LIB_H += util/strbuf.h
303LIB_H += util/string.h 334LIB_H += util/string.h
335LIB_H += util/strlist.h
304LIB_H += util/run-command.h 336LIB_H += util/run-command.h
305LIB_H += util/sigchain.h 337LIB_H += util/sigchain.h
306LIB_H += util/symbol.h 338LIB_H += util/symbol.h
339LIB_H += util/module.h
307LIB_H += util/color.h 340LIB_H += util/color.h
341LIB_H += util/values.h
308 342
309LIB_OBJS += util/abspath.o 343LIB_OBJS += util/abspath.o
310LIB_OBJS += util/alias.o 344LIB_OBJS += util/alias.o
@@ -322,23 +356,37 @@ LIB_OBJS += util/run-command.o
322LIB_OBJS += util/quote.o 356LIB_OBJS += util/quote.o
323LIB_OBJS += util/strbuf.o 357LIB_OBJS += util/strbuf.o
324LIB_OBJS += util/string.o 358LIB_OBJS += util/string.o
359LIB_OBJS += util/strlist.o
325LIB_OBJS += util/usage.o 360LIB_OBJS += util/usage.o
326LIB_OBJS += util/wrapper.o 361LIB_OBJS += util/wrapper.o
327LIB_OBJS += util/sigchain.o 362LIB_OBJS += util/sigchain.o
328LIB_OBJS += util/symbol.o 363LIB_OBJS += util/symbol.o
364LIB_OBJS += util/module.o
329LIB_OBJS += util/color.o 365LIB_OBJS += util/color.o
330LIB_OBJS += util/pager.o 366LIB_OBJS += util/pager.o
367LIB_OBJS += util/header.o
368LIB_OBJS += util/callchain.o
369LIB_OBJS += util/values.o
370LIB_OBJS += util/debug.o
371LIB_OBJS += util/map.o
372LIB_OBJS += util/thread.o
373LIB_OBJS += util/trace-event-parse.o
374LIB_OBJS += util/trace-event-read.o
375LIB_OBJS += util/trace-event-info.o
376LIB_OBJS += util/svghelper.o
331 377
332BUILTIN_OBJS += builtin-annotate.o 378BUILTIN_OBJS += builtin-annotate.o
333BUILTIN_OBJS += builtin-help.o 379BUILTIN_OBJS += builtin-help.o
380BUILTIN_OBJS += builtin-sched.o
334BUILTIN_OBJS += builtin-list.o 381BUILTIN_OBJS += builtin-list.o
335BUILTIN_OBJS += builtin-record.o 382BUILTIN_OBJS += builtin-record.o
336BUILTIN_OBJS += builtin-report.o 383BUILTIN_OBJS += builtin-report.o
337BUILTIN_OBJS += builtin-stat.o 384BUILTIN_OBJS += builtin-stat.o
385BUILTIN_OBJS += builtin-timechart.o
338BUILTIN_OBJS += builtin-top.o 386BUILTIN_OBJS += builtin-top.o
387BUILTIN_OBJS += builtin-trace.o
339 388
340PERFLIBS = $(LIB_FILE) 389PERFLIBS = $(LIB_FILE)
341EXTLIBS =
342 390
343# 391#
344# Platform specific tweaks 392# Platform specific tweaks
@@ -367,6 +415,39 @@ ifeq ($(uname_S),Darwin)
367 PTHREAD_LIBS = 415 PTHREAD_LIBS =
368endif 416endif
369 417
418ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
419 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
420endif
421
422ifdef NO_DEMANGLE
423 BASIC_CFLAGS += -DNO_DEMANGLE
424else
425 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd > /dev/null 2>&1 && echo y")
426
427 ifeq ($(has_bfd),y)
428 EXTLIBS += -lbfd
429 else
430 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y")
431 ifeq ($(has_bfd_iberty),y)
432 EXTLIBS += -lbfd -liberty
433 else
434 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty -lz > /dev/null 2>&1 && echo y")
435 ifeq ($(has_bfd_iberty_z),y)
436 EXTLIBS += -lbfd -liberty -lz
437 else
438 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -liberty > /dev/null 2>&1 && echo y")
439 ifeq ($(has_cplus_demangle),y)
440 EXTLIBS += -liberty
441 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
442 else
443 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling)
444 BASIC_CFLAGS += -DNO_DEMANGLE
445 endif
446 endif
447 endif
448 endif
449endif
450
370ifndef CC_LD_DYNPATH 451ifndef CC_LD_DYNPATH
371 ifdef NO_R_TO_GCC_LINKER 452 ifdef NO_R_TO_GCC_LINKER
372 # Some gcc does not accept and pass -R to the linker to specify 453 # Some gcc does not accept and pass -R to the linker to specify
@@ -377,12 +458,6 @@ ifndef CC_LD_DYNPATH
377 endif 458 endif
378endif 459endif
379 460
380ifdef ZLIB_PATH
381 BASIC_CFLAGS += -I$(ZLIB_PATH)/include
382 EXTLIBS += -L$(ZLIB_PATH)/$(lib) $(CC_LD_DYNPATH)$(ZLIB_PATH)/$(lib)
383endif
384EXTLIBS += -lz
385
386ifdef NEEDS_SOCKET 461ifdef NEEDS_SOCKET
387 EXTLIBS += -lsocket 462 EXTLIBS += -lsocket
388endif 463endif
@@ -638,6 +713,12 @@ builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS
638 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 713 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
639 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 714 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
640 715
716builtin-timechart.o: builtin-timechart.c common-cmds.h PERF-CFLAGS
717 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
718 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
719 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
720 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
721
641$(BUILT_INS): perf$X 722$(BUILT_INS): perf$X
642 $(QUIET_BUILT_IN)$(RM) $@ && \ 723 $(QUIET_BUILT_IN)$(RM) $@ && \
643 ln perf$X $@ 2>/dev/null || \ 724 ln perf$X $@ 2>/dev/null || \
@@ -693,6 +774,9 @@ builtin-init-db.o: builtin-init-db.c PERF-CFLAGS
693util/config.o: util/config.c PERF-CFLAGS 774util/config.o: util/config.c PERF-CFLAGS
694 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 775 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
695 776
777util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
778 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
779
696perf-%$X: %.o $(PERFLIBS) 780perf-%$X: %.o $(PERFLIBS)
697 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 781 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
698 782
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 7e58e3ad1508..1ec741615814 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -10,85 +10,37 @@
10#include "util/util.h" 10#include "util/util.h"
11 11
12#include "util/color.h" 12#include "util/color.h"
13#include "util/list.h" 13#include <linux/list.h>
14#include "util/cache.h" 14#include "util/cache.h"
15#include "util/rbtree.h" 15#include <linux/rbtree.h>
16#include "util/symbol.h" 16#include "util/symbol.h"
17#include "util/string.h" 17#include "util/string.h"
18 18
19#include "perf.h" 19#include "perf.h"
20#include "util/debug.h"
20 21
21#include "util/parse-options.h" 22#include "util/parse-options.h"
22#include "util/parse-events.h" 23#include "util/parse-events.h"
23 24#include "util/thread.h"
24#define SHOW_KERNEL 1
25#define SHOW_USER 2
26#define SHOW_HV 4
27
28#define MIN_GREEN 0.5
29#define MIN_RED 5.0
30
31 25
32static char const *input_name = "perf.data"; 26static char const *input_name = "perf.data";
33static char *vmlinux = "vmlinux";
34 27
35static char default_sort_order[] = "comm,symbol"; 28static char default_sort_order[] = "comm,symbol";
36static char *sort_order = default_sort_order; 29static char *sort_order = default_sort_order;
37 30
31static int force;
38static int input; 32static int input;
39static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 33static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
40 34
41static int dump_trace = 0; 35static int full_paths;
42#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
43
44static int verbose;
45 36
46static int print_line; 37static int print_line;
47 38
48static unsigned long page_size; 39static unsigned long page_size;
49static unsigned long mmap_window = 32; 40static unsigned long mmap_window = 32;
50 41
51struct ip_event { 42static struct rb_root threads;
52 struct perf_event_header header; 43static struct thread *last_match;
53 u64 ip;
54 u32 pid, tid;
55};
56
57struct mmap_event {
58 struct perf_event_header header;
59 u32 pid, tid;
60 u64 start;
61 u64 len;
62 u64 pgoff;
63 char filename[PATH_MAX];
64};
65
66struct comm_event {
67 struct perf_event_header header;
68 u32 pid, tid;
69 char comm[16];
70};
71
72struct fork_event {
73 struct perf_event_header header;
74 u32 pid, ppid;
75};
76
77struct period_event {
78 struct perf_event_header header;
79 u64 time;
80 u64 id;
81 u64 sample_period;
82};
83
84typedef union event_union {
85 struct perf_event_header header;
86 struct ip_event ip;
87 struct mmap_event mmap;
88 struct comm_event comm;
89 struct fork_event fork;
90 struct period_event period;
91} event_t;
92 44
93 45
94struct sym_ext { 46struct sym_ext {
@@ -97,323 +49,6 @@ struct sym_ext {
97 char *path; 49 char *path;
98}; 50};
99 51
100static LIST_HEAD(dsos);
101static struct dso *kernel_dso;
102static struct dso *vdso;
103
104
105static void dsos__add(struct dso *dso)
106{
107 list_add_tail(&dso->node, &dsos);
108}
109
110static struct dso *dsos__find(const char *name)
111{
112 struct dso *pos;
113
114 list_for_each_entry(pos, &dsos, node)
115 if (strcmp(pos->name, name) == 0)
116 return pos;
117 return NULL;
118}
119
120static struct dso *dsos__findnew(const char *name)
121{
122 struct dso *dso = dsos__find(name);
123 int nr;
124
125 if (dso)
126 return dso;
127
128 dso = dso__new(name, 0);
129 if (!dso)
130 goto out_delete_dso;
131
132 nr = dso__load(dso, NULL, verbose);
133 if (nr < 0) {
134 if (verbose)
135 fprintf(stderr, "Failed to open: %s\n", name);
136 goto out_delete_dso;
137 }
138 if (!nr && verbose) {
139 fprintf(stderr,
140 "No symbols found in: %s, maybe install a debug package?\n",
141 name);
142 }
143
144 dsos__add(dso);
145
146 return dso;
147
148out_delete_dso:
149 dso__delete(dso);
150 return NULL;
151}
152
153static void dsos__fprintf(FILE *fp)
154{
155 struct dso *pos;
156
157 list_for_each_entry(pos, &dsos, node)
158 dso__fprintf(pos, fp);
159}
160
161static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
162{
163 return dso__find_symbol(kernel_dso, ip);
164}
165
166static int load_kernel(void)
167{
168 int err;
169
170 kernel_dso = dso__new("[kernel]", 0);
171 if (!kernel_dso)
172 return -1;
173
174 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
175 if (err) {
176 dso__delete(kernel_dso);
177 kernel_dso = NULL;
178 } else
179 dsos__add(kernel_dso);
180
181 vdso = dso__new("[vdso]", 0);
182 if (!vdso)
183 return -1;
184
185 vdso->find_symbol = vdso__find_symbol;
186
187 dsos__add(vdso);
188
189 return err;
190}
191
192struct map {
193 struct list_head node;
194 u64 start;
195 u64 end;
196 u64 pgoff;
197 u64 (*map_ip)(struct map *, u64);
198 struct dso *dso;
199};
200
201static u64 map__map_ip(struct map *map, u64 ip)
202{
203 return ip - map->start + map->pgoff;
204}
205
206static u64 vdso__map_ip(struct map *map, u64 ip)
207{
208 return ip;
209}
210
211static struct map *map__new(struct mmap_event *event)
212{
213 struct map *self = malloc(sizeof(*self));
214
215 if (self != NULL) {
216 const char *filename = event->filename;
217
218 self->start = event->start;
219 self->end = event->start + event->len;
220 self->pgoff = event->pgoff;
221
222 self->dso = dsos__findnew(filename);
223 if (self->dso == NULL)
224 goto out_delete;
225
226 if (self->dso == vdso)
227 self->map_ip = vdso__map_ip;
228 else
229 self->map_ip = map__map_ip;
230 }
231 return self;
232out_delete:
233 free(self);
234 return NULL;
235}
236
237static struct map *map__clone(struct map *self)
238{
239 struct map *map = malloc(sizeof(*self));
240
241 if (!map)
242 return NULL;
243
244 memcpy(map, self, sizeof(*self));
245
246 return map;
247}
248
249static int map__overlap(struct map *l, struct map *r)
250{
251 if (l->start > r->start) {
252 struct map *t = l;
253 l = r;
254 r = t;
255 }
256
257 if (l->end > r->start)
258 return 1;
259
260 return 0;
261}
262
263static size_t map__fprintf(struct map *self, FILE *fp)
264{
265 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
266 self->start, self->end, self->pgoff, self->dso->name);
267}
268
269
270struct thread {
271 struct rb_node rb_node;
272 struct list_head maps;
273 pid_t pid;
274 char *comm;
275};
276
277static struct thread *thread__new(pid_t pid)
278{
279 struct thread *self = malloc(sizeof(*self));
280
281 if (self != NULL) {
282 self->pid = pid;
283 self->comm = malloc(32);
284 if (self->comm)
285 snprintf(self->comm, 32, ":%d", self->pid);
286 INIT_LIST_HEAD(&self->maps);
287 }
288
289 return self;
290}
291
292static int thread__set_comm(struct thread *self, const char *comm)
293{
294 if (self->comm)
295 free(self->comm);
296 self->comm = strdup(comm);
297 return self->comm ? 0 : -ENOMEM;
298}
299
300static size_t thread__fprintf(struct thread *self, FILE *fp)
301{
302 struct map *pos;
303 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
304
305 list_for_each_entry(pos, &self->maps, node)
306 ret += map__fprintf(pos, fp);
307
308 return ret;
309}
310
311
312static struct rb_root threads;
313static struct thread *last_match;
314
315static struct thread *threads__findnew(pid_t pid)
316{
317 struct rb_node **p = &threads.rb_node;
318 struct rb_node *parent = NULL;
319 struct thread *th;
320
321 /*
322 * Font-end cache - PID lookups come in blocks,
323 * so most of the time we dont have to look up
324 * the full rbtree:
325 */
326 if (last_match && last_match->pid == pid)
327 return last_match;
328
329 while (*p != NULL) {
330 parent = *p;
331 th = rb_entry(parent, struct thread, rb_node);
332
333 if (th->pid == pid) {
334 last_match = th;
335 return th;
336 }
337
338 if (pid < th->pid)
339 p = &(*p)->rb_left;
340 else
341 p = &(*p)->rb_right;
342 }
343
344 th = thread__new(pid);
345 if (th != NULL) {
346 rb_link_node(&th->rb_node, parent, p);
347 rb_insert_color(&th->rb_node, &threads);
348 last_match = th;
349 }
350
351 return th;
352}
353
354static void thread__insert_map(struct thread *self, struct map *map)
355{
356 struct map *pos, *tmp;
357
358 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
359 if (map__overlap(pos, map)) {
360 list_del_init(&pos->node);
361 /* XXX leaks dsos */
362 free(pos);
363 }
364 }
365
366 list_add_tail(&map->node, &self->maps);
367}
368
369static int thread__fork(struct thread *self, struct thread *parent)
370{
371 struct map *map;
372
373 if (self->comm)
374 free(self->comm);
375 self->comm = strdup(parent->comm);
376 if (!self->comm)
377 return -ENOMEM;
378
379 list_for_each_entry(map, &parent->maps, node) {
380 struct map *new = map__clone(map);
381 if (!new)
382 return -ENOMEM;
383 thread__insert_map(self, new);
384 }
385
386 return 0;
387}
388
389static struct map *thread__find_map(struct thread *self, u64 ip)
390{
391 struct map *pos;
392
393 if (self == NULL)
394 return NULL;
395
396 list_for_each_entry(pos, &self->maps, node)
397 if (ip >= pos->start && ip <= pos->end)
398 return pos;
399
400 return NULL;
401}
402
403static size_t threads__fprintf(FILE *fp)
404{
405 size_t ret = 0;
406 struct rb_node *nd;
407
408 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
409 struct thread *pos = rb_entry(nd, struct thread, rb_node);
410
411 ret += thread__fprintf(pos, fp);
412 }
413
414 return ret;
415}
416
417/* 52/*
418 * histogram, sorted on item, collects counts 53 * histogram, sorted on item, collects counts
419 */ 54 */
@@ -440,7 +75,7 @@ struct hist_entry {
440struct sort_entry { 75struct sort_entry {
441 struct list_head list; 76 struct list_head list;
442 77
443 char *header; 78 const char *header;
444 79
445 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 80 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
446 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 81 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
@@ -584,7 +219,7 @@ static struct sort_entry sort_sym = {
584static int sort__need_collapse = 0; 219static int sort__need_collapse = 0;
585 220
586struct sort_dimension { 221struct sort_dimension {
587 char *name; 222 const char *name;
588 struct sort_entry *entry; 223 struct sort_entry *entry;
589 int taken; 224 int taken;
590}; 225};
@@ -600,7 +235,7 @@ static LIST_HEAD(hist_entry__sort_list);
600 235
601static int sort_dimension__add(char *tok) 236static int sort_dimension__add(char *tok)
602{ 237{
603 int i; 238 unsigned int i;
604 239
605 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 240 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
606 struct sort_dimension *sd = &sort_dimensions[i]; 241 struct sort_dimension *sd = &sort_dimensions[i];
@@ -837,17 +472,6 @@ static void output__resort(void)
837 } 472 }
838} 473}
839 474
840static void register_idle_thread(void)
841{
842 struct thread *thread = threads__findnew(0);
843
844 if (thread == NULL ||
845 thread__set_comm(thread, "[idle]")) {
846 fprintf(stderr, "problem inserting idle task.\n");
847 exit(-1);
848 }
849}
850
851static unsigned long total = 0, 475static unsigned long total = 0,
852 total_mmap = 0, 476 total_mmap = 0,
853 total_comm = 0, 477 total_comm = 0,
@@ -855,23 +479,25 @@ static unsigned long total = 0,
855 total_unknown = 0; 479 total_unknown = 0;
856 480
857static int 481static int
858process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 482process_sample_event(event_t *event, unsigned long offset, unsigned long head)
859{ 483{
860 char level; 484 char level;
861 int show = 0; 485 int show = 0;
862 struct dso *dso = NULL; 486 struct dso *dso = NULL;
863 struct thread *thread = threads__findnew(event->ip.pid); 487 struct thread *thread;
864 u64 ip = event->ip.ip; 488 u64 ip = event->ip.ip;
865 struct map *map = NULL; 489 struct map *map = NULL;
866 490
867 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", 491 thread = threads__findnew(event->ip.pid, &threads, &last_match);
492
493 dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
868 (void *)(offset + head), 494 (void *)(offset + head),
869 (void *)(long)(event->header.size), 495 (void *)(long)(event->header.size),
870 event->header.misc, 496 event->header.misc,
871 event->ip.pid, 497 event->ip.pid,
872 (void *)(long)ip); 498 (void *)(long)ip);
873 499
874 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); 500 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
875 501
876 if (thread == NULL) { 502 if (thread == NULL) {
877 fprintf(stderr, "problem processing %d event, skipping it.\n", 503 fprintf(stderr, "problem processing %d event, skipping it.\n",
@@ -879,15 +505,15 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
879 return -1; 505 return -1;
880 } 506 }
881 507
882 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 508 if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
883 show = SHOW_KERNEL; 509 show = SHOW_KERNEL;
884 level = 'k'; 510 level = 'k';
885 511
886 dso = kernel_dso; 512 dso = kernel_dso;
887 513
888 dprintf(" ...... dso: %s\n", dso->name); 514 dump_printf(" ...... dso: %s\n", dso->name);
889 515
890 } else if (event->header.misc & PERF_EVENT_MISC_USER) { 516 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
891 517
892 show = SHOW_USER; 518 show = SHOW_USER;
893 level = '.'; 519 level = '.';
@@ -906,12 +532,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
906 if ((long long)ip < 0) 532 if ((long long)ip < 0)
907 dso = kernel_dso; 533 dso = kernel_dso;
908 } 534 }
909 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 535 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
910 536
911 } else { 537 } else {
912 show = SHOW_HV; 538 show = SHOW_HV;
913 level = 'H'; 539 level = 'H';
914 dprintf(" ...... dso: [hypervisor]\n"); 540 dump_printf(" ...... dso: [hypervisor]\n");
915 } 541 }
916 542
917 if (show & show_mask) { 543 if (show & show_mask) {
@@ -934,10 +560,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
934static int 560static int
935process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 561process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
936{ 562{
937 struct thread *thread = threads__findnew(event->mmap.pid); 563 struct thread *thread;
938 struct map *map = map__new(&event->mmap); 564 struct map *map = map__new(&event->mmap, NULL, 0);
565
566 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
939 567
940 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", 568 dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
941 (void *)(offset + head), 569 (void *)(offset + head),
942 (void *)(long)(event->header.size), 570 (void *)(long)(event->header.size),
943 event->mmap.pid, 571 event->mmap.pid,
@@ -947,7 +575,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
947 event->mmap.filename); 575 event->mmap.filename);
948 576
949 if (thread == NULL || map == NULL) { 577 if (thread == NULL || map == NULL) {
950 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); 578 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
951 return 0; 579 return 0;
952 } 580 }
953 581
@@ -960,16 +588,17 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
960static int 588static int
961process_comm_event(event_t *event, unsigned long offset, unsigned long head) 589process_comm_event(event_t *event, unsigned long offset, unsigned long head)
962{ 590{
963 struct thread *thread = threads__findnew(event->comm.pid); 591 struct thread *thread;
964 592
965 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", 593 thread = threads__findnew(event->comm.pid, &threads, &last_match);
594 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
966 (void *)(offset + head), 595 (void *)(offset + head),
967 (void *)(long)(event->header.size), 596 (void *)(long)(event->header.size),
968 event->comm.comm, event->comm.pid); 597 event->comm.comm, event->comm.pid);
969 598
970 if (thread == NULL || 599 if (thread == NULL ||
971 thread__set_comm(thread, event->comm.comm)) { 600 thread__set_comm(thread, event->comm.comm)) {
972 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); 601 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
973 return -1; 602 return -1;
974 } 603 }
975 total_comm++; 604 total_comm++;
@@ -980,16 +609,25 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
980static int 609static int
981process_fork_event(event_t *event, unsigned long offset, unsigned long head) 610process_fork_event(event_t *event, unsigned long offset, unsigned long head)
982{ 611{
983 struct thread *thread = threads__findnew(event->fork.pid); 612 struct thread *thread;
984 struct thread *parent = threads__findnew(event->fork.ppid); 613 struct thread *parent;
985 614
986 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 615 thread = threads__findnew(event->fork.pid, &threads, &last_match);
616 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
617 dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n",
987 (void *)(offset + head), 618 (void *)(offset + head),
988 (void *)(long)(event->header.size), 619 (void *)(long)(event->header.size),
989 event->fork.pid, event->fork.ppid); 620 event->fork.pid, event->fork.ppid);
990 621
622 /*
623 * A thread clone will have the same PID for both
624 * parent and child.
625 */
626 if (thread == parent)
627 return 0;
628
991 if (!thread || !parent || thread__fork(thread, parent)) { 629 if (!thread || !parent || thread__fork(thread, parent)) {
992 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 630 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
993 return -1; 631 return -1;
994 } 632 }
995 total_fork++; 633 total_fork++;
@@ -998,42 +636,26 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
998} 636}
999 637
1000static int 638static int
1001process_period_event(event_t *event, unsigned long offset, unsigned long head)
1002{
1003 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
1004 (void *)(offset + head),
1005 (void *)(long)(event->header.size),
1006 event->period.time,
1007 event->period.id,
1008 event->period.sample_period);
1009
1010 return 0;
1011}
1012
1013static int
1014process_event(event_t *event, unsigned long offset, unsigned long head) 639process_event(event_t *event, unsigned long offset, unsigned long head)
1015{ 640{
1016 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1017 return process_overflow_event(event, offset, head);
1018
1019 switch (event->header.type) { 641 switch (event->header.type) {
1020 case PERF_EVENT_MMAP: 642 case PERF_RECORD_SAMPLE:
643 return process_sample_event(event, offset, head);
644
645 case PERF_RECORD_MMAP:
1021 return process_mmap_event(event, offset, head); 646 return process_mmap_event(event, offset, head);
1022 647
1023 case PERF_EVENT_COMM: 648 case PERF_RECORD_COMM:
1024 return process_comm_event(event, offset, head); 649 return process_comm_event(event, offset, head);
1025 650
1026 case PERF_EVENT_FORK: 651 case PERF_RECORD_FORK:
1027 return process_fork_event(event, offset, head); 652 return process_fork_event(event, offset, head);
1028
1029 case PERF_EVENT_PERIOD:
1030 return process_period_event(event, offset, head);
1031 /* 653 /*
1032 * We dont process them right now but they are fine: 654 * We dont process them right now but they are fine:
1033 */ 655 */
1034 656
1035 case PERF_EVENT_THROTTLE: 657 case PERF_RECORD_THROTTLE:
1036 case PERF_EVENT_UNTHROTTLE: 658 case PERF_RECORD_UNTHROTTLE:
1037 return 0; 659 return 0;
1038 660
1039 default: 661 default:
@@ -1043,24 +665,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1043 return 0; 665 return 0;
1044} 666}
1045 667
1046static char *get_color(double percent)
1047{
1048 char *color = PERF_COLOR_NORMAL;
1049
1050 /*
1051 * We color high-overhead entries in red, mid-overhead
1052 * entries in green - and keep the low overhead places
1053 * normal:
1054 */
1055 if (percent >= MIN_RED)
1056 color = PERF_COLOR_RED;
1057 else {
1058 if (percent > MIN_GREEN)
1059 color = PERF_COLOR_GREEN;
1060 }
1061 return color;
1062}
1063
1064static int 668static int
1065parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) 669parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1066{ 670{
@@ -1069,7 +673,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1069 static const char *prev_color; 673 static const char *prev_color;
1070 unsigned int offset; 674 unsigned int offset;
1071 size_t line_len; 675 size_t line_len;
1072 u64 line_ip; 676 s64 line_ip;
1073 int ret; 677 int ret;
1074 char *c; 678 char *c;
1075 679
@@ -1109,7 +713,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1109 const char *path = NULL; 713 const char *path = NULL;
1110 unsigned int hits = 0; 714 unsigned int hits = 0;
1111 double percent = 0.0; 715 double percent = 0.0;
1112 char *color; 716 const char *color;
1113 struct sym_ext *sym_ext = sym->priv; 717 struct sym_ext *sym_ext = sym->priv;
1114 718
1115 offset = line_ip - start; 719 offset = line_ip - start;
@@ -1122,7 +726,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1122 } else if (sym->hist_sum) 726 } else if (sym->hist_sum)
1123 percent = 100.0 * hits / sym->hist_sum; 727 percent = 100.0 * hits / sym->hist_sum;
1124 728
1125 color = get_color(percent); 729 color = get_percent_color(percent);
1126 730
1127 /* 731 /*
1128 * Also color the filename and line if needed, with 732 * Also color the filename and line if needed, with
@@ -1191,7 +795,7 @@ static void free_source_line(struct symbol *sym, int len)
1191 795
1192/* Get the filename:line for the colored entries */ 796/* Get the filename:line for the colored entries */
1193static void 797static void
1194get_source_line(struct symbol *sym, u64 start, int len, char *filename) 798get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
1195{ 799{
1196 int i; 800 int i;
1197 char cmd[PATH_MAX * 2]; 801 char cmd[PATH_MAX * 2];
@@ -1237,7 +841,7 @@ get_source_line(struct symbol *sym, u64 start, int len, char *filename)
1237 } 841 }
1238} 842}
1239 843
1240static void print_summary(char *filename) 844static void print_summary(const char *filename)
1241{ 845{
1242 struct sym_ext *sym_ext; 846 struct sym_ext *sym_ext;
1243 struct rb_node *node; 847 struct rb_node *node;
@@ -1253,12 +857,12 @@ static void print_summary(char *filename)
1253 node = rb_first(&root_sym_ext); 857 node = rb_first(&root_sym_ext);
1254 while (node) { 858 while (node) {
1255 double percent; 859 double percent;
1256 char *color; 860 const char *color;
1257 char *path; 861 char *path;
1258 862
1259 sym_ext = rb_entry(node, struct sym_ext, node); 863 sym_ext = rb_entry(node, struct sym_ext, node);
1260 percent = sym_ext->percent; 864 percent = sym_ext->percent;
1261 color = get_color(percent); 865 color = get_percent_color(percent);
1262 path = sym_ext->path; 866 path = sym_ext->path;
1263 867
1264 color_fprintf(stdout, color, " %7.2f %s", percent, path); 868 color_fprintf(stdout, color, " %7.2f %s", percent, path);
@@ -1268,19 +872,25 @@ static void print_summary(char *filename)
1268 872
1269static void annotate_sym(struct dso *dso, struct symbol *sym) 873static void annotate_sym(struct dso *dso, struct symbol *sym)
1270{ 874{
1271 char *filename = dso->name; 875 const char *filename = dso->name, *d_filename;
1272 u64 start, end, len; 876 u64 start, end, len;
1273 char command[PATH_MAX*2]; 877 char command[PATH_MAX*2];
1274 FILE *file; 878 FILE *file;
1275 879
1276 if (!filename) 880 if (!filename)
1277 return; 881 return;
1278 if (dso == kernel_dso) 882 if (sym->module)
1279 filename = vmlinux; 883 filename = sym->module->path;
884 else if (dso == kernel_dso)
885 filename = vmlinux_name;
1280 886
1281 start = sym->obj_start; 887 start = sym->obj_start;
1282 if (!start) 888 if (!start)
1283 start = sym->start; 889 start = sym->start;
890 if (full_paths)
891 d_filename = filename;
892 else
893 d_filename = basename(filename);
1284 894
1285 end = start + sym->end - sym->start + 1; 895 end = start + sym->end - sym->start + 1;
1286 len = sym->end - sym->start; 896 len = sym->end - sym->start;
@@ -1291,13 +901,14 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1291 } 901 }
1292 902
1293 printf("\n\n------------------------------------------------\n"); 903 printf("\n\n------------------------------------------------\n");
1294 printf(" Percent | Source code & Disassembly of %s\n", filename); 904 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
1295 printf("------------------------------------------------\n"); 905 printf("------------------------------------------------\n");
1296 906
1297 if (verbose >= 2) 907 if (verbose >= 2)
1298 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); 908 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1299 909
1300 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename); 910 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
911 (u64)start, (u64)end, filename, filename);
1301 912
1302 if (verbose >= 3) 913 if (verbose >= 3)
1303 printf("doing: %s\n", command); 914 printf("doing: %s\n", command);
@@ -1343,12 +954,12 @@ static int __cmd_annotate(void)
1343 int ret, rc = EXIT_FAILURE; 954 int ret, rc = EXIT_FAILURE;
1344 unsigned long offset = 0; 955 unsigned long offset = 0;
1345 unsigned long head = 0; 956 unsigned long head = 0;
1346 struct stat stat; 957 struct stat input_stat;
1347 event_t *event; 958 event_t *event;
1348 uint32_t size; 959 uint32_t size;
1349 char *buf; 960 char *buf;
1350 961
1351 register_idle_thread(); 962 register_idle_thread(&threads, &last_match);
1352 963
1353 input = open(input_name, O_RDONLY); 964 input = open(input_name, O_RDONLY);
1354 if (input < 0) { 965 if (input < 0) {
@@ -1356,13 +967,18 @@ static int __cmd_annotate(void)
1356 exit(-1); 967 exit(-1);
1357 } 968 }
1358 969
1359 ret = fstat(input, &stat); 970 ret = fstat(input, &input_stat);
1360 if (ret < 0) { 971 if (ret < 0) {
1361 perror("failed to stat file"); 972 perror("failed to stat file");
1362 exit(-1); 973 exit(-1);
1363 } 974 }
1364 975
1365 if (!stat.st_size) { 976 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
977 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
978 exit(-1);
979 }
980
981 if (!input_stat.st_size) {
1366 fprintf(stderr, "zero-sized file, nothing to do!\n"); 982 fprintf(stderr, "zero-sized file, nothing to do!\n");
1367 exit(0); 983 exit(0);
1368 } 984 }
@@ -1389,10 +1005,10 @@ more:
1389 1005
1390 if (head + event->header.size >= page_size * mmap_window) { 1006 if (head + event->header.size >= page_size * mmap_window) {
1391 unsigned long shift = page_size * (head / page_size); 1007 unsigned long shift = page_size * (head / page_size);
1392 int ret; 1008 int munmap_ret;
1393 1009
1394 ret = munmap(buf, page_size * mmap_window); 1010 munmap_ret = munmap(buf, page_size * mmap_window);
1395 assert(ret == 0); 1011 assert(munmap_ret == 0);
1396 1012
1397 offset += shift; 1013 offset += shift;
1398 head -= shift; 1014 head -= shift;
@@ -1401,14 +1017,14 @@ more:
1401 1017
1402 size = event->header.size; 1018 size = event->header.size;
1403 1019
1404 dprintf("%p [%p]: event: %d\n", 1020 dump_printf("%p [%p]: event: %d\n",
1405 (void *)(offset + head), 1021 (void *)(offset + head),
1406 (void *)(long)event->header.size, 1022 (void *)(long)event->header.size,
1407 event->header.type); 1023 event->header.type);
1408 1024
1409 if (!size || process_event(event, offset, head) < 0) { 1025 if (!size || process_event(event, offset, head) < 0) {
1410 1026
1411 dprintf("%p [%p]: skipping unknown header type: %d\n", 1027 dump_printf("%p [%p]: skipping unknown header type: %d\n",
1412 (void *)(offset + head), 1028 (void *)(offset + head),
1413 (void *)(long)(event->header.size), 1029 (void *)(long)(event->header.size),
1414 event->header.type); 1030 event->header.type);
@@ -1428,23 +1044,23 @@ more:
1428 1044
1429 head += size; 1045 head += size;
1430 1046
1431 if (offset + head < stat.st_size) 1047 if (offset + head < (unsigned long)input_stat.st_size)
1432 goto more; 1048 goto more;
1433 1049
1434 rc = EXIT_SUCCESS; 1050 rc = EXIT_SUCCESS;
1435 close(input); 1051 close(input);
1436 1052
1437 dprintf(" IP events: %10ld\n", total); 1053 dump_printf(" IP events: %10ld\n", total);
1438 dprintf(" mmap events: %10ld\n", total_mmap); 1054 dump_printf(" mmap events: %10ld\n", total_mmap);
1439 dprintf(" comm events: %10ld\n", total_comm); 1055 dump_printf(" comm events: %10ld\n", total_comm);
1440 dprintf(" fork events: %10ld\n", total_fork); 1056 dump_printf(" fork events: %10ld\n", total_fork);
1441 dprintf(" unknown events: %10ld\n", total_unknown); 1057 dump_printf(" unknown events: %10ld\n", total_unknown);
1442 1058
1443 if (dump_trace) 1059 if (dump_trace)
1444 return 0; 1060 return 0;
1445 1061
1446 if (verbose >= 3) 1062 if (verbose >= 3)
1447 threads__fprintf(stdout); 1063 threads__fprintf(stdout, &threads);
1448 1064
1449 if (verbose >= 2) 1065 if (verbose >= 2)
1450 dsos__fprintf(stdout); 1066 dsos__fprintf(stdout);
@@ -1467,13 +1083,18 @@ static const struct option options[] = {
1467 "input file name"), 1083 "input file name"),
1468 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", 1084 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
1469 "symbol to annotate"), 1085 "symbol to annotate"),
1086 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1470 OPT_BOOLEAN('v', "verbose", &verbose, 1087 OPT_BOOLEAN('v', "verbose", &verbose,
1471 "be more verbose (show symbol address, etc)"), 1088 "be more verbose (show symbol address, etc)"),
1472 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1089 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1473 "dump raw trace in ASCII"), 1090 "dump raw trace in ASCII"),
1474 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1091 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
1092 OPT_BOOLEAN('m', "modules", &modules,
1093 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1475 OPT_BOOLEAN('l', "print-line", &print_line, 1094 OPT_BOOLEAN('l', "print-line", &print_line,
1476 "print matching source lines (may be slow)"), 1095 "print matching source lines (may be slow)"),
1096 OPT_BOOLEAN('P', "full-paths", &full_paths,
1097 "Don't shorten the displayed pathnames"),
1477 OPT_END() 1098 OPT_END()
1478}; 1099};
1479 1100
@@ -1492,7 +1113,7 @@ static void setup_sorting(void)
1492 free(str); 1113 free(str);
1493} 1114}
1494 1115
1495int cmd_annotate(int argc, const char **argv, const char *prefix) 1116int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1496{ 1117{
1497 symbol__init(); 1118 symbol__init();
1498 1119
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 0f32dc3f3c4c..4fb8734a796e 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Builtin help command 4 * Builtin help command
5 */ 5 */
6#include "perf.h"
6#include "util/cache.h" 7#include "util/cache.h"
7#include "builtin.h" 8#include "builtin.h"
8#include "util/exec_cmd.h" 9#include "util/exec_cmd.h"
@@ -277,7 +278,7 @@ static struct cmdnames main_cmds, other_cmds;
277 278
278void list_common_cmds_help(void) 279void list_common_cmds_help(void)
279{ 280{
280 int i, longest = 0; 281 unsigned int i, longest = 0;
281 282
282 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { 283 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
283 if (longest < strlen(common_cmds[i].name)) 284 if (longest < strlen(common_cmds[i].name))
@@ -415,9 +416,10 @@ static void show_html_page(const char *perf_cmd)
415 open_html(page_path.buf); 416 open_html(page_path.buf);
416} 417}
417 418
418int cmd_help(int argc, const char **argv, const char *prefix) 419int cmd_help(int argc, const char **argv, const char *prefix __used)
419{ 420{
420 const char *alias; 421 const char *alias;
422
421 load_command_list("perf-", &main_cmds, &other_cmds); 423 load_command_list("perf-", &main_cmds, &other_cmds);
422 424
423 perf_config(perf_help_config, NULL); 425 perf_config(perf_help_config, NULL);
@@ -454,6 +456,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)
454 break; 456 break;
455 case HELP_FORMAT_WEB: 457 case HELP_FORMAT_WEB:
456 show_html_page(argv[0]); 458 show_html_page(argv[0]);
459 default:
457 break; 460 break;
458 } 461 }
459 462
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index fe60e37c96ef..d88c6961274c 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -10,11 +10,12 @@
10 10
11#include "perf.h" 11#include "perf.h"
12 12
13#include "util/parse-options.h"
14#include "util/parse-events.h" 13#include "util/parse-events.h"
14#include "util/cache.h"
15 15
16int cmd_list(int argc, const char **argv, const char *prefix) 16int cmd_list(int argc __used, const char **argv __used, const char *prefix __used)
17{ 17{
18 setup_pager();
18 print_events(); 19 print_events();
19 return 0; 20 return 0;
20} 21}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index d7ebbd757543..a5a050af8e7d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -14,6 +14,11 @@
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/string.h" 15#include "util/string.h"
16 16
17#include "util/header.h"
18#include "util/event.h"
19#include "util/debug.h"
20#include "util/trace-event.h"
21
17#include <unistd.h> 22#include <unistd.h>
18#include <sched.h> 23#include <sched.h>
19 24
@@ -32,13 +37,19 @@ static int output;
32static const char *output_name = "perf.data"; 37static const char *output_name = "perf.data";
33static int group = 0; 38static int group = 0;
34static unsigned int realtime_prio = 0; 39static unsigned int realtime_prio = 0;
40static int raw_samples = 0;
35static int system_wide = 0; 41static int system_wide = 0;
42static int profile_cpu = -1;
36static pid_t target_pid = -1; 43static pid_t target_pid = -1;
37static int inherit = 1; 44static int inherit = 1;
38static int force = 0; 45static int force = 0;
39static int append_file = 0; 46static int append_file = 0;
40static int call_graph = 0; 47static int call_graph = 0;
41static int verbose = 0; 48static int inherit_stat = 0;
49static int no_samples = 0;
50static int sample_address = 0;
51static int multiplex = 0;
52static int multiplex_fd = -1;
42 53
43static long samples; 54static long samples;
44static struct timeval last_read; 55static struct timeval last_read;
@@ -52,25 +63,8 @@ static int nr_poll;
52static int nr_cpu; 63static int nr_cpu;
53 64
54static int file_new = 1; 65static int file_new = 1;
55static struct perf_file_header file_header;
56
57struct mmap_event {
58 struct perf_event_header header;
59 u32 pid;
60 u32 tid;
61 u64 start;
62 u64 len;
63 u64 pgoff;
64 char filename[PATH_MAX];
65};
66
67struct comm_event {
68 struct perf_event_header header;
69 u32 pid;
70 u32 tid;
71 char comm[16];
72};
73 66
67struct perf_header *header;
74 68
75struct mmap_data { 69struct mmap_data {
76 int counter; 70 int counter;
@@ -83,7 +77,7 @@ static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
83 77
84static unsigned long mmap_read_head(struct mmap_data *md) 78static unsigned long mmap_read_head(struct mmap_data *md)
85{ 79{
86 struct perf_counter_mmap_page *pc = md->base; 80 struct perf_event_mmap_page *pc = md->base;
87 long head; 81 long head;
88 82
89 head = pc->data_head; 83 head = pc->data_head;
@@ -94,7 +88,7 @@ static unsigned long mmap_read_head(struct mmap_data *md)
94 88
95static void mmap_write_tail(struct mmap_data *md, unsigned long tail) 89static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
96{ 90{
97 struct perf_counter_mmap_page *pc = md->base; 91 struct perf_event_mmap_page *pc = md->base;
98 92
99 /* 93 /*
100 * ensure all reads are done before we write the tail out. 94 * ensure all reads are done before we write the tail out.
@@ -197,47 +191,49 @@ static void sig_atexit(void)
197 kill(getpid(), signr); 191 kill(getpid(), signr);
198} 192}
199 193
200static void pid_synthesize_comm_event(pid_t pid, int full) 194static pid_t pid_synthesize_comm_event(pid_t pid, int full)
201{ 195{
202 struct comm_event comm_ev; 196 struct comm_event comm_ev;
203 char filename[PATH_MAX]; 197 char filename[PATH_MAX];
204 char bf[BUFSIZ]; 198 char bf[BUFSIZ];
205 int fd; 199 FILE *fp;
206 size_t size; 200 size_t size = 0;
207 char *field, *sep;
208 DIR *tasks; 201 DIR *tasks;
209 struct dirent dirent, *next; 202 struct dirent dirent, *next;
203 pid_t tgid = 0;
210 204
211 snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); 205 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
212 206
213 fd = open(filename, O_RDONLY); 207 fp = fopen(filename, "r");
214 if (fd < 0) { 208 if (fp == NULL) {
215 /* 209 /*
216 * We raced with a task exiting - just return: 210 * We raced with a task exiting - just return:
217 */ 211 */
218 if (verbose) 212 if (verbose)
219 fprintf(stderr, "couldn't open %s\n", filename); 213 fprintf(stderr, "couldn't open %s\n", filename);
220 return; 214 return 0;
221 } 215 }
222 if (read(fd, bf, sizeof(bf)) < 0) {
223 fprintf(stderr, "couldn't read %s\n", filename);
224 exit(EXIT_FAILURE);
225 }
226 close(fd);
227 216
228 /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */
229 memset(&comm_ev, 0, sizeof(comm_ev)); 217 memset(&comm_ev, 0, sizeof(comm_ev));
230 field = strchr(bf, '('); 218 while (!comm_ev.comm[0] || !comm_ev.pid) {
231 if (field == NULL) 219 if (fgets(bf, sizeof(bf), fp) == NULL)
232 goto out_failure; 220 goto out_failure;
233 sep = strchr(++field, ')'); 221
234 if (sep == NULL) 222 if (memcmp(bf, "Name:", 5) == 0) {
235 goto out_failure; 223 char *name = bf + 5;
236 size = sep - field; 224 while (*name && isspace(*name))
237 memcpy(comm_ev.comm, field, size++); 225 ++name;
238 226 size = strlen(name) - 1;
239 comm_ev.pid = pid; 227 memcpy(comm_ev.comm, name, size++);
240 comm_ev.header.type = PERF_EVENT_COMM; 228 } else if (memcmp(bf, "Tgid:", 5) == 0) {
229 char *tgids = bf + 5;
230 while (*tgids && isspace(*tgids))
231 ++tgids;
232 tgid = comm_ev.pid = atoi(tgids);
233 }
234 }
235
236 comm_ev.header.type = PERF_RECORD_COMM;
241 size = ALIGN(size, sizeof(u64)); 237 size = ALIGN(size, sizeof(u64));
242 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); 238 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
243 239
@@ -245,7 +241,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
245 comm_ev.tid = pid; 241 comm_ev.tid = pid;
246 242
247 write_output(&comm_ev, comm_ev.header.size); 243 write_output(&comm_ev, comm_ev.header.size);
248 return; 244 goto out_fclose;
249 } 245 }
250 246
251 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 247 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
@@ -262,7 +258,10 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
262 write_output(&comm_ev, comm_ev.header.size); 258 write_output(&comm_ev, comm_ev.header.size);
263 } 259 }
264 closedir(tasks); 260 closedir(tasks);
265 return; 261
262out_fclose:
263 fclose(fp);
264 return tgid;
266 265
267out_failure: 266out_failure:
268 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", 267 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
@@ -270,7 +269,7 @@ out_failure:
270 exit(EXIT_FAILURE); 269 exit(EXIT_FAILURE);
271} 270}
272 271
273static void pid_synthesize_mmap_samples(pid_t pid) 272static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
274{ 273{
275 char filename[PATH_MAX]; 274 char filename[PATH_MAX];
276 FILE *fp; 275 FILE *fp;
@@ -289,7 +288,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
289 while (1) { 288 while (1) {
290 char bf[BUFSIZ], *pbf = bf; 289 char bf[BUFSIZ], *pbf = bf;
291 struct mmap_event mmap_ev = { 290 struct mmap_event mmap_ev = {
292 .header.type = PERF_EVENT_MMAP, 291 .header = { .type = PERF_RECORD_MMAP },
293 }; 292 };
294 int n; 293 int n;
295 size_t size; 294 size_t size;
@@ -306,12 +305,15 @@ static void pid_synthesize_mmap_samples(pid_t pid)
306 continue; 305 continue;
307 pbf += n + 3; 306 pbf += n + 3;
308 if (*pbf == 'x') { /* vm_exec */ 307 if (*pbf == 'x') { /* vm_exec */
309 char *execname = strrchr(bf, ' '); 308 char *execname = strchr(bf, '/');
309
310 /* Catch VDSO */
311 if (execname == NULL)
312 execname = strstr(bf, "[vdso]");
310 313
311 if (execname == NULL || execname[1] != '/') 314 if (execname == NULL)
312 continue; 315 continue;
313 316
314 execname += 1;
315 size = strlen(execname); 317 size = strlen(execname);
316 execname[size - 1] = '\0'; /* Remove \n */ 318 execname[size - 1] = '\0'; /* Remove \n */
317 memcpy(mmap_ev.filename, execname, size); 319 memcpy(mmap_ev.filename, execname, size);
@@ -319,7 +321,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
319 mmap_ev.len -= mmap_ev.start; 321 mmap_ev.len -= mmap_ev.start;
320 mmap_ev.header.size = (sizeof(mmap_ev) - 322 mmap_ev.header.size = (sizeof(mmap_ev) -
321 (sizeof(mmap_ev.filename) - size)); 323 (sizeof(mmap_ev.filename) - size));
322 mmap_ev.pid = pid; 324 mmap_ev.pid = tgid;
323 mmap_ev.tid = pid; 325 mmap_ev.tid = pid;
324 326
325 write_output(&mmap_ev, mmap_ev.header.size); 327 write_output(&mmap_ev, mmap_ev.header.size);
@@ -329,7 +331,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
329 fclose(fp); 331 fclose(fp);
330} 332}
331 333
332static void synthesize_samples(void) 334static void synthesize_all(void)
333{ 335{
334 DIR *proc; 336 DIR *proc;
335 struct dirent dirent, *next; 337 struct dirent dirent, *next;
@@ -338,14 +340,14 @@ static void synthesize_samples(void)
338 340
339 while (!readdir_r(proc, &dirent, &next) && next) { 341 while (!readdir_r(proc, &dirent, &next) && next) {
340 char *end; 342 char *end;
341 pid_t pid; 343 pid_t pid, tgid;
342 344
343 pid = strtol(dirent.d_name, &end, 10); 345 pid = strtol(dirent.d_name, &end, 10);
344 if (*end) /* only interested in proper numerical dirents */ 346 if (*end) /* only interested in proper numerical dirents */
345 continue; 347 continue;
346 348
347 pid_synthesize_comm_event(pid, 1); 349 tgid = pid_synthesize_comm_event(pid, 1);
348 pid_synthesize_mmap_samples(pid); 350 pid_synthesize_mmap_samples(pid, tgid);
349 } 351 }
350 352
351 closedir(proc); 353 closedir(proc);
@@ -353,12 +355,37 @@ static void synthesize_samples(void)
353 355
354static int group_fd; 356static int group_fd;
355 357
356static void create_counter(int counter, int cpu, pid_t pid) 358static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
357{ 359{
358 struct perf_counter_attr *attr = attrs + counter; 360 struct perf_header_attr *h_attr;
359 int track = 1; 361
362 if (nr < header->attrs) {
363 h_attr = header->attr[nr];
364 } else {
365 h_attr = perf_header_attr__new(a);
366 perf_header__add_attr(header, h_attr);
367 }
360 368
361 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 369 return h_attr;
370}
371
372static void create_counter(int counter, int cpu, pid_t pid)
373{
374 struct perf_event_attr *attr = attrs + counter;
375 struct perf_header_attr *h_attr;
376 int track = !counter; /* only the first counter needs these */
377 struct {
378 u64 count;
379 u64 time_enabled;
380 u64 time_running;
381 u64 id;
382 } read_data;
383
384 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
385 PERF_FORMAT_TOTAL_TIME_RUNNING |
386 PERF_FORMAT_ID;
387
388 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
362 389
363 if (freq) { 390 if (freq) {
364 attr->sample_type |= PERF_SAMPLE_PERIOD; 391 attr->sample_type |= PERF_SAMPLE_PERIOD;
@@ -366,16 +393,22 @@ static void create_counter(int counter, int cpu, pid_t pid)
366 attr->sample_freq = freq; 393 attr->sample_freq = freq;
367 } 394 }
368 395
396 if (no_samples)
397 attr->sample_freq = 0;
398
399 if (inherit_stat)
400 attr->inherit_stat = 1;
401
402 if (sample_address)
403 attr->sample_type |= PERF_SAMPLE_ADDR;
404
369 if (call_graph) 405 if (call_graph)
370 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 406 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
371 407
372 if (file_new) { 408 if (raw_samples) {
373 file_header.sample_type = attr->sample_type; 409 attr->sample_type |= PERF_SAMPLE_TIME;
374 } else { 410 attr->sample_type |= PERF_SAMPLE_RAW;
375 if (file_header.sample_type != attr->sample_type) { 411 attr->sample_type |= PERF_SAMPLE_CPU;
376 fprintf(stderr, "incompatible append\n");
377 exit(-1);
378 }
379 } 412 }
380 413
381 attr->mmap = track; 414 attr->mmap = track;
@@ -383,16 +416,16 @@ static void create_counter(int counter, int cpu, pid_t pid)
383 attr->inherit = (cpu < 0) && inherit; 416 attr->inherit = (cpu < 0) && inherit;
384 attr->disabled = 1; 417 attr->disabled = 1;
385 418
386 track = 0; /* only the first counter needs these */
387
388try_again: 419try_again:
389 fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); 420 fd[nr_cpu][counter] = sys_perf_event_open(attr, pid, cpu, group_fd, 0);
390 421
391 if (fd[nr_cpu][counter] < 0) { 422 if (fd[nr_cpu][counter] < 0) {
392 int err = errno; 423 int err = errno;
393 424
394 if (err == EPERM) 425 if (err == EPERM)
395 die("Permission error - are you root?\n"); 426 die("Permission error - are you root?\n");
427 else if (err == ENODEV && profile_cpu != -1)
428 die("No such device - did you specify an out-of-range profile CPU?\n");
396 429
397 /* 430 /*
398 * If it's cycles then fall back to hrtimer 431 * If it's cycles then fall back to hrtimer
@@ -411,10 +444,26 @@ try_again:
411 printf("\n"); 444 printf("\n");
412 error("perfcounter syscall returned with %d (%s)\n", 445 error("perfcounter syscall returned with %d (%s)\n",
413 fd[nr_cpu][counter], strerror(err)); 446 fd[nr_cpu][counter], strerror(err));
414 die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n"); 447 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
448 exit(-1);
449 }
450
451 h_attr = get_header_attr(attr, counter);
452
453 if (!file_new) {
454 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
455 fprintf(stderr, "incompatible append\n");
456 exit(-1);
457 }
458 }
459
460 if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) {
461 perror("Unable to read perf file descriptor\n");
415 exit(-1); 462 exit(-1);
416 } 463 }
417 464
465 perf_header_attr__add_id(h_attr, read_data.id);
466
418 assert(fd[nr_cpu][counter] >= 0); 467 assert(fd[nr_cpu][counter] >= 0);
419 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 468 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
420 469
@@ -423,33 +472,37 @@ try_again:
423 */ 472 */
424 if (group && group_fd == -1) 473 if (group && group_fd == -1)
425 group_fd = fd[nr_cpu][counter]; 474 group_fd = fd[nr_cpu][counter];
475 if (multiplex && multiplex_fd == -1)
476 multiplex_fd = fd[nr_cpu][counter];
426 477
427 event_array[nr_poll].fd = fd[nr_cpu][counter]; 478 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
428 event_array[nr_poll].events = POLLIN; 479 int ret;
429 nr_poll++; 480
430 481 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
431 mmap_array[nr_cpu][counter].counter = counter; 482 assert(ret != -1);
432 mmap_array[nr_cpu][counter].prev = 0; 483 } else {
433 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; 484 event_array[nr_poll].fd = fd[nr_cpu][counter];
434 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, 485 event_array[nr_poll].events = POLLIN;
435 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); 486 nr_poll++;
436 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { 487
437 error("failed to mmap with %d (%s)\n", errno, strerror(errno)); 488 mmap_array[nr_cpu][counter].counter = counter;
438 exit(-1); 489 mmap_array[nr_cpu][counter].prev = 0;
490 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1;
491 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
492 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0);
493 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) {
494 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
495 exit(-1);
496 }
439 } 497 }
440 498
441 ioctl(fd[nr_cpu][counter], PERF_COUNTER_IOC_ENABLE); 499 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
442} 500}
443 501
444static void open_counters(int cpu, pid_t pid) 502static void open_counters(int cpu, pid_t pid)
445{ 503{
446 int counter; 504 int counter;
447 505
448 if (pid > 0) {
449 pid_synthesize_comm_event(pid, 0);
450 pid_synthesize_mmap_samples(pid);
451 }
452
453 group_fd = -1; 506 group_fd = -1;
454 for (counter = 0; counter < nr_counters; counter++) 507 for (counter = 0; counter < nr_counters; counter++)
455 create_counter(counter, cpu, pid); 508 create_counter(counter, cpu, pid);
@@ -459,19 +512,19 @@ static void open_counters(int cpu, pid_t pid)
459 512
460static void atexit_header(void) 513static void atexit_header(void)
461{ 514{
462 file_header.data_size += bytes_written; 515 header->data_size += bytes_written;
463 516
464 if (pwrite(output, &file_header, sizeof(file_header), 0) == -1) 517 perf_header__write(header, output);
465 perror("failed to write on file headers");
466} 518}
467 519
468static int __cmd_record(int argc, const char **argv) 520static int __cmd_record(int argc, const char **argv)
469{ 521{
470 int i, counter; 522 int i, counter;
471 struct stat st; 523 struct stat st;
472 pid_t pid; 524 pid_t pid = 0;
473 int flags; 525 int flags;
474 int ret; 526 int ret;
527 unsigned long waking = 0;
475 528
476 page_size = sysconf(_SC_PAGE_SIZE); 529 page_size = sysconf(_SC_PAGE_SIZE);
477 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 530 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -482,10 +535,14 @@ static int __cmd_record(int argc, const char **argv)
482 signal(SIGCHLD, sig_handler); 535 signal(SIGCHLD, sig_handler);
483 signal(SIGINT, sig_handler); 536 signal(SIGINT, sig_handler);
484 537
485 if (!stat(output_name, &st) && !force && !append_file) { 538 if (!stat(output_name, &st) && st.st_size) {
486 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 539 if (!force && !append_file) {
487 output_name); 540 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
488 exit(-1); 541 output_name);
542 exit(-1);
543 }
544 } else {
545 append_file = 0;
489 } 546 }
490 547
491 flags = O_CREAT|O_RDWR; 548 flags = O_CREAT|O_RDWR;
@@ -500,21 +557,47 @@ static int __cmd_record(int argc, const char **argv)
500 exit(-1); 557 exit(-1);
501 } 558 }
502 559
503 if (!file_new) { 560 if (!file_new)
504 if (read(output, &file_header, sizeof(file_header)) == -1) { 561 header = perf_header__read(output);
505 perror("failed to read file headers"); 562 else
506 exit(-1); 563 header = perf_header__new();
564
565
566 if (raw_samples) {
567 read_tracing_data(attrs, nr_counters);
568 } else {
569 for (i = 0; i < nr_counters; i++) {
570 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
571 read_tracing_data(attrs, nr_counters);
572 break;
573 }
507 } 574 }
575 }
576 atexit(atexit_header);
508 577
509 lseek(output, file_header.data_size, SEEK_CUR); 578 if (!system_wide) {
579 pid = target_pid;
580 if (pid == -1)
581 pid = getpid();
582
583 open_counters(profile_cpu, pid);
584 } else {
585 if (profile_cpu != -1) {
586 open_counters(profile_cpu, target_pid);
587 } else {
588 for (i = 0; i < nr_cpus; i++)
589 open_counters(i, target_pid);
590 }
510 } 591 }
511 592
512 atexit(atexit_header); 593 if (file_new)
594 perf_header__write(header, output);
513 595
514 if (!system_wide) { 596 if (!system_wide) {
515 open_counters(-1, target_pid != -1 ? target_pid : getpid()); 597 pid_t tgid = pid_synthesize_comm_event(pid, 0);
516 } else for (i = 0; i < nr_cpus; i++) 598 pid_synthesize_mmap_samples(pid, tgid);
517 open_counters(i, target_pid); 599 } else
600 synthesize_all();
518 601
519 if (target_pid == -1 && argc) { 602 if (target_pid == -1 && argc) {
520 pid = fork(); 603 pid = fork();
@@ -539,21 +622,33 @@ static int __cmd_record(int argc, const char **argv)
539 } 622 }
540 } 623 }
541 624
542 if (system_wide) 625 for (;;) {
543 synthesize_samples();
544
545 while (!done) {
546 int hits = samples; 626 int hits = samples;
547 627
548 for (i = 0; i < nr_cpu; i++) { 628 for (i = 0; i < nr_cpu; i++) {
549 for (counter = 0; counter < nr_counters; counter++) 629 for (counter = 0; counter < nr_counters; counter++) {
550 mmap_read(&mmap_array[i][counter]); 630 if (mmap_array[i][counter].base)
631 mmap_read(&mmap_array[i][counter]);
632 }
551 } 633 }
552 634
553 if (hits == samples) 635 if (hits == samples) {
554 ret = poll(event_array, nr_poll, 100); 636 if (done)
637 break;
638 ret = poll(event_array, nr_poll, -1);
639 waking++;
640 }
641
642 if (done) {
643 for (i = 0; i < nr_cpu; i++) {
644 for (counter = 0; counter < nr_counters; counter++)
645 ioctl(fd[i][counter], PERF_EVENT_IOC_DISABLE);
646 }
647 }
555 } 648 }
556 649
650 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
651
557 /* 652 /*
558 * Approximate RIP event size: 24 bytes. 653 * Approximate RIP event size: 24 bytes.
559 */ 654 */
@@ -580,10 +675,14 @@ static const struct option options[] = {
580 "record events on existing pid"), 675 "record events on existing pid"),
581 OPT_INTEGER('r', "realtime", &realtime_prio, 676 OPT_INTEGER('r', "realtime", &realtime_prio,
582 "collect data with this RT SCHED_FIFO priority"), 677 "collect data with this RT SCHED_FIFO priority"),
678 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
679 "collect raw sample records from all opened counters"),
583 OPT_BOOLEAN('a', "all-cpus", &system_wide, 680 OPT_BOOLEAN('a', "all-cpus", &system_wide,
584 "system-wide collection from all CPUs"), 681 "system-wide collection from all CPUs"),
585 OPT_BOOLEAN('A', "append", &append_file, 682 OPT_BOOLEAN('A', "append", &append_file,
586 "append to the output file to do incremental profiling"), 683 "append to the output file to do incremental profiling"),
684 OPT_INTEGER('C', "profile_cpu", &profile_cpu,
685 "CPU to profile on"),
587 OPT_BOOLEAN('f', "force", &force, 686 OPT_BOOLEAN('f', "force", &force,
588 "overwrite existing data file"), 687 "overwrite existing data file"),
589 OPT_LONG('c', "count", &default_interval, 688 OPT_LONG('c', "count", &default_interval,
@@ -600,14 +699,23 @@ static const struct option options[] = {
600 "do call-graph (stack chain/backtrace) recording"), 699 "do call-graph (stack chain/backtrace) recording"),
601 OPT_BOOLEAN('v', "verbose", &verbose, 700 OPT_BOOLEAN('v', "verbose", &verbose,
602 "be more verbose (show counter open errors, etc)"), 701 "be more verbose (show counter open errors, etc)"),
702 OPT_BOOLEAN('s', "stat", &inherit_stat,
703 "per thread counts"),
704 OPT_BOOLEAN('d', "data", &sample_address,
705 "Sample addresses"),
706 OPT_BOOLEAN('n', "no-samples", &no_samples,
707 "don't sample"),
708 OPT_BOOLEAN('M', "multiplex", &multiplex,
709 "multiplex counter output in a single channel"),
603 OPT_END() 710 OPT_END()
604}; 711};
605 712
606int cmd_record(int argc, const char **argv, const char *prefix) 713int cmd_record(int argc, const char **argv, const char *prefix __used)
607{ 714{
608 int counter; 715 int counter;
609 716
610 argc = parse_options(argc, argv, options, record_usage, 0); 717 argc = parse_options(argc, argv, options, record_usage,
718 PARSE_OPT_STOP_AT_NON_OPTION);
611 if (!argc && target_pid == -1 && !system_wide) 719 if (!argc && target_pid == -1 && !system_wide)
612 usage_with_options(record_usage, options); 720 usage_with_options(record_usage, options);
613 721
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 5eb5566f0c95..19669c20088e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -10,38 +10,45 @@
10#include "util/util.h" 10#include "util/util.h"
11 11
12#include "util/color.h" 12#include "util/color.h"
13#include "util/list.h" 13#include <linux/list.h>
14#include "util/cache.h" 14#include "util/cache.h"
15#include "util/rbtree.h" 15#include <linux/rbtree.h>
16#include "util/symbol.h" 16#include "util/symbol.h"
17#include "util/string.h" 17#include "util/string.h"
18#include "util/callchain.h"
19#include "util/strlist.h"
20#include "util/values.h"
18 21
19#include "perf.h" 22#include "perf.h"
23#include "util/debug.h"
24#include "util/header.h"
20 25
21#include "util/parse-options.h" 26#include "util/parse-options.h"
22#include "util/parse-events.h" 27#include "util/parse-events.h"
23 28
24#define SHOW_KERNEL 1 29#include "util/thread.h"
25#define SHOW_USER 2
26#define SHOW_HV 4
27 30
28static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
29static char *vmlinux = NULL;
30 32
31static char default_sort_order[] = "comm,dso"; 33static char default_sort_order[] = "comm,dso,symbol";
32static char *sort_order = default_sort_order; 34static char *sort_order = default_sort_order;
35static char *dso_list_str, *comm_list_str, *sym_list_str,
36 *col_width_list_str;
37static struct strlist *dso_list, *comm_list, *sym_list;
38static char *field_sep;
33 39
40static int force;
34static int input; 41static int input;
35static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 42static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
36 43
37static int dump_trace = 0; 44static int full_paths;
38#define dprintf(x...) do { if (dump_trace) printf(x); } while (0) 45static int show_nr_samples;
39#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
40 46
41static int verbose; 47static int show_threads;
42#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0) 48static struct perf_read_values show_threads_values;
43 49
44static int full_paths; 50static char default_pretty_printing_style[] = "normal";
51static char *pretty_printing_style = default_pretty_printing_style;
45 52
46static unsigned long page_size; 53static unsigned long page_size;
47static unsigned long mmap_window = 32; 54static unsigned long mmap_window = 32;
@@ -52,410 +59,58 @@ static regex_t parent_regex;
52 59
53static int exclude_other = 1; 60static int exclude_other = 1;
54 61
55struct ip_event { 62static char callchain_default_opt[] = "fractal,0.5";
56 struct perf_event_header header;
57 u64 ip;
58 u32 pid, tid;
59 unsigned char __more_data[];
60};
61
62struct ip_callchain {
63 u64 nr;
64 u64 ips[0];
65};
66
67struct mmap_event {
68 struct perf_event_header header;
69 u32 pid, tid;
70 u64 start;
71 u64 len;
72 u64 pgoff;
73 char filename[PATH_MAX];
74};
75
76struct comm_event {
77 struct perf_event_header header;
78 u32 pid, tid;
79 char comm[16];
80};
81
82struct fork_event {
83 struct perf_event_header header;
84 u32 pid, ppid;
85};
86
87struct period_event {
88 struct perf_event_header header;
89 u64 time;
90 u64 id;
91 u64 sample_period;
92};
93
94struct lost_event {
95 struct perf_event_header header;
96 u64 id;
97 u64 lost;
98};
99
100typedef union event_union {
101 struct perf_event_header header;
102 struct ip_event ip;
103 struct mmap_event mmap;
104 struct comm_event comm;
105 struct fork_event fork;
106 struct period_event period;
107 struct lost_event lost;
108} event_t;
109
110static LIST_HEAD(dsos);
111static struct dso *kernel_dso;
112static struct dso *vdso;
113
114static void dsos__add(struct dso *dso)
115{
116 list_add_tail(&dso->node, &dsos);
117}
118
119static struct dso *dsos__find(const char *name)
120{
121 struct dso *pos;
122
123 list_for_each_entry(pos, &dsos, node)
124 if (strcmp(pos->name, name) == 0)
125 return pos;
126 return NULL;
127}
128
129static struct dso *dsos__findnew(const char *name)
130{
131 struct dso *dso = dsos__find(name);
132 int nr;
133
134 if (dso)
135 return dso;
136
137 dso = dso__new(name, 0);
138 if (!dso)
139 goto out_delete_dso;
140
141 nr = dso__load(dso, NULL, verbose);
142 if (nr < 0) {
143 eprintf("Failed to open: %s\n", name);
144 goto out_delete_dso;
145 }
146 if (!nr)
147 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
148
149 dsos__add(dso);
150
151 return dso;
152
153out_delete_dso:
154 dso__delete(dso);
155 return NULL;
156}
157
158static void dsos__fprintf(FILE *fp)
159{
160 struct dso *pos;
161
162 list_for_each_entry(pos, &dsos, node)
163 dso__fprintf(pos, fp);
164}
165
166static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
167{
168 return dso__find_symbol(kernel_dso, ip);
169}
170
171static int load_kernel(void)
172{
173 int err;
174
175 kernel_dso = dso__new("[kernel]", 0);
176 if (!kernel_dso)
177 return -1;
178
179 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
180 if (err) {
181 dso__delete(kernel_dso);
182 kernel_dso = NULL;
183 } else
184 dsos__add(kernel_dso);
185
186 vdso = dso__new("[vdso]", 0);
187 if (!vdso)
188 return -1;
189 63
190 vdso->find_symbol = vdso__find_symbol; 64static int callchain;
191 65
192 dsos__add(vdso); 66static char __cwd[PATH_MAX];
67static char *cwd = __cwd;
68static int cwdlen;
193 69
194 return err; 70static struct rb_root threads;
195} 71static struct thread *last_match;
196
197static char __cwd[PATH_MAX];
198static char *cwd = __cwd;
199static int cwdlen;
200
201static int strcommon(const char *pathname)
202{
203 int n = 0;
204 72
205 while (pathname[n] == cwd[n] && n < cwdlen) 73static struct perf_header *header;
206 ++n;
207
208 return n;
209}
210 74
211struct map { 75static
212 struct list_head node; 76struct callchain_param callchain_param = {
213 u64 start; 77 .mode = CHAIN_GRAPH_REL,
214 u64 end; 78 .min_percent = 0.5
215 u64 pgoff;
216 u64 (*map_ip)(struct map *, u64);
217 struct dso *dso;
218}; 79};
219 80
220static u64 map__map_ip(struct map *map, u64 ip) 81static u64 sample_type;
221{
222 return ip - map->start + map->pgoff;
223}
224
225static u64 vdso__map_ip(struct map *map, u64 ip)
226{
227 return ip;
228}
229
230static inline int is_anon_memory(const char *filename)
231{
232 return strcmp(filename, "//anon") == 0;
233}
234 82
235static struct map *map__new(struct mmap_event *event) 83static int repsep_fprintf(FILE *fp, const char *fmt, ...)
236{ 84{
237 struct map *self = malloc(sizeof(*self)); 85 int n;
238 86 va_list ap;
239 if (self != NULL) { 87
240 const char *filename = event->filename; 88 va_start(ap, fmt);
241 char newfilename[PATH_MAX]; 89 if (!field_sep)
242 int anon; 90 n = vfprintf(fp, fmt, ap);
243 91 else {
244 if (cwd) { 92 char *bf = NULL;
245 int n = strcommon(filename); 93 n = vasprintf(&bf, fmt, ap);
246 94 if (n > 0) {
247 if (n == cwdlen) { 95 char *sep = bf;
248 snprintf(newfilename, sizeof(newfilename), 96
249 ".%s", filename + n); 97 while (1) {
250 filename = newfilename; 98 sep = strchr(sep, *field_sep);
99 if (sep == NULL)
100 break;
101 *sep = '.';
251 } 102 }
252 } 103 }
253 104 fputs(bf, fp);
254 anon = is_anon_memory(filename); 105 free(bf);
255
256 if (anon) {
257 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
258 filename = newfilename;
259 }
260
261 self->start = event->start;
262 self->end = event->start + event->len;
263 self->pgoff = event->pgoff;
264
265 self->dso = dsos__findnew(filename);
266 if (self->dso == NULL)
267 goto out_delete;
268
269 if (self->dso == vdso || anon)
270 self->map_ip = vdso__map_ip;
271 else
272 self->map_ip = map__map_ip;
273 }
274 return self;
275out_delete:
276 free(self);
277 return NULL;
278}
279
280static struct map *map__clone(struct map *self)
281{
282 struct map *map = malloc(sizeof(*self));
283
284 if (!map)
285 return NULL;
286
287 memcpy(map, self, sizeof(*self));
288
289 return map;
290}
291
292static int map__overlap(struct map *l, struct map *r)
293{
294 if (l->start > r->start) {
295 struct map *t = l;
296 l = r;
297 r = t;
298 }
299
300 if (l->end > r->start)
301 return 1;
302
303 return 0;
304}
305
306static size_t map__fprintf(struct map *self, FILE *fp)
307{
308 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
309 self->start, self->end, self->pgoff, self->dso->name);
310}
311
312
313struct thread {
314 struct rb_node rb_node;
315 struct list_head maps;
316 pid_t pid;
317 char *comm;
318};
319
320static struct thread *thread__new(pid_t pid)
321{
322 struct thread *self = malloc(sizeof(*self));
323
324 if (self != NULL) {
325 self->pid = pid;
326 self->comm = malloc(32);
327 if (self->comm)
328 snprintf(self->comm, 32, ":%d", self->pid);
329 INIT_LIST_HEAD(&self->maps);
330 } 106 }
331 107 va_end(ap);
332 return self; 108 return n;
333}
334
335static int thread__set_comm(struct thread *self, const char *comm)
336{
337 if (self->comm)
338 free(self->comm);
339 self->comm = strdup(comm);
340 return self->comm ? 0 : -ENOMEM;
341}
342
343static size_t thread__fprintf(struct thread *self, FILE *fp)
344{
345 struct map *pos;
346 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
347
348 list_for_each_entry(pos, &self->maps, node)
349 ret += map__fprintf(pos, fp);
350
351 return ret;
352}
353
354
355static struct rb_root threads;
356static struct thread *last_match;
357
358static struct thread *threads__findnew(pid_t pid)
359{
360 struct rb_node **p = &threads.rb_node;
361 struct rb_node *parent = NULL;
362 struct thread *th;
363
364 /*
365 * Font-end cache - PID lookups come in blocks,
366 * so most of the time we dont have to look up
367 * the full rbtree:
368 */
369 if (last_match && last_match->pid == pid)
370 return last_match;
371
372 while (*p != NULL) {
373 parent = *p;
374 th = rb_entry(parent, struct thread, rb_node);
375
376 if (th->pid == pid) {
377 last_match = th;
378 return th;
379 }
380
381 if (pid < th->pid)
382 p = &(*p)->rb_left;
383 else
384 p = &(*p)->rb_right;
385 }
386
387 th = thread__new(pid);
388 if (th != NULL) {
389 rb_link_node(&th->rb_node, parent, p);
390 rb_insert_color(&th->rb_node, &threads);
391 last_match = th;
392 }
393
394 return th;
395}
396
397static void thread__insert_map(struct thread *self, struct map *map)
398{
399 struct map *pos, *tmp;
400
401 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
402 if (map__overlap(pos, map)) {
403 list_del_init(&pos->node);
404 /* XXX leaks dsos */
405 free(pos);
406 }
407 }
408
409 list_add_tail(&map->node, &self->maps);
410}
411
412static int thread__fork(struct thread *self, struct thread *parent)
413{
414 struct map *map;
415
416 if (self->comm)
417 free(self->comm);
418 self->comm = strdup(parent->comm);
419 if (!self->comm)
420 return -ENOMEM;
421
422 list_for_each_entry(map, &parent->maps, node) {
423 struct map *new = map__clone(map);
424 if (!new)
425 return -ENOMEM;
426 thread__insert_map(self, new);
427 }
428
429 return 0;
430}
431
432static struct map *thread__find_map(struct thread *self, u64 ip)
433{
434 struct map *pos;
435
436 if (self == NULL)
437 return NULL;
438
439 list_for_each_entry(pos, &self->maps, node)
440 if (ip >= pos->start && ip <= pos->end)
441 return pos;
442
443 return NULL;
444} 109}
445 110
446static size_t threads__fprintf(FILE *fp) 111static unsigned int dsos__col_width,
447{ 112 comms__col_width,
448 size_t ret = 0; 113 threads__col_width;
449 struct rb_node *nd;
450
451 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
452 struct thread *pos = rb_entry(nd, struct thread, rb_node);
453
454 ret += thread__fprintf(pos, fp);
455 }
456
457 return ret;
458}
459 114
460/* 115/*
461 * histogram, sorted on item, collects counts 116 * histogram, sorted on item, collects counts
@@ -464,17 +119,19 @@ static size_t threads__fprintf(FILE *fp)
464static struct rb_root hist; 119static struct rb_root hist;
465 120
466struct hist_entry { 121struct hist_entry {
467 struct rb_node rb_node; 122 struct rb_node rb_node;
468 123
469 struct thread *thread; 124 struct thread *thread;
470 struct map *map; 125 struct map *map;
471 struct dso *dso; 126 struct dso *dso;
472 struct symbol *sym; 127 struct symbol *sym;
473 struct symbol *parent; 128 struct symbol *parent;
474 u64 ip; 129 u64 ip;
475 char level; 130 char level;
476 131 struct callchain_node callchain;
477 u64 count; 132 struct rb_root sorted_chain;
133
134 u64 count;
478}; 135};
479 136
480/* 137/*
@@ -484,11 +141,13 @@ struct hist_entry {
484struct sort_entry { 141struct sort_entry {
485 struct list_head list; 142 struct list_head list;
486 143
487 char *header; 144 const char *header;
488 145
489 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 146 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
490 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 147 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
491 size_t (*print)(FILE *fp, struct hist_entry *); 148 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
149 unsigned int *width;
150 bool elide;
492}; 151};
493 152
494static int64_t cmp_null(void *l, void *r) 153static int64_t cmp_null(void *l, void *r)
@@ -510,15 +169,17 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
510} 169}
511 170
512static size_t 171static size_t
513sort__thread_print(FILE *fp, struct hist_entry *self) 172sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
514{ 173{
515 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); 174 return repsep_fprintf(fp, "%*s:%5d", width - 6,
175 self->thread->comm ?: "", self->thread->pid);
516} 176}
517 177
518static struct sort_entry sort_thread = { 178static struct sort_entry sort_thread = {
519 .header = " Command: Pid", 179 .header = "Command: Pid",
520 .cmp = sort__thread_cmp, 180 .cmp = sort__thread_cmp,
521 .print = sort__thread_print, 181 .print = sort__thread_print,
182 .width = &threads__col_width,
522}; 183};
523 184
524/* --sort comm */ 185/* --sort comm */
@@ -542,16 +203,17 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
542} 203}
543 204
544static size_t 205static size_t
545sort__comm_print(FILE *fp, struct hist_entry *self) 206sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
546{ 207{
547 return fprintf(fp, "%16s", self->thread->comm); 208 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
548} 209}
549 210
550static struct sort_entry sort_comm = { 211static struct sort_entry sort_comm = {
551 .header = " Command", 212 .header = "Command",
552 .cmp = sort__comm_cmp, 213 .cmp = sort__comm_cmp,
553 .collapse = sort__comm_collapse, 214 .collapse = sort__comm_collapse,
554 .print = sort__comm_print, 215 .print = sort__comm_print,
216 .width = &comms__col_width,
555}; 217};
556 218
557/* --sort dso */ 219/* --sort dso */
@@ -569,18 +231,19 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
569} 231}
570 232
571static size_t 233static size_t
572sort__dso_print(FILE *fp, struct hist_entry *self) 234sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
573{ 235{
574 if (self->dso) 236 if (self->dso)
575 return fprintf(fp, "%-25s", self->dso->name); 237 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
576 238
577 return fprintf(fp, "%016llx ", (u64)self->ip); 239 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
578} 240}
579 241
580static struct sort_entry sort_dso = { 242static struct sort_entry sort_dso = {
581 .header = "Shared Object ", 243 .header = "Shared Object",
582 .cmp = sort__dso_cmp, 244 .cmp = sort__dso_cmp,
583 .print = sort__dso_print, 245 .print = sort__dso_print,
246 .width = &dsos__col_width,
584}; 247};
585 248
586/* --sort symbol */ 249/* --sort symbol */
@@ -600,18 +263,23 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
600} 263}
601 264
602static size_t 265static size_t
603sort__sym_print(FILE *fp, struct hist_entry *self) 266sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
604{ 267{
605 size_t ret = 0; 268 size_t ret = 0;
606 269
607 if (verbose) 270 if (verbose)
608 ret += fprintf(fp, "%#018llx ", (u64)self->ip); 271 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
272 dso__symtab_origin(self->dso));
609 273
274 ret += repsep_fprintf(fp, "[%c] ", self->level);
610 if (self->sym) { 275 if (self->sym) {
611 ret += fprintf(fp, "[%c] %s", 276 ret += repsep_fprintf(fp, "%s", self->sym->name);
612 self->dso == kernel_dso ? 'k' : '.', self->sym->name); 277
278 if (self->sym->module)
279 ret += repsep_fprintf(fp, "\t[%s]",
280 self->sym->module->name);
613 } else { 281 } else {
614 ret += fprintf(fp, "%#016llx", (u64)self->ip); 282 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
615 } 283 }
616 284
617 return ret; 285 return ret;
@@ -638,26 +306,26 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
638} 306}
639 307
640static size_t 308static size_t
641sort__parent_print(FILE *fp, struct hist_entry *self) 309sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
642{ 310{
643 size_t ret = 0; 311 return repsep_fprintf(fp, "%-*s", width,
644 312 self->parent ? self->parent->name : "[other]");
645 ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]");
646
647 return ret;
648} 313}
649 314
315static unsigned int parent_symbol__col_width;
316
650static struct sort_entry sort_parent = { 317static struct sort_entry sort_parent = {
651 .header = "Parent symbol ", 318 .header = "Parent symbol",
652 .cmp = sort__parent_cmp, 319 .cmp = sort__parent_cmp,
653 .print = sort__parent_print, 320 .print = sort__parent_print,
321 .width = &parent_symbol__col_width,
654}; 322};
655 323
656static int sort__need_collapse = 0; 324static int sort__need_collapse = 0;
657static int sort__has_parent = 0; 325static int sort__has_parent = 0;
658 326
659struct sort_dimension { 327struct sort_dimension {
660 char *name; 328 const char *name;
661 struct sort_entry *entry; 329 struct sort_entry *entry;
662 int taken; 330 int taken;
663}; 331};
@@ -672,9 +340,9 @@ static struct sort_dimension sort_dimensions[] = {
672 340
673static LIST_HEAD(hist_entry__sort_list); 341static LIST_HEAD(hist_entry__sort_list);
674 342
675static int sort_dimension__add(char *tok) 343static int sort_dimension__add(const char *tok)
676{ 344{
677 int i; 345 unsigned int i;
678 346
679 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 347 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
680 struct sort_dimension *sd = &sort_dimensions[i]; 348 struct sort_dimension *sd = &sort_dimensions[i];
@@ -744,6 +412,205 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
744 return cmp; 412 return cmp;
745} 413}
746 414
415static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
416{
417 int i;
418 size_t ret = 0;
419
420 ret += fprintf(fp, "%s", " ");
421
422 for (i = 0; i < depth; i++)
423 if (depth_mask & (1 << i))
424 ret += fprintf(fp, "| ");
425 else
426 ret += fprintf(fp, " ");
427
428 ret += fprintf(fp, "\n");
429
430 return ret;
431}
432static size_t
433ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
434 int depth_mask, int count, u64 total_samples,
435 int hits)
436{
437 int i;
438 size_t ret = 0;
439
440 ret += fprintf(fp, "%s", " ");
441 for (i = 0; i < depth; i++) {
442 if (depth_mask & (1 << i))
443 ret += fprintf(fp, "|");
444 else
445 ret += fprintf(fp, " ");
446 if (!count && i == depth - 1) {
447 double percent;
448
449 percent = hits * 100.0 / total_samples;
450 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
451 } else
452 ret += fprintf(fp, "%s", " ");
453 }
454 if (chain->sym)
455 ret += fprintf(fp, "%s\n", chain->sym->name);
456 else
457 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
458
459 return ret;
460}
461
462static struct symbol *rem_sq_bracket;
463static struct callchain_list rem_hits;
464
465static void init_rem_hits(void)
466{
467 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
468 if (!rem_sq_bracket) {
469 fprintf(stderr, "Not enough memory to display remaining hits\n");
470 return;
471 }
472
473 strcpy(rem_sq_bracket->name, "[...]");
474 rem_hits.sym = rem_sq_bracket;
475}
476
477static size_t
478callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
479 u64 total_samples, int depth, int depth_mask)
480{
481 struct rb_node *node, *next;
482 struct callchain_node *child;
483 struct callchain_list *chain;
484 int new_depth_mask = depth_mask;
485 u64 new_total;
486 u64 remaining;
487 size_t ret = 0;
488 int i;
489
490 if (callchain_param.mode == CHAIN_GRAPH_REL)
491 new_total = self->children_hit;
492 else
493 new_total = total_samples;
494
495 remaining = new_total;
496
497 node = rb_first(&self->rb_root);
498 while (node) {
499 u64 cumul;
500
501 child = rb_entry(node, struct callchain_node, rb_node);
502 cumul = cumul_hits(child);
503 remaining -= cumul;
504
505 /*
506 * The depth mask manages the output of pipes that show
507 * the depth. We don't want to keep the pipes of the current
508 * level for the last child of this depth.
509 * Except if we have remaining filtered hits. They will
510 * supersede the last child
511 */
512 next = rb_next(node);
513 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
514 new_depth_mask &= ~(1 << (depth - 1));
515
516 /*
517 * But we keep the older depth mask for the line seperator
518 * to keep the level link until we reach the last child
519 */
520 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
521 i = 0;
522 list_for_each_entry(chain, &child->val, list) {
523 if (chain->ip >= PERF_CONTEXT_MAX)
524 continue;
525 ret += ipchain__fprintf_graph(fp, chain, depth,
526 new_depth_mask, i++,
527 new_total,
528 cumul);
529 }
530 ret += callchain__fprintf_graph(fp, child, new_total,
531 depth + 1,
532 new_depth_mask | (1 << depth));
533 node = next;
534 }
535
536 if (callchain_param.mode == CHAIN_GRAPH_REL &&
537 remaining && remaining != new_total) {
538
539 if (!rem_sq_bracket)
540 return ret;
541
542 new_depth_mask &= ~(1 << (depth - 1));
543
544 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
545 new_depth_mask, 0, new_total,
546 remaining);
547 }
548
549 return ret;
550}
551
552static size_t
553callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
554 u64 total_samples)
555{
556 struct callchain_list *chain;
557 size_t ret = 0;
558
559 if (!self)
560 return 0;
561
562 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
563
564
565 list_for_each_entry(chain, &self->val, list) {
566 if (chain->ip >= PERF_CONTEXT_MAX)
567 continue;
568 if (chain->sym)
569 ret += fprintf(fp, " %s\n", chain->sym->name);
570 else
571 ret += fprintf(fp, " %p\n",
572 (void *)(long)chain->ip);
573 }
574
575 return ret;
576}
577
578static size_t
579hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
580 u64 total_samples)
581{
582 struct rb_node *rb_node;
583 struct callchain_node *chain;
584 size_t ret = 0;
585
586 rb_node = rb_first(&self->sorted_chain);
587 while (rb_node) {
588 double percent;
589
590 chain = rb_entry(rb_node, struct callchain_node, rb_node);
591 percent = chain->hit * 100.0 / total_samples;
592 switch (callchain_param.mode) {
593 case CHAIN_FLAT:
594 ret += percent_color_fprintf(fp, " %6.2f%%\n",
595 percent);
596 ret += callchain__fprintf_flat(fp, chain, total_samples);
597 break;
598 case CHAIN_GRAPH_ABS: /* Falldown */
599 case CHAIN_GRAPH_REL:
600 ret += callchain__fprintf_graph(fp, chain,
601 total_samples, 1, 1);
602 case CHAIN_NONE:
603 default:
604 break;
605 }
606 ret += fprintf(fp, "\n");
607 rb_node = rb_next(rb_node);
608 }
609
610 return ret;
611}
612
613
747static size_t 614static size_t
748hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples) 615hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
749{ 616{
@@ -753,37 +620,33 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
753 if (exclude_other && !self->parent) 620 if (exclude_other && !self->parent)
754 return 0; 621 return 0;
755 622
756 if (total_samples) { 623 if (total_samples)
757 double percent = self->count * 100.0 / total_samples; 624 ret = percent_color_fprintf(fp,
758 char *color = PERF_COLOR_NORMAL; 625 field_sep ? "%.2f" : " %6.2f%%",
759 626 (self->count * 100.0) / total_samples);
760 /* 627 else
761 * We color high-overhead entries in red, mid-overhead 628 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
762 * entries in green - and keep the low overhead places
763 * normal:
764 */
765 if (percent >= 5.0) {
766 color = PERF_COLOR_RED;
767 } else {
768 if (percent >= 0.5)
769 color = PERF_COLOR_GREEN;
770 }
771 629
772 ret = color_fprintf(fp, color, " %6.2f%%", 630 if (show_nr_samples) {
773 (self->count * 100.0) / total_samples); 631 if (field_sep)
774 } else 632 fprintf(fp, "%c%lld", *field_sep, self->count);
775 ret = fprintf(fp, "%12Ld ", self->count); 633 else
634 fprintf(fp, "%11lld", self->count);
635 }
776 636
777 list_for_each_entry(se, &hist_entry__sort_list, list) { 637 list_for_each_entry(se, &hist_entry__sort_list, list) {
778 if (exclude_other && (se == &sort_parent)) 638 if (se->elide)
779 continue; 639 continue;
780 640
781 fprintf(fp, " "); 641 fprintf(fp, "%s", field_sep ?: " ");
782 ret += se->print(fp, self); 642 ret += se->print(fp, self, se->width ? *se->width : 0);
783 } 643 }
784 644
785 ret += fprintf(fp, "\n"); 645 ret += fprintf(fp, "\n");
786 646
647 if (callchain)
648 hist_entry_callchain__fprintf(fp, self, total_samples);
649
787 return ret; 650 return ret;
788} 651}
789 652
@@ -791,13 +654,53 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
791 * 654 *
792 */ 655 */
793 656
657static void dso__calc_col_width(struct dso *self)
658{
659 if (!col_width_list_str && !field_sep &&
660 (!dso_list || strlist__has_entry(dso_list, self->name))) {
661 unsigned int slen = strlen(self->name);
662 if (slen > dsos__col_width)
663 dsos__col_width = slen;
664 }
665
666 self->slen_calculated = 1;
667}
668
669static void thread__comm_adjust(struct thread *self)
670{
671 char *comm = self->comm;
672
673 if (!col_width_list_str && !field_sep &&
674 (!comm_list || strlist__has_entry(comm_list, comm))) {
675 unsigned int slen = strlen(comm);
676
677 if (slen > comms__col_width) {
678 comms__col_width = slen;
679 threads__col_width = slen + 6;
680 }
681 }
682}
683
684static int thread__set_comm_adjust(struct thread *self, const char *comm)
685{
686 int ret = thread__set_comm(self, comm);
687
688 if (ret)
689 return ret;
690
691 thread__comm_adjust(self);
692
693 return 0;
694}
695
696
794static struct symbol * 697static struct symbol *
795resolve_symbol(struct thread *thread, struct map **mapp, 698resolve_symbol(struct thread *thread, struct map **mapp,
796 struct dso **dsop, u64 *ipp) 699 struct dso **dsop, u64 *ipp)
797{ 700{
798 struct dso *dso = dsop ? *dsop : NULL; 701 struct dso *dso = dsop ? *dsop : NULL;
799 struct map *map = mapp ? *mapp : NULL; 702 struct map *map = mapp ? *mapp : NULL;
800 uint64_t ip = *ipp; 703 u64 ip = *ipp;
801 704
802 if (!thread) 705 if (!thread)
803 return NULL; 706 return NULL;
@@ -810,11 +713,18 @@ resolve_symbol(struct thread *thread, struct map **mapp,
810 713
811 map = thread__find_map(thread, ip); 714 map = thread__find_map(thread, ip);
812 if (map != NULL) { 715 if (map != NULL) {
716 /*
717 * We have to do this here as we may have a dso
718 * with no symbol hit that has a name longer than
719 * the ones with symbols sampled.
720 */
721 if (!sort_dso.elide && !map->dso->slen_calculated)
722 dso__calc_col_width(map->dso);
723
813 if (mapp) 724 if (mapp)
814 *mapp = map; 725 *mapp = map;
815got_map: 726got_map:
816 ip = map->map_ip(map, ip); 727 ip = map->map_ip(map, ip);
817 *ipp = ip;
818 728
819 dso = map->dso; 729 dso = map->dso;
820 } else { 730 } else {
@@ -827,7 +737,9 @@ got_map:
827 if ((long long)ip < 0) 737 if ((long long)ip < 0)
828 dso = kernel_dso; 738 dso = kernel_dso;
829 } 739 }
830 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 740 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
741 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
742 *ipp = ip;
831 743
832 if (dsop) 744 if (dsop)
833 *dsop = dso; 745 *dsop = dso;
@@ -846,6 +758,58 @@ static int call__match(struct symbol *sym)
846 return 0; 758 return 0;
847} 759}
848 760
761static struct symbol **
762resolve_callchain(struct thread *thread, struct map *map __used,
763 struct ip_callchain *chain, struct hist_entry *entry)
764{
765 u64 context = PERF_CONTEXT_MAX;
766 struct symbol **syms = NULL;
767 unsigned int i;
768
769 if (callchain) {
770 syms = calloc(chain->nr, sizeof(*syms));
771 if (!syms) {
772 fprintf(stderr, "Can't allocate memory for symbols\n");
773 exit(-1);
774 }
775 }
776
777 for (i = 0; i < chain->nr; i++) {
778 u64 ip = chain->ips[i];
779 struct dso *dso = NULL;
780 struct symbol *sym;
781
782 if (ip >= PERF_CONTEXT_MAX) {
783 context = ip;
784 continue;
785 }
786
787 switch (context) {
788 case PERF_CONTEXT_HV:
789 dso = hypervisor_dso;
790 break;
791 case PERF_CONTEXT_KERNEL:
792 dso = kernel_dso;
793 break;
794 default:
795 break;
796 }
797
798 sym = resolve_symbol(thread, NULL, &dso, &ip);
799
800 if (sym) {
801 if (sort__has_parent && call__match(sym) &&
802 !entry->parent)
803 entry->parent = sym;
804 if (!callchain)
805 break;
806 syms[i] = sym;
807 }
808 }
809
810 return syms;
811}
812
849/* 813/*
850 * collect histogram counts 814 * collect histogram counts
851 */ 815 */
@@ -858,6 +822,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
858 struct rb_node **p = &hist.rb_node; 822 struct rb_node **p = &hist.rb_node;
859 struct rb_node *parent = NULL; 823 struct rb_node *parent = NULL;
860 struct hist_entry *he; 824 struct hist_entry *he;
825 struct symbol **syms = NULL;
861 struct hist_entry entry = { 826 struct hist_entry entry = {
862 .thread = thread, 827 .thread = thread,
863 .map = map, 828 .map = map,
@@ -867,39 +832,12 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
867 .level = level, 832 .level = level,
868 .count = count, 833 .count = count,
869 .parent = NULL, 834 .parent = NULL,
835 .sorted_chain = RB_ROOT
870 }; 836 };
871 int cmp; 837 int cmp;
872 838
873 if (sort__has_parent && chain) { 839 if ((sort__has_parent || callchain) && chain)
874 u64 context = PERF_CONTEXT_MAX; 840 syms = resolve_callchain(thread, map, chain, &entry);
875 int i;
876
877 for (i = 0; i < chain->nr; i++) {
878 u64 ip = chain->ips[i];
879 struct dso *dso = NULL;
880 struct symbol *sym;
881
882 if (ip >= PERF_CONTEXT_MAX) {
883 context = ip;
884 continue;
885 }
886
887 switch (context) {
888 case PERF_CONTEXT_KERNEL:
889 dso = kernel_dso;
890 break;
891 default:
892 break;
893 }
894
895 sym = resolve_symbol(thread, NULL, &dso, &ip);
896
897 if (sym && call__match(sym)) {
898 entry.parent = sym;
899 break;
900 }
901 }
902 }
903 841
904 while (*p != NULL) { 842 while (*p != NULL) {
905 parent = *p; 843 parent = *p;
@@ -909,6 +847,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
909 847
910 if (!cmp) { 848 if (!cmp) {
911 he->count += count; 849 he->count += count;
850 if (callchain) {
851 append_chain(&he->callchain, chain, syms);
852 free(syms);
853 }
912 return 0; 854 return 0;
913 } 855 }
914 856
@@ -922,6 +864,11 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
922 if (!he) 864 if (!he)
923 return -ENOMEM; 865 return -ENOMEM;
924 *he = entry; 866 *he = entry;
867 if (callchain) {
868 callchain_init(&he->callchain);
869 append_chain(&he->callchain, chain, syms);
870 free(syms);
871 }
925 rb_link_node(&he->rb_node, parent, p); 872 rb_link_node(&he->rb_node, parent, p);
926 rb_insert_color(&he->rb_node, &hist); 873 rb_insert_color(&he->rb_node, &hist);
927 874
@@ -992,12 +939,16 @@ static void collapse__resort(void)
992 939
993static struct rb_root output_hists; 940static struct rb_root output_hists;
994 941
995static void output__insert_entry(struct hist_entry *he) 942static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
996{ 943{
997 struct rb_node **p = &output_hists.rb_node; 944 struct rb_node **p = &output_hists.rb_node;
998 struct rb_node *parent = NULL; 945 struct rb_node *parent = NULL;
999 struct hist_entry *iter; 946 struct hist_entry *iter;
1000 947
948 if (callchain)
949 callchain_param.sort(&he->sorted_chain, &he->callchain,
950 min_callchain_hits, &callchain_param);
951
1001 while (*p != NULL) { 952 while (*p != NULL) {
1002 parent = *p; 953 parent = *p;
1003 iter = rb_entry(parent, struct hist_entry, rb_node); 954 iter = rb_entry(parent, struct hist_entry, rb_node);
@@ -1012,11 +963,14 @@ static void output__insert_entry(struct hist_entry *he)
1012 rb_insert_color(&he->rb_node, &output_hists); 963 rb_insert_color(&he->rb_node, &output_hists);
1013} 964}
1014 965
1015static void output__resort(void) 966static void output__resort(u64 total_samples)
1016{ 967{
1017 struct rb_node *next; 968 struct rb_node *next;
1018 struct hist_entry *n; 969 struct hist_entry *n;
1019 struct rb_root *tree = &hist; 970 struct rb_root *tree = &hist;
971 u64 min_callchain_hits;
972
973 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
1020 974
1021 if (sort__need_collapse) 975 if (sort__need_collapse)
1022 tree = &collapse_hists; 976 tree = &collapse_hists;
@@ -1028,7 +982,7 @@ static void output__resort(void)
1028 next = rb_next(&n->rb_node); 982 next = rb_next(&n->rb_node);
1029 983
1030 rb_erase(&n->rb_node, tree); 984 rb_erase(&n->rb_node, tree);
1031 output__insert_entry(n); 985 output__insert_entry(n, min_callchain_hits);
1032 } 986 }
1033} 987}
1034 988
@@ -1038,35 +992,72 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1038 struct sort_entry *se; 992 struct sort_entry *se;
1039 struct rb_node *nd; 993 struct rb_node *nd;
1040 size_t ret = 0; 994 size_t ret = 0;
995 unsigned int width;
996 char *col_width = col_width_list_str;
997 int raw_printing_style;
1041 998
1042 fprintf(fp, "\n"); 999 raw_printing_style = !strcmp(pretty_printing_style, "raw");
1043 fprintf(fp, "#\n"); 1000
1044 fprintf(fp, "# (%Ld samples)\n", (u64)total_samples); 1001 init_rem_hits();
1002
1003 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1045 fprintf(fp, "#\n"); 1004 fprintf(fp, "#\n");
1046 1005
1047 fprintf(fp, "# Overhead"); 1006 fprintf(fp, "# Overhead");
1007 if (show_nr_samples) {
1008 if (field_sep)
1009 fprintf(fp, "%cSamples", *field_sep);
1010 else
1011 fputs(" Samples ", fp);
1012 }
1048 list_for_each_entry(se, &hist_entry__sort_list, list) { 1013 list_for_each_entry(se, &hist_entry__sort_list, list) {
1049 if (exclude_other && (se == &sort_parent)) 1014 if (se->elide)
1015 continue;
1016 if (field_sep) {
1017 fprintf(fp, "%c%s", *field_sep, se->header);
1050 continue; 1018 continue;
1051 fprintf(fp, " %s", se->header); 1019 }
1020 width = strlen(se->header);
1021 if (se->width) {
1022 if (col_width_list_str) {
1023 if (col_width) {
1024 *se->width = atoi(col_width);
1025 col_width = strchr(col_width, ',');
1026 if (col_width)
1027 ++col_width;
1028 }
1029 }
1030 width = *se->width = max(*se->width, width);
1031 }
1032 fprintf(fp, " %*s", width, se->header);
1052 } 1033 }
1053 fprintf(fp, "\n"); 1034 fprintf(fp, "\n");
1054 1035
1036 if (field_sep)
1037 goto print_entries;
1038
1055 fprintf(fp, "# ........"); 1039 fprintf(fp, "# ........");
1040 if (show_nr_samples)
1041 fprintf(fp, " ..........");
1056 list_for_each_entry(se, &hist_entry__sort_list, list) { 1042 list_for_each_entry(se, &hist_entry__sort_list, list) {
1057 int i; 1043 unsigned int i;
1058 1044
1059 if (exclude_other && (se == &sort_parent)) 1045 if (se->elide)
1060 continue; 1046 continue;
1061 1047
1062 fprintf(fp, " "); 1048 fprintf(fp, " ");
1063 for (i = 0; i < strlen(se->header); i++) 1049 if (se->width)
1050 width = *se->width;
1051 else
1052 width = strlen(se->header);
1053 for (i = 0; i < width; i++)
1064 fprintf(fp, "."); 1054 fprintf(fp, ".");
1065 } 1055 }
1066 fprintf(fp, "\n"); 1056 fprintf(fp, "\n");
1067 1057
1068 fprintf(fp, "#\n"); 1058 fprintf(fp, "#\n");
1069 1059
1060print_entries:
1070 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 1061 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1071 pos = rb_entry(nd, struct hist_entry, rb_node); 1062 pos = rb_entry(nd, struct hist_entry, rb_node);
1072 ret += hist_entry__fprintf(fp, pos, total_samples); 1063 ret += hist_entry__fprintf(fp, pos, total_samples);
@@ -1075,23 +1066,18 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1075 if (sort_order == default_sort_order && 1066 if (sort_order == default_sort_order &&
1076 parent_pattern == default_parent_pattern) { 1067 parent_pattern == default_parent_pattern) {
1077 fprintf(fp, "#\n"); 1068 fprintf(fp, "#\n");
1078 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); 1069 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1079 fprintf(fp, "#\n"); 1070 fprintf(fp, "#\n");
1080 } 1071 }
1081 fprintf(fp, "\n"); 1072 fprintf(fp, "\n");
1082 1073
1083 return ret; 1074 free(rem_sq_bracket);
1084}
1085 1075
1086static void register_idle_thread(void) 1076 if (show_threads)
1087{ 1077 perf_read_values_display(fp, &show_threads_values,
1088 struct thread *thread = threads__findnew(0); 1078 raw_printing_style);
1089 1079
1090 if (thread == NULL || 1080 return ret;
1091 thread__set_comm(thread, "[idle]")) {
1092 fprintf(stderr, "problem inserting idle task.\n");
1093 exit(-1);
1094 }
1095} 1081}
1096 1082
1097static unsigned long total = 0, 1083static unsigned long total = 0,
@@ -1115,37 +1101,40 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
1115} 1101}
1116 1102
1117static int 1103static int
1118process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 1104process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1119{ 1105{
1120 char level; 1106 char level;
1121 int show = 0; 1107 int show = 0;
1122 struct dso *dso = NULL; 1108 struct dso *dso = NULL;
1123 struct thread *thread = threads__findnew(event->ip.pid); 1109 struct thread *thread;
1124 u64 ip = event->ip.ip; 1110 u64 ip = event->ip.ip;
1125 u64 period = 1; 1111 u64 period = 1;
1126 struct map *map = NULL; 1112 struct map *map = NULL;
1127 void *more_data = event->ip.__more_data; 1113 void *more_data = event->ip.__more_data;
1128 struct ip_callchain *chain = NULL; 1114 struct ip_callchain *chain = NULL;
1115 int cpumode;
1129 1116
1130 if (event->header.type & PERF_SAMPLE_PERIOD) { 1117 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1118
1119 if (sample_type & PERF_SAMPLE_PERIOD) {
1131 period = *(u64 *)more_data; 1120 period = *(u64 *)more_data;
1132 more_data += sizeof(u64); 1121 more_data += sizeof(u64);
1133 } 1122 }
1134 1123
1135 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n", 1124 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1136 (void *)(offset + head), 1125 (void *)(offset + head),
1137 (void *)(long)(event->header.size), 1126 (void *)(long)(event->header.size),
1138 event->header.misc, 1127 event->header.misc,
1139 event->ip.pid, 1128 event->ip.pid, event->ip.tid,
1140 (void *)(long)ip, 1129 (void *)(long)ip,
1141 (long long)period); 1130 (long long)period);
1142 1131
1143 if (event->header.type & PERF_SAMPLE_CALLCHAIN) { 1132 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1144 int i; 1133 unsigned int i;
1145 1134
1146 chain = (void *)more_data; 1135 chain = (void *)more_data;
1147 1136
1148 dprintf("... chain: nr:%Lu\n", chain->nr); 1137 dump_printf("... chain: nr:%Lu\n", chain->nr);
1149 1138
1150 if (validate_chain(chain, event) < 0) { 1139 if (validate_chain(chain, event) < 0) {
1151 eprintf("call-chain problem with event, skipping it.\n"); 1140 eprintf("call-chain problem with event, skipping it.\n");
@@ -1154,11 +1143,11 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1154 1143
1155 if (dump_trace) { 1144 if (dump_trace) {
1156 for (i = 0; i < chain->nr; i++) 1145 for (i = 0; i < chain->nr; i++)
1157 dprintf("..... %2d: %016Lx\n", i, chain->ips[i]); 1146 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
1158 } 1147 }
1159 } 1148 }
1160 1149
1161 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1150 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1162 1151
1163 if (thread == NULL) { 1152 if (thread == NULL) {
1164 eprintf("problem processing %d event, skipping it.\n", 1153 eprintf("problem processing %d event, skipping it.\n",
@@ -1166,15 +1155,20 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1166 return -1; 1155 return -1;
1167 } 1156 }
1168 1157
1169 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 1158 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1159 return 0;
1160
1161 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1162
1163 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1170 show = SHOW_KERNEL; 1164 show = SHOW_KERNEL;
1171 level = 'k'; 1165 level = 'k';
1172 1166
1173 dso = kernel_dso; 1167 dso = kernel_dso;
1174 1168
1175 dprintf(" ...... dso: %s\n", dso->name); 1169 dump_printf(" ...... dso: %s\n", dso->name);
1176 1170
1177 } else if (event->header.misc & PERF_EVENT_MISC_USER) { 1171 } else if (cpumode == PERF_RECORD_MISC_USER) {
1178 1172
1179 show = SHOW_USER; 1173 show = SHOW_USER;
1180 level = '.'; 1174 level = '.';
@@ -1182,12 +1176,22 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1182 } else { 1176 } else {
1183 show = SHOW_HV; 1177 show = SHOW_HV;
1184 level = 'H'; 1178 level = 'H';
1185 dprintf(" ...... dso: [hypervisor]\n"); 1179
1180 dso = hypervisor_dso;
1181
1182 dump_printf(" ...... dso: [hypervisor]\n");
1186 } 1183 }
1187 1184
1188 if (show & show_mask) { 1185 if (show & show_mask) {
1189 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 1186 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1190 1187
1188 if (dso_list && (!dso || !dso->name ||
1189 !strlist__has_entry(dso_list, dso->name)))
1190 return 0;
1191
1192 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1193 return 0;
1194
1191 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { 1195 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1192 eprintf("problem incrementing symbol count, skipping event\n"); 1196 eprintf("problem incrementing symbol count, skipping event\n");
1193 return -1; 1197 return -1;
@@ -1201,20 +1205,23 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1201static int 1205static int
1202process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 1206process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1203{ 1207{
1204 struct thread *thread = threads__findnew(event->mmap.pid); 1208 struct thread *thread;
1205 struct map *map = map__new(&event->mmap); 1209 struct map *map = map__new(&event->mmap, cwd, cwdlen);
1210
1211 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
1206 1212
1207 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", 1213 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1208 (void *)(offset + head), 1214 (void *)(offset + head),
1209 (void *)(long)(event->header.size), 1215 (void *)(long)(event->header.size),
1210 event->mmap.pid, 1216 event->mmap.pid,
1217 event->mmap.tid,
1211 (void *)(long)event->mmap.start, 1218 (void *)(long)event->mmap.start,
1212 (void *)(long)event->mmap.len, 1219 (void *)(long)event->mmap.len,
1213 (void *)(long)event->mmap.pgoff, 1220 (void *)(long)event->mmap.pgoff,
1214 event->mmap.filename); 1221 event->mmap.filename);
1215 1222
1216 if (thread == NULL || map == NULL) { 1223 if (thread == NULL || map == NULL) {
1217 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); 1224 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
1218 return 0; 1225 return 0;
1219 } 1226 }
1220 1227
@@ -1227,16 +1234,18 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1227static int 1234static int
1228process_comm_event(event_t *event, unsigned long offset, unsigned long head) 1235process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1229{ 1236{
1230 struct thread *thread = threads__findnew(event->comm.pid); 1237 struct thread *thread;
1231 1238
1232 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", 1239 thread = threads__findnew(event->comm.pid, &threads, &last_match);
1240
1241 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
1233 (void *)(offset + head), 1242 (void *)(offset + head),
1234 (void *)(long)(event->header.size), 1243 (void *)(long)(event->header.size),
1235 event->comm.comm, event->comm.pid); 1244 event->comm.comm, event->comm.pid);
1236 1245
1237 if (thread == NULL || 1246 if (thread == NULL ||
1238 thread__set_comm(thread, event->comm.comm)) { 1247 thread__set_comm_adjust(thread, event->comm.comm)) {
1239 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); 1248 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
1240 return -1; 1249 return -1;
1241 } 1250 }
1242 total_comm++; 1251 total_comm++;
@@ -1245,18 +1254,33 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1245} 1254}
1246 1255
1247static int 1256static int
1248process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1257process_task_event(event_t *event, unsigned long offset, unsigned long head)
1249{ 1258{
1250 struct thread *thread = threads__findnew(event->fork.pid); 1259 struct thread *thread;
1251 struct thread *parent = threads__findnew(event->fork.ppid); 1260 struct thread *parent;
1261
1262 thread = threads__findnew(event->fork.pid, &threads, &last_match);
1263 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
1252 1264
1253 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1265 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
1254 (void *)(offset + head), 1266 (void *)(offset + head),
1255 (void *)(long)(event->header.size), 1267 (void *)(long)(event->header.size),
1256 event->fork.pid, event->fork.ppid); 1268 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
1269 event->fork.pid, event->fork.tid,
1270 event->fork.ppid, event->fork.ptid);
1271
1272 /*
1273 * A thread clone will have the same PID for both
1274 * parent and child.
1275 */
1276 if (thread == parent)
1277 return 0;
1278
1279 if (event->header.type == PERF_RECORD_EXIT)
1280 return 0;
1257 1281
1258 if (!thread || !parent || thread__fork(thread, parent)) { 1282 if (!thread || !parent || thread__fork(thread, parent)) {
1259 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1283 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1260 return -1; 1284 return -1;
1261 } 1285 }
1262 total_fork++; 1286 total_fork++;
@@ -1265,22 +1289,9 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1265} 1289}
1266 1290
1267static int 1291static int
1268process_period_event(event_t *event, unsigned long offset, unsigned long head)
1269{
1270 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
1271 (void *)(offset + head),
1272 (void *)(long)(event->header.size),
1273 event->period.time,
1274 event->period.id,
1275 event->period.sample_period);
1276
1277 return 0;
1278}
1279
1280static int
1281process_lost_event(event_t *event, unsigned long offset, unsigned long head) 1292process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1282{ 1293{
1283 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", 1294 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
1284 (void *)(offset + head), 1295 (void *)(offset + head),
1285 (void *)(long)(event->header.size), 1296 (void *)(long)(event->header.size),
1286 event->lost.id, 1297 event->lost.id,
@@ -1291,40 +1302,33 @@ process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1291 return 0; 1302 return 0;
1292} 1303}
1293 1304
1294static void trace_event(event_t *event) 1305static int
1306process_read_event(event_t *event, unsigned long offset, unsigned long head)
1295{ 1307{
1296 unsigned char *raw_event = (void *)event; 1308 struct perf_event_attr *attr;
1297 char *color = PERF_COLOR_BLUE; 1309
1298 int i, j; 1310 attr = perf_header__find_attr(event->read.id, header);
1299 1311
1300 if (!dump_trace) 1312 if (show_threads) {
1301 return; 1313 const char *name = attr ? __event_name(attr->type, attr->config)
1302 1314 : "unknown";
1303 dprintf("."); 1315 perf_read_values_add_value(&show_threads_values,
1304 cdprintf("\n. ... raw event: size %d bytes\n", event->header.size); 1316 event->read.pid, event->read.tid,
1317 event->read.id,
1318 name,
1319 event->read.value);
1320 }
1305 1321
1306 for (i = 0; i < event->header.size; i++) { 1322 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
1307 if ((i & 15) == 0) { 1323 (void *)(offset + head),
1308 dprintf("."); 1324 (void *)(long)(event->header.size),
1309 cdprintf(" %04x: ", i); 1325 event->read.pid,
1310 } 1326 event->read.tid,
1327 attr ? __event_name(attr->type, attr->config)
1328 : "FAIL",
1329 event->read.value);
1311 1330
1312 cdprintf(" %02x", raw_event[i]); 1331 return 0;
1313
1314 if (((i & 15) == 15) || i == event->header.size-1) {
1315 cdprintf(" ");
1316 for (j = 0; j < 15-(i & 15); j++)
1317 cdprintf(" ");
1318 for (j = 0; j < (i & 15); j++) {
1319 if (isprint(raw_event[i-15+j]))
1320 cdprintf("%c", raw_event[i-15+j]);
1321 else
1322 cdprintf(".");
1323 }
1324 cdprintf("\n");
1325 }
1326 }
1327 dprintf(".\n");
1328} 1332}
1329 1333
1330static int 1334static int
@@ -1332,31 +1336,32 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1332{ 1336{
1333 trace_event(event); 1337 trace_event(event);
1334 1338
1335 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1336 return process_overflow_event(event, offset, head);
1337
1338 switch (event->header.type) { 1339 switch (event->header.type) {
1339 case PERF_EVENT_MMAP: 1340 case PERF_RECORD_SAMPLE:
1341 return process_sample_event(event, offset, head);
1342
1343 case PERF_RECORD_MMAP:
1340 return process_mmap_event(event, offset, head); 1344 return process_mmap_event(event, offset, head);
1341 1345
1342 case PERF_EVENT_COMM: 1346 case PERF_RECORD_COMM:
1343 return process_comm_event(event, offset, head); 1347 return process_comm_event(event, offset, head);
1344 1348
1345 case PERF_EVENT_FORK: 1349 case PERF_RECORD_FORK:
1346 return process_fork_event(event, offset, head); 1350 case PERF_RECORD_EXIT:
1347 1351 return process_task_event(event, offset, head);
1348 case PERF_EVENT_PERIOD:
1349 return process_period_event(event, offset, head);
1350 1352
1351 case PERF_EVENT_LOST: 1353 case PERF_RECORD_LOST:
1352 return process_lost_event(event, offset, head); 1354 return process_lost_event(event, offset, head);
1353 1355
1356 case PERF_RECORD_READ:
1357 return process_read_event(event, offset, head);
1358
1354 /* 1359 /*
1355 * We dont process them right now but they are fine: 1360 * We dont process them right now but they are fine:
1356 */ 1361 */
1357 1362
1358 case PERF_EVENT_THROTTLE: 1363 case PERF_RECORD_THROTTLE:
1359 case PERF_EVENT_UNTHROTTLE: 1364 case PERF_RECORD_UNTHROTTLE:
1360 return 0; 1365 return 0;
1361 1366
1362 default: 1367 default:
@@ -1366,19 +1371,22 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1366 return 0; 1371 return 0;
1367} 1372}
1368 1373
1369static struct perf_file_header file_header;
1370
1371static int __cmd_report(void) 1374static int __cmd_report(void)
1372{ 1375{
1373 int ret, rc = EXIT_FAILURE; 1376 int ret, rc = EXIT_FAILURE;
1374 unsigned long offset = 0; 1377 unsigned long offset = 0;
1375 unsigned long head = sizeof(file_header); 1378 unsigned long head, shift;
1376 struct stat stat; 1379 struct stat input_stat;
1380 struct thread *idle;
1377 event_t *event; 1381 event_t *event;
1378 uint32_t size; 1382 uint32_t size;
1379 char *buf; 1383 char *buf;
1380 1384
1381 register_idle_thread(); 1385 idle = register_idle_thread(&threads, &last_match);
1386 thread__comm_adjust(idle);
1387
1388 if (show_threads)
1389 perf_read_values_init(&show_threads_values);
1382 1390
1383 input = open(input_name, O_RDONLY); 1391 input = open(input_name, O_RDONLY);
1384 if (input < 0) { 1392 if (input < 0) {
@@ -1389,26 +1397,47 @@ static int __cmd_report(void)
1389 exit(-1); 1397 exit(-1);
1390 } 1398 }
1391 1399
1392 ret = fstat(input, &stat); 1400 ret = fstat(input, &input_stat);
1393 if (ret < 0) { 1401 if (ret < 0) {
1394 perror("failed to stat file"); 1402 perror("failed to stat file");
1395 exit(-1); 1403 exit(-1);
1396 } 1404 }
1397 1405
1398 if (!stat.st_size) { 1406 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
1407 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
1408 exit(-1);
1409 }
1410
1411 if (!input_stat.st_size) {
1399 fprintf(stderr, "zero-sized file, nothing to do!\n"); 1412 fprintf(stderr, "zero-sized file, nothing to do!\n");
1400 exit(0); 1413 exit(0);
1401 } 1414 }
1402 1415
1403 if (read(input, &file_header, sizeof(file_header)) == -1) { 1416 header = perf_header__read(input);
1404 perror("failed to read file headers"); 1417 head = header->data_offset;
1405 exit(-1);
1406 }
1407 1418
1408 if (sort__has_parent && 1419 sample_type = perf_header__sample_type(header);
1409 !(file_header.sample_type & PERF_SAMPLE_CALLCHAIN)) { 1420
1410 fprintf(stderr, "selected --sort parent, but no callchain data\n"); 1421 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1411 exit(-1); 1422 if (sort__has_parent) {
1423 fprintf(stderr, "selected --sort parent, but no"
1424 " callchain data. Did you call"
1425 " perf record without -g?\n");
1426 exit(-1);
1427 }
1428 if (callchain) {
1429 fprintf(stderr, "selected -g but no callchain data."
1430 " Did you call perf record without"
1431 " -g?\n");
1432 exit(-1);
1433 }
1434 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1435 callchain = 1;
1436 if (register_callchain_param(&callchain_param) < 0) {
1437 fprintf(stderr, "Can't register callchain"
1438 " params\n");
1439 exit(-1);
1440 }
1412 } 1441 }
1413 1442
1414 if (load_kernel() < 0) { 1443 if (load_kernel() < 0) {
@@ -1426,6 +1455,11 @@ static int __cmd_report(void)
1426 cwd = NULL; 1455 cwd = NULL;
1427 cwdlen = 0; 1456 cwdlen = 0;
1428 } 1457 }
1458
1459 shift = page_size * (head / page_size);
1460 offset += shift;
1461 head -= shift;
1462
1429remap: 1463remap:
1430 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 1464 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1431 MAP_SHARED, input, offset); 1465 MAP_SHARED, input, offset);
@@ -1442,11 +1476,12 @@ more:
1442 size = 8; 1476 size = 8;
1443 1477
1444 if (head + event->header.size >= page_size * mmap_window) { 1478 if (head + event->header.size >= page_size * mmap_window) {
1445 unsigned long shift = page_size * (head / page_size); 1479 int munmap_ret;
1446 int ret;
1447 1480
1448 ret = munmap(buf, page_size * mmap_window); 1481 shift = page_size * (head / page_size);
1449 assert(ret == 0); 1482
1483 munmap_ret = munmap(buf, page_size * mmap_window);
1484 assert(munmap_ret == 0);
1450 1485
1451 offset += shift; 1486 offset += shift;
1452 head -= shift; 1487 head -= shift;
@@ -1455,14 +1490,14 @@ more:
1455 1490
1456 size = event->header.size; 1491 size = event->header.size;
1457 1492
1458 dprintf("\n%p [%p]: event: %d\n", 1493 dump_printf("\n%p [%p]: event: %d\n",
1459 (void *)(offset + head), 1494 (void *)(offset + head),
1460 (void *)(long)event->header.size, 1495 (void *)(long)event->header.size,
1461 event->header.type); 1496 event->header.type);
1462 1497
1463 if (!size || process_event(event, offset, head) < 0) { 1498 if (!size || process_event(event, offset, head) < 0) {
1464 1499
1465 dprintf("%p [%p]: skipping unknown header type: %d\n", 1500 dump_printf("%p [%p]: skipping unknown header type: %d\n",
1466 (void *)(offset + head), 1501 (void *)(offset + head),
1467 (void *)(long)(event->header.size), 1502 (void *)(long)(event->header.size),
1468 event->header.type); 1503 event->header.type);
@@ -1482,39 +1517,95 @@ more:
1482 1517
1483 head += size; 1518 head += size;
1484 1519
1485 if (offset + head >= sizeof(file_header) + file_header.data_size) 1520 if (offset + head >= header->data_offset + header->data_size)
1486 goto done; 1521 goto done;
1487 1522
1488 if (offset + head < stat.st_size) 1523 if (offset + head < (unsigned long)input_stat.st_size)
1489 goto more; 1524 goto more;
1490 1525
1491done: 1526done:
1492 rc = EXIT_SUCCESS; 1527 rc = EXIT_SUCCESS;
1493 close(input); 1528 close(input);
1494 1529
1495 dprintf(" IP events: %10ld\n", total); 1530 dump_printf(" IP events: %10ld\n", total);
1496 dprintf(" mmap events: %10ld\n", total_mmap); 1531 dump_printf(" mmap events: %10ld\n", total_mmap);
1497 dprintf(" comm events: %10ld\n", total_comm); 1532 dump_printf(" comm events: %10ld\n", total_comm);
1498 dprintf(" fork events: %10ld\n", total_fork); 1533 dump_printf(" fork events: %10ld\n", total_fork);
1499 dprintf(" lost events: %10ld\n", total_lost); 1534 dump_printf(" lost events: %10ld\n", total_lost);
1500 dprintf(" unknown events: %10ld\n", total_unknown); 1535 dump_printf(" unknown events: %10ld\n", total_unknown);
1501 1536
1502 if (dump_trace) 1537 if (dump_trace)
1503 return 0; 1538 return 0;
1504 1539
1505 if (verbose >= 3) 1540 if (verbose >= 3)
1506 threads__fprintf(stdout); 1541 threads__fprintf(stdout, &threads);
1507 1542
1508 if (verbose >= 2) 1543 if (verbose >= 2)
1509 dsos__fprintf(stdout); 1544 dsos__fprintf(stdout);
1510 1545
1511 collapse__resort(); 1546 collapse__resort();
1512 output__resort(); 1547 output__resort(total);
1513 output__fprintf(stdout, total); 1548 output__fprintf(stdout, total);
1514 1549
1550 if (show_threads)
1551 perf_read_values_destroy(&show_threads_values);
1552
1515 return rc; 1553 return rc;
1516} 1554}
1517 1555
1556static int
1557parse_callchain_opt(const struct option *opt __used, const char *arg,
1558 int unset __used)
1559{
1560 char *tok;
1561 char *endptr;
1562
1563 callchain = 1;
1564
1565 if (!arg)
1566 return 0;
1567
1568 tok = strtok((char *)arg, ",");
1569 if (!tok)
1570 return -1;
1571
1572 /* get the output mode */
1573 if (!strncmp(tok, "graph", strlen(arg)))
1574 callchain_param.mode = CHAIN_GRAPH_ABS;
1575
1576 else if (!strncmp(tok, "flat", strlen(arg)))
1577 callchain_param.mode = CHAIN_FLAT;
1578
1579 else if (!strncmp(tok, "fractal", strlen(arg)))
1580 callchain_param.mode = CHAIN_GRAPH_REL;
1581
1582 else if (!strncmp(tok, "none", strlen(arg))) {
1583 callchain_param.mode = CHAIN_NONE;
1584 callchain = 0;
1585
1586 return 0;
1587 }
1588
1589 else
1590 return -1;
1591
1592 /* get the min percentage */
1593 tok = strtok(NULL, ",");
1594 if (!tok)
1595 goto setup;
1596
1597 callchain_param.min_percent = strtod(tok, &endptr);
1598 if (tok == endptr)
1599 return -1;
1600
1601setup:
1602 if (register_callchain_param(&callchain_param) < 0) {
1603 fprintf(stderr, "Can't register callchain params\n");
1604 return -1;
1605 }
1606 return 0;
1607}
1608
1518static const char * const report_usage[] = { 1609static const char * const report_usage[] = {
1519 "perf report [<options>] <command>", 1610 "perf report [<options>] <command>",
1520 NULL 1611 NULL
@@ -1527,7 +1618,16 @@ static const struct option options[] = {
1527 "be more verbose (show symbol address, etc)"), 1618 "be more verbose (show symbol address, etc)"),
1528 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1619 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1529 "dump raw trace in ASCII"), 1620 "dump raw trace in ASCII"),
1530 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1621 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
1622 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1623 OPT_BOOLEAN('m', "modules", &modules,
1624 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1625 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1626 "Show a column with the number of samples"),
1627 OPT_BOOLEAN('T', "threads", &show_threads,
1628 "Show per-thread event counters"),
1629 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
1630 "pretty printing style key: normal raw"),
1531 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1631 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1532 "sort by key(s): pid, comm, dso, symbol, parent"), 1632 "sort by key(s): pid, comm, dso, symbol, parent"),
1533 OPT_BOOLEAN('P', "full-paths", &full_paths, 1633 OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1536,6 +1636,21 @@ static const struct option options[] = {
1536 "regex filter to identify parent, see: '--sort parent'"), 1636 "regex filter to identify parent, see: '--sort parent'"),
1537 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 1637 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1538 "Only display entries with parent-match"), 1638 "Only display entries with parent-match"),
1639 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1640 "Display callchains using output_type and min percent threshold. "
1641 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1642 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1643 "only consider symbols in these dsos"),
1644 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1645 "only consider symbols in these comms"),
1646 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1647 "only consider these symbols"),
1648 OPT_STRING('w', "column-widths", &col_width_list_str,
1649 "width[,width...]",
1650 "don't try to adjust column width, use these fixed values"),
1651 OPT_STRING('t', "field-separator", &field_sep, "separator",
1652 "separator for columns, no spaces will be added between "
1653 "columns '.' is reserved."),
1539 OPT_END() 1654 OPT_END()
1540}; 1655};
1541 1656
@@ -1554,7 +1669,26 @@ static void setup_sorting(void)
1554 free(str); 1669 free(str);
1555} 1670}
1556 1671
1557int cmd_report(int argc, const char **argv, const char *prefix) 1672static void setup_list(struct strlist **list, const char *list_str,
1673 struct sort_entry *se, const char *list_name,
1674 FILE *fp)
1675{
1676 if (list_str) {
1677 *list = strlist__new(true, list_str);
1678 if (!*list) {
1679 fprintf(stderr, "problems parsing %s list\n",
1680 list_name);
1681 exit(129);
1682 }
1683 if (strlist__nr_entries(*list) == 1) {
1684 fprintf(fp, "# %s: %s\n", list_name,
1685 strlist__entry(*list, 0)->s);
1686 se->elide = true;
1687 }
1688 }
1689}
1690
1691int cmd_report(int argc, const char **argv, const char *prefix __used)
1558{ 1692{
1559 symbol__init(); 1693 symbol__init();
1560 1694
@@ -1564,9 +1698,10 @@ int cmd_report(int argc, const char **argv, const char *prefix)
1564 1698
1565 setup_sorting(); 1699 setup_sorting();
1566 1700
1567 if (parent_pattern != default_parent_pattern) 1701 if (parent_pattern != default_parent_pattern) {
1568 sort_dimension__add("parent"); 1702 sort_dimension__add("parent");
1569 else 1703 sort_parent.elide = 1;
1704 } else
1570 exclude_other = 0; 1705 exclude_other = 0;
1571 1706
1572 /* 1707 /*
@@ -1577,5 +1712,15 @@ int cmd_report(int argc, const char **argv, const char *prefix)
1577 1712
1578 setup_pager(); 1713 setup_pager();
1579 1714
1715 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
1716 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
1717 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
1718
1719 if (field_sep && *field_sep == '.') {
1720 fputs("'.' is the only non valid --field-separator argument\n",
1721 stderr);
1722 exit(129);
1723 }
1724
1580 return __cmd_report(); 1725 return __cmd_report();
1581} 1726}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
new file mode 100644
index 000000000000..ea9c15c0cdfe
--- /dev/null
+++ b/tools/perf/builtin-sched.c
@@ -0,0 +1,2004 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/util.h"
5#include "util/cache.h"
6#include "util/symbol.h"
7#include "util/thread.h"
8#include "util/header.h"
9
10#include "util/parse-options.h"
11#include "util/trace-event.h"
12
13#include "util/debug.h"
14
15#include <sys/types.h>
16#include <sys/prctl.h>
17
18#include <semaphore.h>
19#include <pthread.h>
20#include <math.h>
21
22static char const *input_name = "perf.data";
23static int input;
24static unsigned long page_size;
25static unsigned long mmap_window = 32;
26
27static unsigned long total_comm = 0;
28
29static struct rb_root threads;
30static struct thread *last_match;
31
32static struct perf_header *header;
33static u64 sample_type;
34
35static char default_sort_order[] = "avg, max, switch, runtime";
36static char *sort_order = default_sort_order;
37
38#define PR_SET_NAME 15 /* Set process name */
39#define MAX_CPUS 4096
40
41#define BUG_ON(x) assert(!(x))
42
43static u64 run_measurement_overhead;
44static u64 sleep_measurement_overhead;
45
46#define COMM_LEN 20
47#define SYM_LEN 129
48
49#define MAX_PID 65536
50
51static unsigned long nr_tasks;
52
53struct sched_atom;
54
55struct task_desc {
56 unsigned long nr;
57 unsigned long pid;
58 char comm[COMM_LEN];
59
60 unsigned long nr_events;
61 unsigned long curr_event;
62 struct sched_atom **atoms;
63
64 pthread_t thread;
65 sem_t sleep_sem;
66
67 sem_t ready_for_work;
68 sem_t work_done_sem;
69
70 u64 cpu_usage;
71};
72
73enum sched_event_type {
74 SCHED_EVENT_RUN,
75 SCHED_EVENT_SLEEP,
76 SCHED_EVENT_WAKEUP,
77};
78
79struct sched_atom {
80 enum sched_event_type type;
81 u64 timestamp;
82 u64 duration;
83 unsigned long nr;
84 int specific_wait;
85 sem_t *wait_sem;
86 struct task_desc *wakee;
87};
88
89static struct task_desc *pid_to_task[MAX_PID];
90
91static struct task_desc **tasks;
92
93static pthread_mutex_t start_work_mutex = PTHREAD_MUTEX_INITIALIZER;
94static u64 start_time;
95
96static pthread_mutex_t work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
97
98static unsigned long nr_run_events;
99static unsigned long nr_sleep_events;
100static unsigned long nr_wakeup_events;
101
102static unsigned long nr_sleep_corrections;
103static unsigned long nr_run_events_optimized;
104
105static unsigned long targetless_wakeups;
106static unsigned long multitarget_wakeups;
107
108static u64 cpu_usage;
109static u64 runavg_cpu_usage;
110static u64 parent_cpu_usage;
111static u64 runavg_parent_cpu_usage;
112
113static unsigned long nr_runs;
114static u64 sum_runtime;
115static u64 sum_fluct;
116static u64 run_avg;
117
118static unsigned long replay_repeat = 10;
119static unsigned long nr_timestamps;
120static unsigned long nr_unordered_timestamps;
121static unsigned long nr_state_machine_bugs;
122static unsigned long nr_context_switch_bugs;
123static unsigned long nr_events;
124static unsigned long nr_lost_chunks;
125static unsigned long nr_lost_events;
126
127#define TASK_STATE_TO_CHAR_STR "RSDTtZX"
128
129enum thread_state {
130 THREAD_SLEEPING = 0,
131 THREAD_WAIT_CPU,
132 THREAD_SCHED_IN,
133 THREAD_IGNORE
134};
135
136struct work_atom {
137 struct list_head list;
138 enum thread_state state;
139 u64 sched_out_time;
140 u64 wake_up_time;
141 u64 sched_in_time;
142 u64 runtime;
143};
144
145struct work_atoms {
146 struct list_head work_list;
147 struct thread *thread;
148 struct rb_node node;
149 u64 max_lat;
150 u64 total_lat;
151 u64 nb_atoms;
152 u64 total_runtime;
153};
154
155typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *);
156
157static struct rb_root atom_root, sorted_atom_root;
158
159static u64 all_runtime;
160static u64 all_count;
161
162
163static u64 get_nsecs(void)
164{
165 struct timespec ts;
166
167 clock_gettime(CLOCK_MONOTONIC, &ts);
168
169 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
170}
171
172static void burn_nsecs(u64 nsecs)
173{
174 u64 T0 = get_nsecs(), T1;
175
176 do {
177 T1 = get_nsecs();
178 } while (T1 + run_measurement_overhead < T0 + nsecs);
179}
180
181static void sleep_nsecs(u64 nsecs)
182{
183 struct timespec ts;
184
185 ts.tv_nsec = nsecs % 999999999;
186 ts.tv_sec = nsecs / 999999999;
187
188 nanosleep(&ts, NULL);
189}
190
191static void calibrate_run_measurement_overhead(void)
192{
193 u64 T0, T1, delta, min_delta = 1000000000ULL;
194 int i;
195
196 for (i = 0; i < 10; i++) {
197 T0 = get_nsecs();
198 burn_nsecs(0);
199 T1 = get_nsecs();
200 delta = T1-T0;
201 min_delta = min(min_delta, delta);
202 }
203 run_measurement_overhead = min_delta;
204
205 printf("run measurement overhead: %Ld nsecs\n", min_delta);
206}
207
208static void calibrate_sleep_measurement_overhead(void)
209{
210 u64 T0, T1, delta, min_delta = 1000000000ULL;
211 int i;
212
213 for (i = 0; i < 10; i++) {
214 T0 = get_nsecs();
215 sleep_nsecs(10000);
216 T1 = get_nsecs();
217 delta = T1-T0;
218 min_delta = min(min_delta, delta);
219 }
220 min_delta -= 10000;
221 sleep_measurement_overhead = min_delta;
222
223 printf("sleep measurement overhead: %Ld nsecs\n", min_delta);
224}
225
226static struct sched_atom *
227get_new_event(struct task_desc *task, u64 timestamp)
228{
229 struct sched_atom *event = calloc(1, sizeof(*event));
230 unsigned long idx = task->nr_events;
231 size_t size;
232
233 event->timestamp = timestamp;
234 event->nr = idx;
235
236 task->nr_events++;
237 size = sizeof(struct sched_atom *) * task->nr_events;
238 task->atoms = realloc(task->atoms, size);
239 BUG_ON(!task->atoms);
240
241 task->atoms[idx] = event;
242
243 return event;
244}
245
246static struct sched_atom *last_event(struct task_desc *task)
247{
248 if (!task->nr_events)
249 return NULL;
250
251 return task->atoms[task->nr_events - 1];
252}
253
254static void
255add_sched_event_run(struct task_desc *task, u64 timestamp, u64 duration)
256{
257 struct sched_atom *event, *curr_event = last_event(task);
258
259 /*
260 * optimize an existing RUN event by merging this one
261 * to it:
262 */
263 if (curr_event && curr_event->type == SCHED_EVENT_RUN) {
264 nr_run_events_optimized++;
265 curr_event->duration += duration;
266 return;
267 }
268
269 event = get_new_event(task, timestamp);
270
271 event->type = SCHED_EVENT_RUN;
272 event->duration = duration;
273
274 nr_run_events++;
275}
276
277static void
278add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
279 struct task_desc *wakee)
280{
281 struct sched_atom *event, *wakee_event;
282
283 event = get_new_event(task, timestamp);
284 event->type = SCHED_EVENT_WAKEUP;
285 event->wakee = wakee;
286
287 wakee_event = last_event(wakee);
288 if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) {
289 targetless_wakeups++;
290 return;
291 }
292 if (wakee_event->wait_sem) {
293 multitarget_wakeups++;
294 return;
295 }
296
297 wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem));
298 sem_init(wakee_event->wait_sem, 0, 0);
299 wakee_event->specific_wait = 1;
300 event->wait_sem = wakee_event->wait_sem;
301
302 nr_wakeup_events++;
303}
304
305static void
306add_sched_event_sleep(struct task_desc *task, u64 timestamp,
307 u64 task_state __used)
308{
309 struct sched_atom *event = get_new_event(task, timestamp);
310
311 event->type = SCHED_EVENT_SLEEP;
312
313 nr_sleep_events++;
314}
315
316static struct task_desc *register_pid(unsigned long pid, const char *comm)
317{
318 struct task_desc *task;
319
320 BUG_ON(pid >= MAX_PID);
321
322 task = pid_to_task[pid];
323
324 if (task)
325 return task;
326
327 task = calloc(1, sizeof(*task));
328 task->pid = pid;
329 task->nr = nr_tasks;
330 strcpy(task->comm, comm);
331 /*
332 * every task starts in sleeping state - this gets ignored
333 * if there's no wakeup pointing to this sleep state:
334 */
335 add_sched_event_sleep(task, 0, 0);
336
337 pid_to_task[pid] = task;
338 nr_tasks++;
339 tasks = realloc(tasks, nr_tasks*sizeof(struct task_task *));
340 BUG_ON(!tasks);
341 tasks[task->nr] = task;
342
343 if (verbose)
344 printf("registered task #%ld, PID %ld (%s)\n", nr_tasks, pid, comm);
345
346 return task;
347}
348
349
350static void print_task_traces(void)
351{
352 struct task_desc *task;
353 unsigned long i;
354
355 for (i = 0; i < nr_tasks; i++) {
356 task = tasks[i];
357 printf("task %6ld (%20s:%10ld), nr_events: %ld\n",
358 task->nr, task->comm, task->pid, task->nr_events);
359 }
360}
361
362static void add_cross_task_wakeups(void)
363{
364 struct task_desc *task1, *task2;
365 unsigned long i, j;
366
367 for (i = 0; i < nr_tasks; i++) {
368 task1 = tasks[i];
369 j = i + 1;
370 if (j == nr_tasks)
371 j = 0;
372 task2 = tasks[j];
373 add_sched_event_wakeup(task1, 0, task2);
374 }
375}
376
377static void
378process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
379{
380 int ret = 0;
381 u64 now;
382 long long delta;
383
384 now = get_nsecs();
385 delta = start_time + atom->timestamp - now;
386
387 switch (atom->type) {
388 case SCHED_EVENT_RUN:
389 burn_nsecs(atom->duration);
390 break;
391 case SCHED_EVENT_SLEEP:
392 if (atom->wait_sem)
393 ret = sem_wait(atom->wait_sem);
394 BUG_ON(ret);
395 break;
396 case SCHED_EVENT_WAKEUP:
397 if (atom->wait_sem)
398 ret = sem_post(atom->wait_sem);
399 BUG_ON(ret);
400 break;
401 default:
402 BUG_ON(1);
403 }
404}
405
406static u64 get_cpu_usage_nsec_parent(void)
407{
408 struct rusage ru;
409 u64 sum;
410 int err;
411
412 err = getrusage(RUSAGE_SELF, &ru);
413 BUG_ON(err);
414
415 sum = ru.ru_utime.tv_sec*1e9 + ru.ru_utime.tv_usec*1e3;
416 sum += ru.ru_stime.tv_sec*1e9 + ru.ru_stime.tv_usec*1e3;
417
418 return sum;
419}
420
421static u64 get_cpu_usage_nsec_self(void)
422{
423 char filename [] = "/proc/1234567890/sched";
424 unsigned long msecs, nsecs;
425 char *line = NULL;
426 u64 total = 0;
427 size_t len = 0;
428 ssize_t chars;
429 FILE *file;
430 int ret;
431
432 sprintf(filename, "/proc/%d/sched", getpid());
433 file = fopen(filename, "r");
434 BUG_ON(!file);
435
436 while ((chars = getline(&line, &len, file)) != -1) {
437 ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n",
438 &msecs, &nsecs);
439 if (ret == 2) {
440 total = msecs*1e6 + nsecs;
441 break;
442 }
443 }
444 if (line)
445 free(line);
446 fclose(file);
447
448 return total;
449}
450
451static void *thread_func(void *ctx)
452{
453 struct task_desc *this_task = ctx;
454 u64 cpu_usage_0, cpu_usage_1;
455 unsigned long i, ret;
456 char comm2[22];
457
458 sprintf(comm2, ":%s", this_task->comm);
459 prctl(PR_SET_NAME, comm2);
460
461again:
462 ret = sem_post(&this_task->ready_for_work);
463 BUG_ON(ret);
464 ret = pthread_mutex_lock(&start_work_mutex);
465 BUG_ON(ret);
466 ret = pthread_mutex_unlock(&start_work_mutex);
467 BUG_ON(ret);
468
469 cpu_usage_0 = get_cpu_usage_nsec_self();
470
471 for (i = 0; i < this_task->nr_events; i++) {
472 this_task->curr_event = i;
473 process_sched_event(this_task, this_task->atoms[i]);
474 }
475
476 cpu_usage_1 = get_cpu_usage_nsec_self();
477 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
478
479 ret = sem_post(&this_task->work_done_sem);
480 BUG_ON(ret);
481
482 ret = pthread_mutex_lock(&work_done_wait_mutex);
483 BUG_ON(ret);
484 ret = pthread_mutex_unlock(&work_done_wait_mutex);
485 BUG_ON(ret);
486
487 goto again;
488}
489
490static void create_tasks(void)
491{
492 struct task_desc *task;
493 pthread_attr_t attr;
494 unsigned long i;
495 int err;
496
497 err = pthread_attr_init(&attr);
498 BUG_ON(err);
499 err = pthread_attr_setstacksize(&attr, (size_t)(16*1024));
500 BUG_ON(err);
501 err = pthread_mutex_lock(&start_work_mutex);
502 BUG_ON(err);
503 err = pthread_mutex_lock(&work_done_wait_mutex);
504 BUG_ON(err);
505 for (i = 0; i < nr_tasks; i++) {
506 task = tasks[i];
507 sem_init(&task->sleep_sem, 0, 0);
508 sem_init(&task->ready_for_work, 0, 0);
509 sem_init(&task->work_done_sem, 0, 0);
510 task->curr_event = 0;
511 err = pthread_create(&task->thread, &attr, thread_func, task);
512 BUG_ON(err);
513 }
514}
515
516static void wait_for_tasks(void)
517{
518 u64 cpu_usage_0, cpu_usage_1;
519 struct task_desc *task;
520 unsigned long i, ret;
521
522 start_time = get_nsecs();
523 cpu_usage = 0;
524 pthread_mutex_unlock(&work_done_wait_mutex);
525
526 for (i = 0; i < nr_tasks; i++) {
527 task = tasks[i];
528 ret = sem_wait(&task->ready_for_work);
529 BUG_ON(ret);
530 sem_init(&task->ready_for_work, 0, 0);
531 }
532 ret = pthread_mutex_lock(&work_done_wait_mutex);
533 BUG_ON(ret);
534
535 cpu_usage_0 = get_cpu_usage_nsec_parent();
536
537 pthread_mutex_unlock(&start_work_mutex);
538
539 for (i = 0; i < nr_tasks; i++) {
540 task = tasks[i];
541 ret = sem_wait(&task->work_done_sem);
542 BUG_ON(ret);
543 sem_init(&task->work_done_sem, 0, 0);
544 cpu_usage += task->cpu_usage;
545 task->cpu_usage = 0;
546 }
547
548 cpu_usage_1 = get_cpu_usage_nsec_parent();
549 if (!runavg_cpu_usage)
550 runavg_cpu_usage = cpu_usage;
551 runavg_cpu_usage = (runavg_cpu_usage*9 + cpu_usage)/10;
552
553 parent_cpu_usage = cpu_usage_1 - cpu_usage_0;
554 if (!runavg_parent_cpu_usage)
555 runavg_parent_cpu_usage = parent_cpu_usage;
556 runavg_parent_cpu_usage = (runavg_parent_cpu_usage*9 +
557 parent_cpu_usage)/10;
558
559 ret = pthread_mutex_lock(&start_work_mutex);
560 BUG_ON(ret);
561
562 for (i = 0; i < nr_tasks; i++) {
563 task = tasks[i];
564 sem_init(&task->sleep_sem, 0, 0);
565 task->curr_event = 0;
566 }
567}
568
569static void run_one_test(void)
570{
571 u64 T0, T1, delta, avg_delta, fluct, std_dev;
572
573 T0 = get_nsecs();
574 wait_for_tasks();
575 T1 = get_nsecs();
576
577 delta = T1 - T0;
578 sum_runtime += delta;
579 nr_runs++;
580
581 avg_delta = sum_runtime / nr_runs;
582 if (delta < avg_delta)
583 fluct = avg_delta - delta;
584 else
585 fluct = delta - avg_delta;
586 sum_fluct += fluct;
587 std_dev = sum_fluct / nr_runs / sqrt(nr_runs);
588 if (!run_avg)
589 run_avg = delta;
590 run_avg = (run_avg*9 + delta)/10;
591
592 printf("#%-3ld: %0.3f, ",
593 nr_runs, (double)delta/1000000.0);
594
595 printf("ravg: %0.2f, ",
596 (double)run_avg/1e6);
597
598 printf("cpu: %0.2f / %0.2f",
599 (double)cpu_usage/1e6, (double)runavg_cpu_usage/1e6);
600
601#if 0
602 /*
603 * rusage statistics done by the parent, these are less
604 * accurate than the sum_exec_runtime based statistics:
605 */
606 printf(" [%0.2f / %0.2f]",
607 (double)parent_cpu_usage/1e6,
608 (double)runavg_parent_cpu_usage/1e6);
609#endif
610
611 printf("\n");
612
613 if (nr_sleep_corrections)
614 printf(" (%ld sleep corrections)\n", nr_sleep_corrections);
615 nr_sleep_corrections = 0;
616}
617
618static void test_calibrations(void)
619{
620 u64 T0, T1;
621
622 T0 = get_nsecs();
623 burn_nsecs(1e6);
624 T1 = get_nsecs();
625
626 printf("the run test took %Ld nsecs\n", T1-T0);
627
628 T0 = get_nsecs();
629 sleep_nsecs(1e6);
630 T1 = get_nsecs();
631
632 printf("the sleep test took %Ld nsecs\n", T1-T0);
633}
634
635static int
636process_comm_event(event_t *event, unsigned long offset, unsigned long head)
637{
638 struct thread *thread;
639
640 thread = threads__findnew(event->comm.pid, &threads, &last_match);
641
642 dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
643 (void *)(offset + head),
644 (void *)(long)(event->header.size),
645 event->comm.comm, event->comm.pid);
646
647 if (thread == NULL ||
648 thread__set_comm(thread, event->comm.comm)) {
649 dump_printf("problem processing perf_event_comm, skipping event.\n");
650 return -1;
651 }
652 total_comm++;
653
654 return 0;
655}
656
657
658struct raw_event_sample {
659 u32 size;
660 char data[0];
661};
662
663#define FILL_FIELD(ptr, field, event, data) \
664 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
665
666#define FILL_ARRAY(ptr, array, event, data) \
667do { \
668 void *__array = raw_field_ptr(event, #array, data); \
669 memcpy(ptr.array, __array, sizeof(ptr.array)); \
670} while(0)
671
672#define FILL_COMMON_FIELDS(ptr, event, data) \
673do { \
674 FILL_FIELD(ptr, common_type, event, data); \
675 FILL_FIELD(ptr, common_flags, event, data); \
676 FILL_FIELD(ptr, common_preempt_count, event, data); \
677 FILL_FIELD(ptr, common_pid, event, data); \
678 FILL_FIELD(ptr, common_tgid, event, data); \
679} while (0)
680
681
682
683struct trace_switch_event {
684 u32 size;
685
686 u16 common_type;
687 u8 common_flags;
688 u8 common_preempt_count;
689 u32 common_pid;
690 u32 common_tgid;
691
692 char prev_comm[16];
693 u32 prev_pid;
694 u32 prev_prio;
695 u64 prev_state;
696 char next_comm[16];
697 u32 next_pid;
698 u32 next_prio;
699};
700
701struct trace_runtime_event {
702 u32 size;
703
704 u16 common_type;
705 u8 common_flags;
706 u8 common_preempt_count;
707 u32 common_pid;
708 u32 common_tgid;
709
710 char comm[16];
711 u32 pid;
712 u64 runtime;
713 u64 vruntime;
714};
715
716struct trace_wakeup_event {
717 u32 size;
718
719 u16 common_type;
720 u8 common_flags;
721 u8 common_preempt_count;
722 u32 common_pid;
723 u32 common_tgid;
724
725 char comm[16];
726 u32 pid;
727
728 u32 prio;
729 u32 success;
730 u32 cpu;
731};
732
733struct trace_fork_event {
734 u32 size;
735
736 u16 common_type;
737 u8 common_flags;
738 u8 common_preempt_count;
739 u32 common_pid;
740 u32 common_tgid;
741
742 char parent_comm[16];
743 u32 parent_pid;
744 char child_comm[16];
745 u32 child_pid;
746};
747
748struct trace_sched_handler {
749 void (*switch_event)(struct trace_switch_event *,
750 struct event *,
751 int cpu,
752 u64 timestamp,
753 struct thread *thread);
754
755 void (*runtime_event)(struct trace_runtime_event *,
756 struct event *,
757 int cpu,
758 u64 timestamp,
759 struct thread *thread);
760
761 void (*wakeup_event)(struct trace_wakeup_event *,
762 struct event *,
763 int cpu,
764 u64 timestamp,
765 struct thread *thread);
766
767 void (*fork_event)(struct trace_fork_event *,
768 struct event *,
769 int cpu,
770 u64 timestamp,
771 struct thread *thread);
772};
773
774
775static void
776replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
777 struct event *event,
778 int cpu __used,
779 u64 timestamp __used,
780 struct thread *thread __used)
781{
782 struct task_desc *waker, *wakee;
783
784 if (verbose) {
785 printf("sched_wakeup event %p\n", event);
786
787 printf(" ... pid %d woke up %s/%d\n",
788 wakeup_event->common_pid,
789 wakeup_event->comm,
790 wakeup_event->pid);
791 }
792
793 waker = register_pid(wakeup_event->common_pid, "<unknown>");
794 wakee = register_pid(wakeup_event->pid, wakeup_event->comm);
795
796 add_sched_event_wakeup(waker, timestamp, wakee);
797}
798
799static u64 cpu_last_switched[MAX_CPUS];
800
801static void
802replay_switch_event(struct trace_switch_event *switch_event,
803 struct event *event,
804 int cpu,
805 u64 timestamp,
806 struct thread *thread __used)
807{
808 struct task_desc *prev, *next;
809 u64 timestamp0;
810 s64 delta;
811
812 if (verbose)
813 printf("sched_switch event %p\n", event);
814
815 if (cpu >= MAX_CPUS || cpu < 0)
816 return;
817
818 timestamp0 = cpu_last_switched[cpu];
819 if (timestamp0)
820 delta = timestamp - timestamp0;
821 else
822 delta = 0;
823
824 if (delta < 0)
825 die("hm, delta: %Ld < 0 ?\n", delta);
826
827 if (verbose) {
828 printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n",
829 switch_event->prev_comm, switch_event->prev_pid,
830 switch_event->next_comm, switch_event->next_pid,
831 delta);
832 }
833
834 prev = register_pid(switch_event->prev_pid, switch_event->prev_comm);
835 next = register_pid(switch_event->next_pid, switch_event->next_comm);
836
837 cpu_last_switched[cpu] = timestamp;
838
839 add_sched_event_run(prev, timestamp, delta);
840 add_sched_event_sleep(prev, timestamp, switch_event->prev_state);
841}
842
843
844static void
845replay_fork_event(struct trace_fork_event *fork_event,
846 struct event *event,
847 int cpu __used,
848 u64 timestamp __used,
849 struct thread *thread __used)
850{
851 if (verbose) {
852 printf("sched_fork event %p\n", event);
853 printf("... parent: %s/%d\n", fork_event->parent_comm, fork_event->parent_pid);
854 printf("... child: %s/%d\n", fork_event->child_comm, fork_event->child_pid);
855 }
856 register_pid(fork_event->parent_pid, fork_event->parent_comm);
857 register_pid(fork_event->child_pid, fork_event->child_comm);
858}
859
860static struct trace_sched_handler replay_ops = {
861 .wakeup_event = replay_wakeup_event,
862 .switch_event = replay_switch_event,
863 .fork_event = replay_fork_event,
864};
865
866struct sort_dimension {
867 const char *name;
868 sort_fn_t cmp;
869 struct list_head list;
870};
871
872static LIST_HEAD(cmp_pid);
873
874static int
875thread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r)
876{
877 struct sort_dimension *sort;
878 int ret = 0;
879
880 BUG_ON(list_empty(list));
881
882 list_for_each_entry(sort, list, list) {
883 ret = sort->cmp(l, r);
884 if (ret)
885 return ret;
886 }
887
888 return ret;
889}
890
891static struct work_atoms *
892thread_atoms_search(struct rb_root *root, struct thread *thread,
893 struct list_head *sort_list)
894{
895 struct rb_node *node = root->rb_node;
896 struct work_atoms key = { .thread = thread };
897
898 while (node) {
899 struct work_atoms *atoms;
900 int cmp;
901
902 atoms = container_of(node, struct work_atoms, node);
903
904 cmp = thread_lat_cmp(sort_list, &key, atoms);
905 if (cmp > 0)
906 node = node->rb_left;
907 else if (cmp < 0)
908 node = node->rb_right;
909 else {
910 BUG_ON(thread != atoms->thread);
911 return atoms;
912 }
913 }
914 return NULL;
915}
916
917static void
918__thread_latency_insert(struct rb_root *root, struct work_atoms *data,
919 struct list_head *sort_list)
920{
921 struct rb_node **new = &(root->rb_node), *parent = NULL;
922
923 while (*new) {
924 struct work_atoms *this;
925 int cmp;
926
927 this = container_of(*new, struct work_atoms, node);
928 parent = *new;
929
930 cmp = thread_lat_cmp(sort_list, data, this);
931
932 if (cmp > 0)
933 new = &((*new)->rb_left);
934 else
935 new = &((*new)->rb_right);
936 }
937
938 rb_link_node(&data->node, parent, new);
939 rb_insert_color(&data->node, root);
940}
941
942static void thread_atoms_insert(struct thread *thread)
943{
944 struct work_atoms *atoms;
945
946 atoms = calloc(sizeof(*atoms), 1);
947 if (!atoms)
948 die("No memory");
949
950 atoms->thread = thread;
951 INIT_LIST_HEAD(&atoms->work_list);
952 __thread_latency_insert(&atom_root, atoms, &cmp_pid);
953}
954
955static void
956latency_fork_event(struct trace_fork_event *fork_event __used,
957 struct event *event __used,
958 int cpu __used,
959 u64 timestamp __used,
960 struct thread *thread __used)
961{
962 /* should insert the newcomer */
963}
964
965__used
966static char sched_out_state(struct trace_switch_event *switch_event)
967{
968 const char *str = TASK_STATE_TO_CHAR_STR;
969
970 return str[switch_event->prev_state];
971}
972
973static void
974add_sched_out_event(struct work_atoms *atoms,
975 char run_state,
976 u64 timestamp)
977{
978 struct work_atom *atom;
979
980 atom = calloc(sizeof(*atom), 1);
981 if (!atom)
982 die("Non memory");
983
984 atom->sched_out_time = timestamp;
985
986 if (run_state == 'R') {
987 atom->state = THREAD_WAIT_CPU;
988 atom->wake_up_time = atom->sched_out_time;
989 }
990
991 list_add_tail(&atom->list, &atoms->work_list);
992}
993
994static void
995add_runtime_event(struct work_atoms *atoms, u64 delta, u64 timestamp __used)
996{
997 struct work_atom *atom;
998
999 BUG_ON(list_empty(&atoms->work_list));
1000
1001 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1002
1003 atom->runtime += delta;
1004 atoms->total_runtime += delta;
1005}
1006
1007static void
1008add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1009{
1010 struct work_atom *atom;
1011 u64 delta;
1012
1013 if (list_empty(&atoms->work_list))
1014 return;
1015
1016 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1017
1018 if (atom->state != THREAD_WAIT_CPU)
1019 return;
1020
1021 if (timestamp < atom->wake_up_time) {
1022 atom->state = THREAD_IGNORE;
1023 return;
1024 }
1025
1026 atom->state = THREAD_SCHED_IN;
1027 atom->sched_in_time = timestamp;
1028
1029 delta = atom->sched_in_time - atom->wake_up_time;
1030 atoms->total_lat += delta;
1031 if (delta > atoms->max_lat)
1032 atoms->max_lat = delta;
1033 atoms->nb_atoms++;
1034}
1035
1036static void
1037latency_switch_event(struct trace_switch_event *switch_event,
1038 struct event *event __used,
1039 int cpu,
1040 u64 timestamp,
1041 struct thread *thread __used)
1042{
1043 struct work_atoms *out_events, *in_events;
1044 struct thread *sched_out, *sched_in;
1045 u64 timestamp0;
1046 s64 delta;
1047
1048 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1049
1050 timestamp0 = cpu_last_switched[cpu];
1051 cpu_last_switched[cpu] = timestamp;
1052 if (timestamp0)
1053 delta = timestamp - timestamp0;
1054 else
1055 delta = 0;
1056
1057 if (delta < 0)
1058 die("hm, delta: %Ld < 0 ?\n", delta);
1059
1060
1061 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match);
1062 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match);
1063
1064 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1065 if (!out_events) {
1066 thread_atoms_insert(sched_out);
1067 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1068 if (!out_events)
1069 die("out-event: Internal tree error");
1070 }
1071 add_sched_out_event(out_events, sched_out_state(switch_event), timestamp);
1072
1073 in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid);
1074 if (!in_events) {
1075 thread_atoms_insert(sched_in);
1076 in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid);
1077 if (!in_events)
1078 die("in-event: Internal tree error");
1079 /*
1080 * Take came in we have not heard about yet,
1081 * add in an initial atom in runnable state:
1082 */
1083 add_sched_out_event(in_events, 'R', timestamp);
1084 }
1085 add_sched_in_event(in_events, timestamp);
1086}
1087
1088static void
1089latency_runtime_event(struct trace_runtime_event *runtime_event,
1090 struct event *event __used,
1091 int cpu,
1092 u64 timestamp,
1093 struct thread *this_thread __used)
1094{
1095 struct work_atoms *atoms;
1096 struct thread *thread;
1097
1098 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1099
1100 thread = threads__findnew(runtime_event->pid, &threads, &last_match);
1101 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1102 if (!atoms) {
1103 thread_atoms_insert(thread);
1104 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1105 if (!atoms)
1106 die("in-event: Internal tree error");
1107 add_sched_out_event(atoms, 'R', timestamp);
1108 }
1109
1110 add_runtime_event(atoms, runtime_event->runtime, timestamp);
1111}
1112
1113static void
1114latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1115 struct event *__event __used,
1116 int cpu __used,
1117 u64 timestamp,
1118 struct thread *thread __used)
1119{
1120 struct work_atoms *atoms;
1121 struct work_atom *atom;
1122 struct thread *wakee;
1123
1124 /* Note for later, it may be interesting to observe the failing cases */
1125 if (!wakeup_event->success)
1126 return;
1127
1128 wakee = threads__findnew(wakeup_event->pid, &threads, &last_match);
1129 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1130 if (!atoms) {
1131 thread_atoms_insert(wakee);
1132 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1133 if (!atoms)
1134 die("wakeup-event: Internal tree error");
1135 add_sched_out_event(atoms, 'S', timestamp);
1136 }
1137
1138 BUG_ON(list_empty(&atoms->work_list));
1139
1140 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1141
1142 if (atom->state != THREAD_SLEEPING)
1143 nr_state_machine_bugs++;
1144
1145 nr_timestamps++;
1146 if (atom->sched_out_time > timestamp) {
1147 nr_unordered_timestamps++;
1148 return;
1149 }
1150
1151 atom->state = THREAD_WAIT_CPU;
1152 atom->wake_up_time = timestamp;
1153}
1154
1155static struct trace_sched_handler lat_ops = {
1156 .wakeup_event = latency_wakeup_event,
1157 .switch_event = latency_switch_event,
1158 .runtime_event = latency_runtime_event,
1159 .fork_event = latency_fork_event,
1160};
1161
1162static void output_lat_thread(struct work_atoms *work_list)
1163{
1164 int i;
1165 int ret;
1166 u64 avg;
1167
1168 if (!work_list->nb_atoms)
1169 return;
1170 /*
1171 * Ignore idle threads:
1172 */
1173 if (!strcmp(work_list->thread->comm, "swapper"))
1174 return;
1175
1176 all_runtime += work_list->total_runtime;
1177 all_count += work_list->nb_atoms;
1178
1179 ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid);
1180
1181 for (i = 0; i < 24 - ret; i++)
1182 printf(" ");
1183
1184 avg = work_list->total_lat / work_list->nb_atoms;
1185
1186 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms |\n",
1187 (double)work_list->total_runtime / 1e6,
1188 work_list->nb_atoms, (double)avg / 1e6,
1189 (double)work_list->max_lat / 1e6);
1190}
1191
1192static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
1193{
1194 if (l->thread->pid < r->thread->pid)
1195 return -1;
1196 if (l->thread->pid > r->thread->pid)
1197 return 1;
1198
1199 return 0;
1200}
1201
1202static struct sort_dimension pid_sort_dimension = {
1203 .name = "pid",
1204 .cmp = pid_cmp,
1205};
1206
1207static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
1208{
1209 u64 avgl, avgr;
1210
1211 if (!l->nb_atoms)
1212 return -1;
1213
1214 if (!r->nb_atoms)
1215 return 1;
1216
1217 avgl = l->total_lat / l->nb_atoms;
1218 avgr = r->total_lat / r->nb_atoms;
1219
1220 if (avgl < avgr)
1221 return -1;
1222 if (avgl > avgr)
1223 return 1;
1224
1225 return 0;
1226}
1227
1228static struct sort_dimension avg_sort_dimension = {
1229 .name = "avg",
1230 .cmp = avg_cmp,
1231};
1232
1233static int max_cmp(struct work_atoms *l, struct work_atoms *r)
1234{
1235 if (l->max_lat < r->max_lat)
1236 return -1;
1237 if (l->max_lat > r->max_lat)
1238 return 1;
1239
1240 return 0;
1241}
1242
1243static struct sort_dimension max_sort_dimension = {
1244 .name = "max",
1245 .cmp = max_cmp,
1246};
1247
1248static int switch_cmp(struct work_atoms *l, struct work_atoms *r)
1249{
1250 if (l->nb_atoms < r->nb_atoms)
1251 return -1;
1252 if (l->nb_atoms > r->nb_atoms)
1253 return 1;
1254
1255 return 0;
1256}
1257
1258static struct sort_dimension switch_sort_dimension = {
1259 .name = "switch",
1260 .cmp = switch_cmp,
1261};
1262
1263static int runtime_cmp(struct work_atoms *l, struct work_atoms *r)
1264{
1265 if (l->total_runtime < r->total_runtime)
1266 return -1;
1267 if (l->total_runtime > r->total_runtime)
1268 return 1;
1269
1270 return 0;
1271}
1272
1273static struct sort_dimension runtime_sort_dimension = {
1274 .name = "runtime",
1275 .cmp = runtime_cmp,
1276};
1277
1278static struct sort_dimension *available_sorts[] = {
1279 &pid_sort_dimension,
1280 &avg_sort_dimension,
1281 &max_sort_dimension,
1282 &switch_sort_dimension,
1283 &runtime_sort_dimension,
1284};
1285
1286#define NB_AVAILABLE_SORTS (int)(sizeof(available_sorts) / sizeof(struct sort_dimension *))
1287
1288static LIST_HEAD(sort_list);
1289
1290static int sort_dimension__add(char *tok, struct list_head *list)
1291{
1292 int i;
1293
1294 for (i = 0; i < NB_AVAILABLE_SORTS; i++) {
1295 if (!strcmp(available_sorts[i]->name, tok)) {
1296 list_add_tail(&available_sorts[i]->list, list);
1297
1298 return 0;
1299 }
1300 }
1301
1302 return -1;
1303}
1304
1305static void setup_sorting(void);
1306
1307static void sort_lat(void)
1308{
1309 struct rb_node *node;
1310
1311 for (;;) {
1312 struct work_atoms *data;
1313 node = rb_first(&atom_root);
1314 if (!node)
1315 break;
1316
1317 rb_erase(node, &atom_root);
1318 data = rb_entry(node, struct work_atoms, node);
1319 __thread_latency_insert(&sorted_atom_root, data, &sort_list);
1320 }
1321}
1322
1323static struct trace_sched_handler *trace_handler;
1324
1325static void
1326process_sched_wakeup_event(struct raw_event_sample *raw,
1327 struct event *event,
1328 int cpu __used,
1329 u64 timestamp __used,
1330 struct thread *thread __used)
1331{
1332 struct trace_wakeup_event wakeup_event;
1333
1334 FILL_COMMON_FIELDS(wakeup_event, event, raw->data);
1335
1336 FILL_ARRAY(wakeup_event, comm, event, raw->data);
1337 FILL_FIELD(wakeup_event, pid, event, raw->data);
1338 FILL_FIELD(wakeup_event, prio, event, raw->data);
1339 FILL_FIELD(wakeup_event, success, event, raw->data);
1340 FILL_FIELD(wakeup_event, cpu, event, raw->data);
1341
1342 if (trace_handler->wakeup_event)
1343 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread);
1344}
1345
1346/*
1347 * Track the current task - that way we can know whether there's any
1348 * weird events, such as a task being switched away that is not current.
1349 */
1350static int max_cpu;
1351
1352static u32 curr_pid[MAX_CPUS] = { [0 ... MAX_CPUS-1] = -1 };
1353
1354static struct thread *curr_thread[MAX_CPUS];
1355
1356static char next_shortname1 = 'A';
1357static char next_shortname2 = '0';
1358
1359static void
1360map_switch_event(struct trace_switch_event *switch_event,
1361 struct event *event __used,
1362 int this_cpu,
1363 u64 timestamp,
1364 struct thread *thread __used)
1365{
1366 struct thread *sched_out, *sched_in;
1367 int new_shortname;
1368 u64 timestamp0;
1369 s64 delta;
1370 int cpu;
1371
1372 BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0);
1373
1374 if (this_cpu > max_cpu)
1375 max_cpu = this_cpu;
1376
1377 timestamp0 = cpu_last_switched[this_cpu];
1378 cpu_last_switched[this_cpu] = timestamp;
1379 if (timestamp0)
1380 delta = timestamp - timestamp0;
1381 else
1382 delta = 0;
1383
1384 if (delta < 0)
1385 die("hm, delta: %Ld < 0 ?\n", delta);
1386
1387
1388 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match);
1389 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match);
1390
1391 curr_thread[this_cpu] = sched_in;
1392
1393 printf(" ");
1394
1395 new_shortname = 0;
1396 if (!sched_in->shortname[0]) {
1397 sched_in->shortname[0] = next_shortname1;
1398 sched_in->shortname[1] = next_shortname2;
1399
1400 if (next_shortname1 < 'Z') {
1401 next_shortname1++;
1402 } else {
1403 next_shortname1='A';
1404 if (next_shortname2 < '9') {
1405 next_shortname2++;
1406 } else {
1407 next_shortname2='0';
1408 }
1409 }
1410 new_shortname = 1;
1411 }
1412
1413 for (cpu = 0; cpu <= max_cpu; cpu++) {
1414 if (cpu != this_cpu)
1415 printf(" ");
1416 else
1417 printf("*");
1418
1419 if (curr_thread[cpu]) {
1420 if (curr_thread[cpu]->pid)
1421 printf("%2s ", curr_thread[cpu]->shortname);
1422 else
1423 printf(". ");
1424 } else
1425 printf(" ");
1426 }
1427
1428 printf(" %12.6f secs ", (double)timestamp/1e9);
1429 if (new_shortname) {
1430 printf("%s => %s:%d\n",
1431 sched_in->shortname, sched_in->comm, sched_in->pid);
1432 } else {
1433 printf("\n");
1434 }
1435}
1436
1437
1438static void
1439process_sched_switch_event(struct raw_event_sample *raw,
1440 struct event *event,
1441 int this_cpu,
1442 u64 timestamp __used,
1443 struct thread *thread __used)
1444{
1445 struct trace_switch_event switch_event;
1446
1447 FILL_COMMON_FIELDS(switch_event, event, raw->data);
1448
1449 FILL_ARRAY(switch_event, prev_comm, event, raw->data);
1450 FILL_FIELD(switch_event, prev_pid, event, raw->data);
1451 FILL_FIELD(switch_event, prev_prio, event, raw->data);
1452 FILL_FIELD(switch_event, prev_state, event, raw->data);
1453 FILL_ARRAY(switch_event, next_comm, event, raw->data);
1454 FILL_FIELD(switch_event, next_pid, event, raw->data);
1455 FILL_FIELD(switch_event, next_prio, event, raw->data);
1456
1457 if (curr_pid[this_cpu] != (u32)-1) {
1458 /*
1459 * Are we trying to switch away a PID that is
1460 * not current?
1461 */
1462 if (curr_pid[this_cpu] != switch_event.prev_pid)
1463 nr_context_switch_bugs++;
1464 }
1465 if (trace_handler->switch_event)
1466 trace_handler->switch_event(&switch_event, event, this_cpu, timestamp, thread);
1467
1468 curr_pid[this_cpu] = switch_event.next_pid;
1469}
1470
1471static void
1472process_sched_runtime_event(struct raw_event_sample *raw,
1473 struct event *event,
1474 int cpu __used,
1475 u64 timestamp __used,
1476 struct thread *thread __used)
1477{
1478 struct trace_runtime_event runtime_event;
1479
1480 FILL_ARRAY(runtime_event, comm, event, raw->data);
1481 FILL_FIELD(runtime_event, pid, event, raw->data);
1482 FILL_FIELD(runtime_event, runtime, event, raw->data);
1483 FILL_FIELD(runtime_event, vruntime, event, raw->data);
1484
1485 if (trace_handler->runtime_event)
1486 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread);
1487}
1488
1489static void
1490process_sched_fork_event(struct raw_event_sample *raw,
1491 struct event *event,
1492 int cpu __used,
1493 u64 timestamp __used,
1494 struct thread *thread __used)
1495{
1496 struct trace_fork_event fork_event;
1497
1498 FILL_COMMON_FIELDS(fork_event, event, raw->data);
1499
1500 FILL_ARRAY(fork_event, parent_comm, event, raw->data);
1501 FILL_FIELD(fork_event, parent_pid, event, raw->data);
1502 FILL_ARRAY(fork_event, child_comm, event, raw->data);
1503 FILL_FIELD(fork_event, child_pid, event, raw->data);
1504
1505 if (trace_handler->fork_event)
1506 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread);
1507}
1508
1509static void
1510process_sched_exit_event(struct event *event,
1511 int cpu __used,
1512 u64 timestamp __used,
1513 struct thread *thread __used)
1514{
1515 if (verbose)
1516 printf("sched_exit event %p\n", event);
1517}
1518
1519static void
1520process_raw_event(event_t *raw_event __used, void *more_data,
1521 int cpu, u64 timestamp, struct thread *thread)
1522{
1523 struct raw_event_sample *raw = more_data;
1524 struct event *event;
1525 int type;
1526
1527 type = trace_parse_common_type(raw->data);
1528 event = trace_find_event(type);
1529
1530 if (!strcmp(event->name, "sched_switch"))
1531 process_sched_switch_event(raw, event, cpu, timestamp, thread);
1532 if (!strcmp(event->name, "sched_stat_runtime"))
1533 process_sched_runtime_event(raw, event, cpu, timestamp, thread);
1534 if (!strcmp(event->name, "sched_wakeup"))
1535 process_sched_wakeup_event(raw, event, cpu, timestamp, thread);
1536 if (!strcmp(event->name, "sched_wakeup_new"))
1537 process_sched_wakeup_event(raw, event, cpu, timestamp, thread);
1538 if (!strcmp(event->name, "sched_process_fork"))
1539 process_sched_fork_event(raw, event, cpu, timestamp, thread);
1540 if (!strcmp(event->name, "sched_process_exit"))
1541 process_sched_exit_event(event, cpu, timestamp, thread);
1542}
1543
1544static int
1545process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1546{
1547 char level;
1548 int show = 0;
1549 struct dso *dso = NULL;
1550 struct thread *thread;
1551 u64 ip = event->ip.ip;
1552 u64 timestamp = -1;
1553 u32 cpu = -1;
1554 u64 period = 1;
1555 void *more_data = event->ip.__more_data;
1556 int cpumode;
1557
1558 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1559
1560 if (sample_type & PERF_SAMPLE_TIME) {
1561 timestamp = *(u64 *)more_data;
1562 more_data += sizeof(u64);
1563 }
1564
1565 if (sample_type & PERF_SAMPLE_CPU) {
1566 cpu = *(u32 *)more_data;
1567 more_data += sizeof(u32);
1568 more_data += sizeof(u32); /* reserved */
1569 }
1570
1571 if (sample_type & PERF_SAMPLE_PERIOD) {
1572 period = *(u64 *)more_data;
1573 more_data += sizeof(u64);
1574 }
1575
1576 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1577 (void *)(offset + head),
1578 (void *)(long)(event->header.size),
1579 event->header.misc,
1580 event->ip.pid, event->ip.tid,
1581 (void *)(long)ip,
1582 (long long)period);
1583
1584 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1585
1586 if (thread == NULL) {
1587 eprintf("problem processing %d event, skipping it.\n",
1588 event->header.type);
1589 return -1;
1590 }
1591
1592 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1593
1594 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1595 show = SHOW_KERNEL;
1596 level = 'k';
1597
1598 dso = kernel_dso;
1599
1600 dump_printf(" ...... dso: %s\n", dso->name);
1601
1602 } else if (cpumode == PERF_RECORD_MISC_USER) {
1603
1604 show = SHOW_USER;
1605 level = '.';
1606
1607 } else {
1608 show = SHOW_HV;
1609 level = 'H';
1610
1611 dso = hypervisor_dso;
1612
1613 dump_printf(" ...... dso: [hypervisor]\n");
1614 }
1615
1616 if (sample_type & PERF_SAMPLE_RAW)
1617 process_raw_event(event, more_data, cpu, timestamp, thread);
1618
1619 return 0;
1620}
1621
1622static int
1623process_event(event_t *event, unsigned long offset, unsigned long head)
1624{
1625 trace_event(event);
1626
1627 nr_events++;
1628 switch (event->header.type) {
1629 case PERF_RECORD_MMAP:
1630 return 0;
1631 case PERF_RECORD_LOST:
1632 nr_lost_chunks++;
1633 nr_lost_events += event->lost.lost;
1634 return 0;
1635
1636 case PERF_RECORD_COMM:
1637 return process_comm_event(event, offset, head);
1638
1639 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
1640 return 0;
1641
1642 case PERF_RECORD_SAMPLE:
1643 return process_sample_event(event, offset, head);
1644
1645 case PERF_RECORD_MAX:
1646 default:
1647 return -1;
1648 }
1649
1650 return 0;
1651}
1652
1653static int read_events(void)
1654{
1655 int ret, rc = EXIT_FAILURE;
1656 unsigned long offset = 0;
1657 unsigned long head = 0;
1658 struct stat perf_stat;
1659 event_t *event;
1660 uint32_t size;
1661 char *buf;
1662
1663 trace_report();
1664 register_idle_thread(&threads, &last_match);
1665
1666 input = open(input_name, O_RDONLY);
1667 if (input < 0) {
1668 perror("failed to open file");
1669 exit(-1);
1670 }
1671
1672 ret = fstat(input, &perf_stat);
1673 if (ret < 0) {
1674 perror("failed to stat file");
1675 exit(-1);
1676 }
1677
1678 if (!perf_stat.st_size) {
1679 fprintf(stderr, "zero-sized file, nothing to do!\n");
1680 exit(0);
1681 }
1682 header = perf_header__read(input);
1683 head = header->data_offset;
1684 sample_type = perf_header__sample_type(header);
1685
1686 if (!(sample_type & PERF_SAMPLE_RAW))
1687 die("No trace sample to read. Did you call perf record "
1688 "without -R?");
1689
1690 if (load_kernel() < 0) {
1691 perror("failed to load kernel symbols");
1692 return EXIT_FAILURE;
1693 }
1694
1695remap:
1696 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1697 MAP_SHARED, input, offset);
1698 if (buf == MAP_FAILED) {
1699 perror("failed to mmap file");
1700 exit(-1);
1701 }
1702
1703more:
1704 event = (event_t *)(buf + head);
1705
1706 size = event->header.size;
1707 if (!size)
1708 size = 8;
1709
1710 if (head + event->header.size >= page_size * mmap_window) {
1711 unsigned long shift = page_size * (head / page_size);
1712 int res;
1713
1714 res = munmap(buf, page_size * mmap_window);
1715 assert(res == 0);
1716
1717 offset += shift;
1718 head -= shift;
1719 goto remap;
1720 }
1721
1722 size = event->header.size;
1723
1724
1725 if (!size || process_event(event, offset, head) < 0) {
1726
1727 /*
1728 * assume we lost track of the stream, check alignment, and
1729 * increment a single u64 in the hope to catch on again 'soon'.
1730 */
1731
1732 if (unlikely(head & 7))
1733 head &= ~7ULL;
1734
1735 size = 8;
1736 }
1737
1738 head += size;
1739
1740 if (offset + head < (unsigned long)perf_stat.st_size)
1741 goto more;
1742
1743 rc = EXIT_SUCCESS;
1744 close(input);
1745
1746 return rc;
1747}
1748
1749static void print_bad_events(void)
1750{
1751 if (nr_unordered_timestamps && nr_timestamps) {
1752 printf(" INFO: %.3f%% unordered timestamps (%ld out of %ld)\n",
1753 (double)nr_unordered_timestamps/(double)nr_timestamps*100.0,
1754 nr_unordered_timestamps, nr_timestamps);
1755 }
1756 if (nr_lost_events && nr_events) {
1757 printf(" INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n",
1758 (double)nr_lost_events/(double)nr_events*100.0,
1759 nr_lost_events, nr_events, nr_lost_chunks);
1760 }
1761 if (nr_state_machine_bugs && nr_timestamps) {
1762 printf(" INFO: %.3f%% state machine bugs (%ld out of %ld)",
1763 (double)nr_state_machine_bugs/(double)nr_timestamps*100.0,
1764 nr_state_machine_bugs, nr_timestamps);
1765 if (nr_lost_events)
1766 printf(" (due to lost events?)");
1767 printf("\n");
1768 }
1769 if (nr_context_switch_bugs && nr_timestamps) {
1770 printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)",
1771 (double)nr_context_switch_bugs/(double)nr_timestamps*100.0,
1772 nr_context_switch_bugs, nr_timestamps);
1773 if (nr_lost_events)
1774 printf(" (due to lost events?)");
1775 printf("\n");
1776 }
1777}
1778
1779static void __cmd_lat(void)
1780{
1781 struct rb_node *next;
1782
1783 setup_pager();
1784 read_events();
1785 sort_lat();
1786
1787 printf("\n -----------------------------------------------------------------------------------------\n");
1788 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n");
1789 printf(" -----------------------------------------------------------------------------------------\n");
1790
1791 next = rb_first(&sorted_atom_root);
1792
1793 while (next) {
1794 struct work_atoms *work_list;
1795
1796 work_list = rb_entry(next, struct work_atoms, node);
1797 output_lat_thread(work_list);
1798 next = rb_next(next);
1799 }
1800
1801 printf(" -----------------------------------------------------------------------------------------\n");
1802 printf(" TOTAL: |%11.3f ms |%9Ld |\n",
1803 (double)all_runtime/1e6, all_count);
1804
1805 printf(" ---------------------------------------------------\n");
1806
1807 print_bad_events();
1808 printf("\n");
1809
1810}
1811
1812static struct trace_sched_handler map_ops = {
1813 .wakeup_event = NULL,
1814 .switch_event = map_switch_event,
1815 .runtime_event = NULL,
1816 .fork_event = NULL,
1817};
1818
1819static void __cmd_map(void)
1820{
1821 max_cpu = sysconf(_SC_NPROCESSORS_CONF);
1822
1823 setup_pager();
1824 read_events();
1825 print_bad_events();
1826}
1827
1828static void __cmd_replay(void)
1829{
1830 unsigned long i;
1831
1832 calibrate_run_measurement_overhead();
1833 calibrate_sleep_measurement_overhead();
1834
1835 test_calibrations();
1836
1837 read_events();
1838
1839 printf("nr_run_events: %ld\n", nr_run_events);
1840 printf("nr_sleep_events: %ld\n", nr_sleep_events);
1841 printf("nr_wakeup_events: %ld\n", nr_wakeup_events);
1842
1843 if (targetless_wakeups)
1844 printf("target-less wakeups: %ld\n", targetless_wakeups);
1845 if (multitarget_wakeups)
1846 printf("multi-target wakeups: %ld\n", multitarget_wakeups);
1847 if (nr_run_events_optimized)
1848 printf("run atoms optimized: %ld\n",
1849 nr_run_events_optimized);
1850
1851 print_task_traces();
1852 add_cross_task_wakeups();
1853
1854 create_tasks();
1855 printf("------------------------------------------------------------\n");
1856 for (i = 0; i < replay_repeat; i++)
1857 run_one_test();
1858}
1859
1860
1861static const char * const sched_usage[] = {
1862 "perf sched [<options>] {record|latency|map|replay|trace}",
1863 NULL
1864};
1865
1866static const struct option sched_options[] = {
1867 OPT_STRING('i', "input", &input_name, "file",
1868 "input file name"),
1869 OPT_BOOLEAN('v', "verbose", &verbose,
1870 "be more verbose (show symbol address, etc)"),
1871 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1872 "dump raw trace in ASCII"),
1873 OPT_END()
1874};
1875
1876static const char * const latency_usage[] = {
1877 "perf sched latency [<options>]",
1878 NULL
1879};
1880
1881static const struct option latency_options[] = {
1882 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1883 "sort by key(s): runtime, switch, avg, max"),
1884 OPT_BOOLEAN('v', "verbose", &verbose,
1885 "be more verbose (show symbol address, etc)"),
1886 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1887 "dump raw trace in ASCII"),
1888 OPT_END()
1889};
1890
1891static const char * const replay_usage[] = {
1892 "perf sched replay [<options>]",
1893 NULL
1894};
1895
1896static const struct option replay_options[] = {
1897 OPT_INTEGER('r', "repeat", &replay_repeat,
1898 "repeat the workload replay N times (-1: infinite)"),
1899 OPT_BOOLEAN('v', "verbose", &verbose,
1900 "be more verbose (show symbol address, etc)"),
1901 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1902 "dump raw trace in ASCII"),
1903 OPT_END()
1904};
1905
1906static void setup_sorting(void)
1907{
1908 char *tmp, *tok, *str = strdup(sort_order);
1909
1910 for (tok = strtok_r(str, ", ", &tmp);
1911 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1912 if (sort_dimension__add(tok, &sort_list) < 0) {
1913 error("Unknown --sort key: `%s'", tok);
1914 usage_with_options(latency_usage, latency_options);
1915 }
1916 }
1917
1918 free(str);
1919
1920 sort_dimension__add((char *)"pid", &cmp_pid);
1921}
1922
1923static const char *record_args[] = {
1924 "record",
1925 "-a",
1926 "-R",
1927 "-M",
1928 "-f",
1929 "-m", "1024",
1930 "-c", "1",
1931 "-e", "sched:sched_switch:r",
1932 "-e", "sched:sched_stat_wait:r",
1933 "-e", "sched:sched_stat_sleep:r",
1934 "-e", "sched:sched_stat_iowait:r",
1935 "-e", "sched:sched_stat_runtime:r",
1936 "-e", "sched:sched_process_exit:r",
1937 "-e", "sched:sched_process_fork:r",
1938 "-e", "sched:sched_wakeup:r",
1939 "-e", "sched:sched_migrate_task:r",
1940};
1941
1942static int __cmd_record(int argc, const char **argv)
1943{
1944 unsigned int rec_argc, i, j;
1945 const char **rec_argv;
1946
1947 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1948 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1949
1950 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1951 rec_argv[i] = strdup(record_args[i]);
1952
1953 for (j = 1; j < (unsigned int)argc; j++, i++)
1954 rec_argv[i] = argv[j];
1955
1956 BUG_ON(i != rec_argc);
1957
1958 return cmd_record(i, rec_argv, NULL);
1959}
1960
1961int cmd_sched(int argc, const char **argv, const char *prefix __used)
1962{
1963 symbol__init();
1964 page_size = getpagesize();
1965
1966 argc = parse_options(argc, argv, sched_options, sched_usage,
1967 PARSE_OPT_STOP_AT_NON_OPTION);
1968 if (!argc)
1969 usage_with_options(sched_usage, sched_options);
1970
1971 if (!strncmp(argv[0], "rec", 3)) {
1972 return __cmd_record(argc, argv);
1973 } else if (!strncmp(argv[0], "lat", 3)) {
1974 trace_handler = &lat_ops;
1975 if (argc > 1) {
1976 argc = parse_options(argc, argv, latency_options, latency_usage, 0);
1977 if (argc)
1978 usage_with_options(latency_usage, latency_options);
1979 }
1980 setup_sorting();
1981 __cmd_lat();
1982 } else if (!strcmp(argv[0], "map")) {
1983 trace_handler = &map_ops;
1984 setup_sorting();
1985 __cmd_map();
1986 } else if (!strncmp(argv[0], "rep", 3)) {
1987 trace_handler = &replay_ops;
1988 if (argc) {
1989 argc = parse_options(argc, argv, replay_options, replay_usage, 0);
1990 if (argc)
1991 usage_with_options(replay_usage, replay_options);
1992 }
1993 __cmd_replay();
1994 } else if (!strcmp(argv[0], "trace")) {
1995 /*
1996 * Aliased to 'perf trace' for now:
1997 */
1998 return cmd_trace(argc, argv, prefix);
1999 } else {
2000 usage_with_options(sched_usage, sched_options);
2001 }
2002
2003 return 0;
2004}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 6d3eeac1ea25..e5f6ece65a13 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -32,6 +32,7 @@
32 * Wu Fengguang <fengguang.wu@intel.com> 32 * Wu Fengguang <fengguang.wu@intel.com>
33 * Mike Galbraith <efault@gmx.de> 33 * Mike Galbraith <efault@gmx.de>
34 * Paul Mackerras <paulus@samba.org> 34 * Paul Mackerras <paulus@samba.org>
35 * Jaswinder Singh Rajput <jaswinder@kernel.org>
35 * 36 *
36 * Released under the GPL v2. (and only v2, not any later version) 37 * Released under the GPL v2. (and only v2, not any later version)
37 */ 38 */
@@ -41,11 +42,13 @@
41#include "util/util.h" 42#include "util/util.h"
42#include "util/parse-options.h" 43#include "util/parse-options.h"
43#include "util/parse-events.h" 44#include "util/parse-events.h"
45#include "util/event.h"
46#include "util/debug.h"
44 47
45#include <sys/prctl.h> 48#include <sys/prctl.h>
46#include <math.h> 49#include <math.h>
47 50
48static struct perf_counter_attr default_attrs[MAX_COUNTERS] = { 51static struct perf_event_attr default_attrs[] = {
49 52
50 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 53 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
51 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES}, 54 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
@@ -60,79 +63,101 @@ static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
60}; 63};
61 64
62static int system_wide = 0; 65static int system_wide = 0;
66static unsigned int nr_cpus = 0;
67static int run_idx = 0;
68
69static int run_count = 1;
63static int inherit = 1; 70static int inherit = 1;
64static int verbose = 0; 71static int scale = 1;
72static int target_pid = -1;
73static int null_run = 0;
65 74
66static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 75static int fd[MAX_NR_CPUS][MAX_COUNTERS];
67 76
68static int target_pid = -1; 77static int event_scaled[MAX_COUNTERS];
69static int nr_cpus = 0;
70static unsigned int page_size;
71 78
72static int scale = 1; 79struct stats
73 80{
74static const unsigned int default_count[] = { 81 double n, mean, M2;
75 1000000,
76 1000000,
77 10000,
78 10000,
79 1000000,
80 10000,
81}; 82};
82 83
83#define MAX_RUN 100 84static void update_stats(struct stats *stats, u64 val)
84 85{
85static int run_count = 1; 86 double delta;
86static int run_idx = 0;
87
88static u64 event_res[MAX_RUN][MAX_COUNTERS][3];
89static u64 event_scaled[MAX_RUN][MAX_COUNTERS];
90
91//static u64 event_hist[MAX_RUN][MAX_COUNTERS][3];
92 87
88 stats->n++;
89 delta = val - stats->mean;
90 stats->mean += delta / stats->n;
91 stats->M2 += delta*(val - stats->mean);
92}
93 93
94static u64 runtime_nsecs[MAX_RUN]; 94static double avg_stats(struct stats *stats)
95static u64 walltime_nsecs[MAX_RUN]; 95{
96static u64 runtime_cycles[MAX_RUN]; 96 return stats->mean;
97}
97 98
98static u64 event_res_avg[MAX_COUNTERS][3]; 99/*
99static u64 event_res_noise[MAX_COUNTERS][3]; 100 * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
101 *
102 * (\Sum n_i^2) - ((\Sum n_i)^2)/n
103 * s^2 = -------------------------------
104 * n - 1
105 *
106 * http://en.wikipedia.org/wiki/Stddev
107 *
108 * The std dev of the mean is related to the std dev by:
109 *
110 * s
111 * s_mean = -------
112 * sqrt(n)
113 *
114 */
115static double stddev_stats(struct stats *stats)
116{
117 double variance = stats->M2 / (stats->n - 1);
118 double variance_mean = variance / stats->n;
100 119
101static u64 event_scaled_avg[MAX_COUNTERS]; 120 return sqrt(variance_mean);
121}
102 122
103static u64 runtime_nsecs_avg; 123struct stats event_res_stats[MAX_COUNTERS][3];
104static u64 runtime_nsecs_noise; 124struct stats runtime_nsecs_stats;
125struct stats walltime_nsecs_stats;
126struct stats runtime_cycles_stats;
105 127
106static u64 walltime_nsecs_avg; 128#define MATCH_EVENT(t, c, counter) \
107static u64 walltime_nsecs_noise; 129 (attrs[counter].type == PERF_TYPE_##t && \
130 attrs[counter].config == PERF_COUNT_##c)
108 131
109static u64 runtime_cycles_avg; 132#define ERR_PERF_OPEN \
110static u64 runtime_cycles_noise; 133"Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n"
111 134
112static void create_perf_stat_counter(int counter) 135static void create_perf_stat_counter(int counter, int pid)
113{ 136{
114 struct perf_counter_attr *attr = attrs + counter; 137 struct perf_event_attr *attr = attrs + counter;
115 138
116 if (scale) 139 if (scale)
117 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 140 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
118 PERF_FORMAT_TOTAL_TIME_RUNNING; 141 PERF_FORMAT_TOTAL_TIME_RUNNING;
119 142
120 if (system_wide) { 143 if (system_wide) {
121 int cpu; 144 unsigned int cpu;
122 for (cpu = 0; cpu < nr_cpus; cpu ++) {
123 fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
124 if (fd[cpu][counter] < 0 && verbose) {
125 printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[cpu][counter], strerror(errno));
126 }
127 }
128 } else {
129 attr->inherit = inherit;
130 attr->disabled = 1;
131 145
132 fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0); 146 for (cpu = 0; cpu < nr_cpus; cpu++) {
133 if (fd[0][counter] < 0 && verbose) { 147 fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0);
134 printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[0][counter], strerror(errno)); 148 if (fd[cpu][counter] < 0 && verbose)
149 fprintf(stderr, ERR_PERF_OPEN, counter,
150 fd[cpu][counter], strerror(errno));
135 } 151 }
152 } else {
153 attr->inherit = inherit;
154 attr->disabled = 1;
155 attr->enable_on_exec = 1;
156
157 fd[0][counter] = sys_perf_event_open(attr, pid, -1, -1, 0);
158 if (fd[0][counter] < 0 && verbose)
159 fprintf(stderr, ERR_PERF_OPEN, counter,
160 fd[0][counter], strerror(errno));
136 } 161 }
137} 162}
138 163
@@ -141,13 +166,8 @@ static void create_perf_stat_counter(int counter)
141 */ 166 */
142static inline int nsec_counter(int counter) 167static inline int nsec_counter(int counter)
143{ 168{
144 if (attrs[counter].type != PERF_TYPE_SOFTWARE) 169 if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) ||
145 return 0; 170 MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
146
147 if (attrs[counter].config == PERF_COUNT_SW_CPU_CLOCK)
148 return 1;
149
150 if (attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
151 return 1; 171 return 1;
152 172
153 return 0; 173 return 0;
@@ -158,22 +178,22 @@ static inline int nsec_counter(int counter)
158 */ 178 */
159static void read_counter(int counter) 179static void read_counter(int counter)
160{ 180{
161 u64 *count, single_count[3]; 181 u64 count[3], single_count[3];
162 ssize_t res; 182 unsigned int cpu;
163 int cpu, nv; 183 size_t res, nv;
164 int scaled; 184 int scaled;
165 185 int i;
166 count = event_res[run_idx][counter];
167 186
168 count[0] = count[1] = count[2] = 0; 187 count[0] = count[1] = count[2] = 0;
169 188
170 nv = scale ? 3 : 1; 189 nv = scale ? 3 : 1;
171 for (cpu = 0; cpu < nr_cpus; cpu ++) { 190 for (cpu = 0; cpu < nr_cpus; cpu++) {
172 if (fd[cpu][counter] < 0) 191 if (fd[cpu][counter] < 0)
173 continue; 192 continue;
174 193
175 res = read(fd[cpu][counter], single_count, nv * sizeof(u64)); 194 res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
176 assert(res == nv * sizeof(u64)); 195 assert(res == nv * sizeof(u64));
196
177 close(fd[cpu][counter]); 197 close(fd[cpu][counter]);
178 fd[cpu][counter] = -1; 198 fd[cpu][counter] = -1;
179 199
@@ -187,63 +207,107 @@ static void read_counter(int counter)
187 scaled = 0; 207 scaled = 0;
188 if (scale) { 208 if (scale) {
189 if (count[2] == 0) { 209 if (count[2] == 0) {
190 event_scaled[run_idx][counter] = -1; 210 event_scaled[counter] = -1;
191 count[0] = 0; 211 count[0] = 0;
192 return; 212 return;
193 } 213 }
194 214
195 if (count[2] < count[1]) { 215 if (count[2] < count[1]) {
196 event_scaled[run_idx][counter] = 1; 216 event_scaled[counter] = 1;
197 count[0] = (unsigned long long) 217 count[0] = (unsigned long long)
198 ((double)count[0] * count[1] / count[2] + 0.5); 218 ((double)count[0] * count[1] / count[2] + 0.5);
199 } 219 }
200 } 220 }
221
222 for (i = 0; i < 3; i++)
223 update_stats(&event_res_stats[counter][i], count[i]);
224
225 if (verbose) {
226 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter),
227 count[0], count[1], count[2]);
228 }
229
201 /* 230 /*
202 * Save the full runtime - to allow normalization during printout: 231 * Save the full runtime - to allow normalization during printout:
203 */ 232 */
204 if (attrs[counter].type == PERF_TYPE_SOFTWARE && 233 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
205 attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) 234 update_stats(&runtime_nsecs_stats, count[0]);
206 runtime_nsecs[run_idx] = count[0]; 235 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
207 if (attrs[counter].type == PERF_TYPE_HARDWARE && 236 update_stats(&runtime_cycles_stats, count[0]);
208 attrs[counter].config == PERF_COUNT_HW_CPU_CYCLES)
209 runtime_cycles[run_idx] = count[0];
210} 237}
211 238
212static int run_perf_stat(int argc, const char **argv) 239static int run_perf_stat(int argc __used, const char **argv)
213{ 240{
214 unsigned long long t0, t1; 241 unsigned long long t0, t1;
215 int status = 0; 242 int status = 0;
216 int counter; 243 int counter;
217 int pid; 244 int pid;
245 int child_ready_pipe[2], go_pipe[2];
246 char buf;
218 247
219 if (!system_wide) 248 if (!system_wide)
220 nr_cpus = 1; 249 nr_cpus = 1;
221 250
222 for (counter = 0; counter < nr_counters; counter++) 251 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
223 create_perf_stat_counter(counter); 252 perror("failed to create pipes");
224 253 exit(1);
225 /* 254 }
226 * Enable counters and exec the command:
227 */
228 t0 = rdclock();
229 prctl(PR_TASK_PERF_COUNTERS_ENABLE);
230 255
231 if ((pid = fork()) < 0) 256 if ((pid = fork()) < 0)
232 perror("failed to fork"); 257 perror("failed to fork");
233 258
234 if (!pid) { 259 if (!pid) {
235 if (execvp(argv[0], (char **)argv)) { 260 close(child_ready_pipe[0]);
236 perror(argv[0]); 261 close(go_pipe[1]);
237 exit(-1); 262 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
238 } 263
264 /*
265 * Do a dummy execvp to get the PLT entry resolved,
266 * so we avoid the resolver overhead on the real
267 * execvp call.
268 */
269 execvp("", (char **)argv);
270
271 /*
272 * Tell the parent we're ready to go
273 */
274 close(child_ready_pipe[1]);
275
276 /*
277 * Wait until the parent tells us to go.
278 */
279 if (read(go_pipe[0], &buf, 1) == -1)
280 perror("unable to read pipe");
281
282 execvp(argv[0], (char **)argv);
283
284 perror(argv[0]);
285 exit(-1);
239 } 286 }
240 287
288 /*
289 * Wait for the child to be ready to exec.
290 */
291 close(child_ready_pipe[1]);
292 close(go_pipe[0]);
293 if (read(child_ready_pipe[0], &buf, 1) == -1)
294 perror("unable to read pipe");
295 close(child_ready_pipe[0]);
296
297 for (counter = 0; counter < nr_counters; counter++)
298 create_perf_stat_counter(counter, pid);
299
300 /*
301 * Enable counters and exec the command:
302 */
303 t0 = rdclock();
304
305 close(go_pipe[1]);
241 wait(&status); 306 wait(&status);
242 307
243 prctl(PR_TASK_PERF_COUNTERS_DISABLE);
244 t1 = rdclock(); 308 t1 = rdclock();
245 309
246 walltime_nsecs[run_idx] = t1 - t0; 310 update_stats(&walltime_nsecs_stats, t1 - t0);
247 311
248 for (counter = 0; counter < nr_counters; counter++) 312 for (counter = 0; counter < nr_counters; counter++)
249 read_counter(counter); 313 read_counter(counter);
@@ -251,46 +315,48 @@ static int run_perf_stat(int argc, const char **argv)
251 return WEXITSTATUS(status); 315 return WEXITSTATUS(status);
252} 316}
253 317
254static void print_noise(u64 *count, u64 *noise) 318static void print_noise(int counter, double avg)
255{ 319{
256 if (run_count > 1) 320 if (run_count == 1)
257 fprintf(stderr, " ( +- %7.3f%% )", 321 return;
258 (double)noise[0]/(count[0]+1)*100.0); 322
323 fprintf(stderr, " ( +- %7.3f%% )",
324 100 * stddev_stats(&event_res_stats[counter][0]) / avg);
259} 325}
260 326
261static void nsec_printout(int counter, u64 *count, u64 *noise) 327static void nsec_printout(int counter, double avg)
262{ 328{
263 double msecs = (double)count[0] / 1000000; 329 double msecs = avg / 1e6;
264
265 fprintf(stderr, " %14.6f %-20s", msecs, event_name(counter));
266 330
267 if (attrs[counter].type == PERF_TYPE_SOFTWARE && 331 fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter));
268 attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) {
269 332
270 if (walltime_nsecs_avg) 333 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
271 fprintf(stderr, " # %10.3f CPUs ", 334 fprintf(stderr, " # %10.3f CPUs ",
272 (double)count[0] / (double)walltime_nsecs_avg); 335 avg / avg_stats(&walltime_nsecs_stats));
273 } 336 }
274 print_noise(count, noise);
275} 337}
276 338
277static void abs_printout(int counter, u64 *count, u64 *noise) 339static void abs_printout(int counter, double avg)
278{ 340{
279 fprintf(stderr, " %14Ld %-20s", count[0], event_name(counter)); 341 double total, ratio = 0.0;
280 342
281 if (runtime_cycles_avg && 343 fprintf(stderr, " %14.0f %-24s", avg, event_name(counter));
282 attrs[counter].type == PERF_TYPE_HARDWARE &&
283 attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) {
284 344
285 fprintf(stderr, " # %10.3f IPC ", 345 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
286 (double)count[0] / (double)runtime_cycles_avg); 346 total = avg_stats(&runtime_cycles_stats);
347
348 if (total)
349 ratio = avg / total;
350
351 fprintf(stderr, " # %10.3f IPC ", ratio);
287 } else { 352 } else {
288 if (runtime_nsecs_avg) { 353 total = avg_stats(&runtime_nsecs_stats);
289 fprintf(stderr, " # %10.3f M/sec", 354
290 (double)count[0]/runtime_nsecs_avg*1000.0); 355 if (total)
291 } 356 ratio = 1000.0 * avg / total;
357
358 fprintf(stderr, " # %10.3f M/sec", ratio);
292 } 359 }
293 print_noise(count, noise);
294} 360}
295 361
296/* 362/*
@@ -298,121 +364,39 @@ static void abs_printout(int counter, u64 *count, u64 *noise)
298 */ 364 */
299static void print_counter(int counter) 365static void print_counter(int counter)
300{ 366{
301 u64 *count, *noise; 367 double avg = avg_stats(&event_res_stats[counter][0]);
302 int scaled; 368 int scaled = event_scaled[counter];
303
304 count = event_res_avg[counter];
305 noise = event_res_noise[counter];
306 scaled = event_scaled_avg[counter];
307 369
308 if (scaled == -1) { 370 if (scaled == -1) {
309 fprintf(stderr, " %14s %-20s\n", 371 fprintf(stderr, " %14s %-24s\n",
310 "<not counted>", event_name(counter)); 372 "<not counted>", event_name(counter));
311 return; 373 return;
312 } 374 }
313 375
314 if (nsec_counter(counter)) 376 if (nsec_counter(counter))
315 nsec_printout(counter, count, noise); 377 nsec_printout(counter, avg);
316 else 378 else
317 abs_printout(counter, count, noise); 379 abs_printout(counter, avg);
318
319 if (scaled)
320 fprintf(stderr, " (scaled from %.2f%%)",
321 (double) count[2] / count[1] * 100);
322
323 fprintf(stderr, "\n");
324}
325
326/*
327 * normalize_noise noise values down to stddev:
328 */
329static void normalize_noise(u64 *val)
330{
331 double res;
332
333 res = (double)*val / (run_count * sqrt((double)run_count));
334 380
335 *val = (u64)res; 381 print_noise(counter, avg);
336}
337 382
338static void update_avg(const char *name, int idx, u64 *avg, u64 *val) 383 if (scaled) {
339{ 384 double avg_enabled, avg_running;
340 *avg += *val;
341 385
342 if (verbose > 1) 386 avg_enabled = avg_stats(&event_res_stats[counter][1]);
343 fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val); 387 avg_running = avg_stats(&event_res_stats[counter][2]);
344}
345/*
346 * Calculate the averages and noises:
347 */
348static void calc_avg(void)
349{
350 int i, j;
351
352 if (verbose > 1)
353 fprintf(stderr, "\n");
354
355 for (i = 0; i < run_count; i++) {
356 update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i);
357 update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i);
358 update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i);
359
360 for (j = 0; j < nr_counters; j++) {
361 update_avg("counter/0", j,
362 event_res_avg[j]+0, event_res[i][j]+0);
363 update_avg("counter/1", j,
364 event_res_avg[j]+1, event_res[i][j]+1);
365 update_avg("counter/2", j,
366 event_res_avg[j]+2, event_res[i][j]+2);
367 update_avg("scaled", j,
368 event_scaled_avg + j, event_scaled[i]+j);
369 }
370 }
371 runtime_nsecs_avg /= run_count;
372 walltime_nsecs_avg /= run_count;
373 runtime_cycles_avg /= run_count;
374
375 for (j = 0; j < nr_counters; j++) {
376 event_res_avg[j][0] /= run_count;
377 event_res_avg[j][1] /= run_count;
378 event_res_avg[j][2] /= run_count;
379 }
380 388
381 for (i = 0; i < run_count; i++) { 389 fprintf(stderr, " (scaled from %.2f%%)",
382 runtime_nsecs_noise += 390 100 * avg_running / avg_enabled);
383 abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg));
384 walltime_nsecs_noise +=
385 abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg));
386 runtime_cycles_noise +=
387 abs((s64)(runtime_cycles[i] - runtime_cycles_avg));
388
389 for (j = 0; j < nr_counters; j++) {
390 event_res_noise[j][0] +=
391 abs((s64)(event_res[i][j][0] - event_res_avg[j][0]));
392 event_res_noise[j][1] +=
393 abs((s64)(event_res[i][j][1] - event_res_avg[j][1]));
394 event_res_noise[j][2] +=
395 abs((s64)(event_res[i][j][2] - event_res_avg[j][2]));
396 }
397 } 391 }
398 392
399 normalize_noise(&runtime_nsecs_noise); 393 fprintf(stderr, "\n");
400 normalize_noise(&walltime_nsecs_noise);
401 normalize_noise(&runtime_cycles_noise);
402
403 for (j = 0; j < nr_counters; j++) {
404 normalize_noise(&event_res_noise[j][0]);
405 normalize_noise(&event_res_noise[j][1]);
406 normalize_noise(&event_res_noise[j][2]);
407 }
408} 394}
409 395
410static void print_stat(int argc, const char **argv) 396static void print_stat(int argc, const char **argv)
411{ 397{
412 int i, counter; 398 int i, counter;
413 399
414 calc_avg();
415
416 fflush(stdout); 400 fflush(stdout);
417 401
418 fprintf(stderr, "\n"); 402 fprintf(stderr, "\n");
@@ -429,11 +413,15 @@ static void print_stat(int argc, const char **argv)
429 for (counter = 0; counter < nr_counters; counter++) 413 for (counter = 0; counter < nr_counters; counter++)
430 print_counter(counter); 414 print_counter(counter);
431 415
432
433 fprintf(stderr, "\n");
434 fprintf(stderr, " %14.9f seconds time elapsed.\n",
435 (double)walltime_nsecs_avg/1e9);
436 fprintf(stderr, "\n"); 416 fprintf(stderr, "\n");
417 fprintf(stderr, " %14.9f seconds time elapsed",
418 avg_stats(&walltime_nsecs_stats)/1e9);
419 if (run_count > 1) {
420 fprintf(stderr, " ( +- %7.3f%% )",
421 100*stddev_stats(&walltime_nsecs_stats) /
422 avg_stats(&walltime_nsecs_stats));
423 }
424 fprintf(stderr, "\n\n");
437} 425}
438 426
439static volatile int signr = -1; 427static volatile int signr = -1;
@@ -466,36 +454,38 @@ static const struct option options[] = {
466 OPT_INTEGER('p', "pid", &target_pid, 454 OPT_INTEGER('p', "pid", &target_pid,
467 "stat events on existing pid"), 455 "stat events on existing pid"),
468 OPT_BOOLEAN('a', "all-cpus", &system_wide, 456 OPT_BOOLEAN('a', "all-cpus", &system_wide,
469 "system-wide collection from all CPUs"), 457 "system-wide collection from all CPUs"),
470 OPT_BOOLEAN('S', "scale", &scale, 458 OPT_BOOLEAN('c', "scale", &scale,
471 "scale/normalize counters"), 459 "scale/normalize counters"),
472 OPT_BOOLEAN('v', "verbose", &verbose, 460 OPT_BOOLEAN('v', "verbose", &verbose,
473 "be more verbose (show counter open errors, etc)"), 461 "be more verbose (show counter open errors, etc)"),
474 OPT_INTEGER('r', "repeat", &run_count, 462 OPT_INTEGER('r', "repeat", &run_count,
475 "repeat command and print average + stddev (max: 100)"), 463 "repeat command and print average + stddev (max: 100)"),
464 OPT_BOOLEAN('n', "null", &null_run,
465 "null run - dont start any counters"),
476 OPT_END() 466 OPT_END()
477}; 467};
478 468
479int cmd_stat(int argc, const char **argv, const char *prefix) 469int cmd_stat(int argc, const char **argv, const char *prefix __used)
480{ 470{
481 int status; 471 int status;
482 472
483 page_size = sysconf(_SC_PAGE_SIZE); 473 argc = parse_options(argc, argv, options, stat_usage,
484 474 PARSE_OPT_STOP_AT_NON_OPTION);
485 memcpy(attrs, default_attrs, sizeof(attrs));
486
487 argc = parse_options(argc, argv, options, stat_usage, 0);
488 if (!argc) 475 if (!argc)
489 usage_with_options(stat_usage, options); 476 usage_with_options(stat_usage, options);
490 if (run_count <= 0 || run_count > MAX_RUN) 477 if (run_count <= 0)
491 usage_with_options(stat_usage, options); 478 usage_with_options(stat_usage, options);
492 479
493 if (!nr_counters) 480 /* Set attrs and nr_counters if no event is selected and !null_run */
494 nr_counters = 8; 481 if (!null_run && !nr_counters) {
482 memcpy(attrs, default_attrs, sizeof(default_attrs));
483 nr_counters = ARRAY_SIZE(default_attrs);
484 }
495 485
496 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 486 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
497 assert(nr_cpus <= MAX_NR_CPUS); 487 assert(nr_cpus <= MAX_NR_CPUS);
498 assert(nr_cpus >= 0); 488 assert((int)nr_cpus >= 0);
499 489
500 /* 490 /*
501 * We dont want to block the signals - that would cause 491 * We dont want to block the signals - that would cause
@@ -511,7 +501,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
511 status = 0; 501 status = 0;
512 for (run_idx = 0; run_idx < run_count; run_idx++) { 502 for (run_idx = 0; run_idx < run_count; run_idx++) {
513 if (run_count != 1 && verbose) 503 if (run_count != 1 && verbose)
514 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx+1); 504 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
515 status = run_perf_stat(argc, argv); 505 status = run_perf_stat(argc, argv);
516 } 506 }
517 507
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
new file mode 100644
index 000000000000..4405681b3134
--- /dev/null
+++ b/tools/perf/builtin-timechart.c
@@ -0,0 +1,1158 @@
1/*
2 * builtin-timechart.c - make an svg timechart of system activity
3 *
4 * (C) Copyright 2009 Intel Corporation
5 *
6 * Authors:
7 * Arjan van de Ven <arjan@linux.intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; version 2
12 * of the License.
13 */
14
15#include "builtin.h"
16
17#include "util/util.h"
18
19#include "util/color.h"
20#include <linux/list.h>
21#include "util/cache.h"
22#include <linux/rbtree.h>
23#include "util/symbol.h"
24#include "util/string.h"
25#include "util/callchain.h"
26#include "util/strlist.h"
27
28#include "perf.h"
29#include "util/header.h"
30#include "util/parse-options.h"
31#include "util/parse-events.h"
32#include "util/svghelper.h"
33
34static char const *input_name = "perf.data";
35static char const *output_name = "output.svg";
36
37
38static unsigned long page_size;
39static unsigned long mmap_window = 32;
40static u64 sample_type;
41
42static unsigned int numcpus;
43static u64 min_freq; /* Lowest CPU frequency seen */
44static u64 max_freq; /* Highest CPU frequency seen */
45static u64 turbo_frequency;
46
47static u64 first_time, last_time;
48
49
50static struct perf_header *header;
51
52struct per_pid;
53struct per_pidcomm;
54
55struct cpu_sample;
56struct power_event;
57struct wake_event;
58
59struct sample_wrapper;
60
61/*
62 * Datastructure layout:
63 * We keep an list of "pid"s, matching the kernels notion of a task struct.
64 * Each "pid" entry, has a list of "comm"s.
65 * this is because we want to track different programs different, while
66 * exec will reuse the original pid (by design).
67 * Each comm has a list of samples that will be used to draw
68 * final graph.
69 */
70
71struct per_pid {
72 struct per_pid *next;
73
74 int pid;
75 int ppid;
76
77 u64 start_time;
78 u64 end_time;
79 u64 total_time;
80 int display;
81
82 struct per_pidcomm *all;
83 struct per_pidcomm *current;
84
85 int painted;
86};
87
88
89struct per_pidcomm {
90 struct per_pidcomm *next;
91
92 u64 start_time;
93 u64 end_time;
94 u64 total_time;
95
96 int Y;
97 int display;
98
99 long state;
100 u64 state_since;
101
102 char *comm;
103
104 struct cpu_sample *samples;
105};
106
107struct sample_wrapper {
108 struct sample_wrapper *next;
109
110 u64 timestamp;
111 unsigned char data[0];
112};
113
114#define TYPE_NONE 0
115#define TYPE_RUNNING 1
116#define TYPE_WAITING 2
117#define TYPE_BLOCKED 3
118
119struct cpu_sample {
120 struct cpu_sample *next;
121
122 u64 start_time;
123 u64 end_time;
124 int type;
125 int cpu;
126};
127
128static struct per_pid *all_data;
129
130#define CSTATE 1
131#define PSTATE 2
132
133struct power_event {
134 struct power_event *next;
135 int type;
136 int state;
137 u64 start_time;
138 u64 end_time;
139 int cpu;
140};
141
142struct wake_event {
143 struct wake_event *next;
144 int waker;
145 int wakee;
146 u64 time;
147};
148
149static struct power_event *power_events;
150static struct wake_event *wake_events;
151
152struct sample_wrapper *all_samples;
153
154static struct per_pid *find_create_pid(int pid)
155{
156 struct per_pid *cursor = all_data;
157
158 while (cursor) {
159 if (cursor->pid == pid)
160 return cursor;
161 cursor = cursor->next;
162 }
163 cursor = malloc(sizeof(struct per_pid));
164 assert(cursor != NULL);
165 memset(cursor, 0, sizeof(struct per_pid));
166 cursor->pid = pid;
167 cursor->next = all_data;
168 all_data = cursor;
169 return cursor;
170}
171
172static void pid_set_comm(int pid, char *comm)
173{
174 struct per_pid *p;
175 struct per_pidcomm *c;
176 p = find_create_pid(pid);
177 c = p->all;
178 while (c) {
179 if (c->comm && strcmp(c->comm, comm) == 0) {
180 p->current = c;
181 return;
182 }
183 if (!c->comm) {
184 c->comm = strdup(comm);
185 p->current = c;
186 return;
187 }
188 c = c->next;
189 }
190 c = malloc(sizeof(struct per_pidcomm));
191 assert(c != NULL);
192 memset(c, 0, sizeof(struct per_pidcomm));
193 c->comm = strdup(comm);
194 p->current = c;
195 c->next = p->all;
196 p->all = c;
197}
198
199static void pid_fork(int pid, int ppid, u64 timestamp)
200{
201 struct per_pid *p, *pp;
202 p = find_create_pid(pid);
203 pp = find_create_pid(ppid);
204 p->ppid = ppid;
205 if (pp->current && pp->current->comm && !p->current)
206 pid_set_comm(pid, pp->current->comm);
207
208 p->start_time = timestamp;
209 if (p->current) {
210 p->current->start_time = timestamp;
211 p->current->state_since = timestamp;
212 }
213}
214
215static void pid_exit(int pid, u64 timestamp)
216{
217 struct per_pid *p;
218 p = find_create_pid(pid);
219 p->end_time = timestamp;
220 if (p->current)
221 p->current->end_time = timestamp;
222}
223
224static void
225pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
226{
227 struct per_pid *p;
228 struct per_pidcomm *c;
229 struct cpu_sample *sample;
230
231 p = find_create_pid(pid);
232 c = p->current;
233 if (!c) {
234 c = malloc(sizeof(struct per_pidcomm));
235 assert(c != NULL);
236 memset(c, 0, sizeof(struct per_pidcomm));
237 p->current = c;
238 c->next = p->all;
239 p->all = c;
240 }
241
242 sample = malloc(sizeof(struct cpu_sample));
243 assert(sample != NULL);
244 memset(sample, 0, sizeof(struct cpu_sample));
245 sample->start_time = start;
246 sample->end_time = end;
247 sample->type = type;
248 sample->next = c->samples;
249 sample->cpu = cpu;
250 c->samples = sample;
251
252 if (sample->type == TYPE_RUNNING && end > start && start > 0) {
253 c->total_time += (end-start);
254 p->total_time += (end-start);
255 }
256
257 if (c->start_time == 0 || c->start_time > start)
258 c->start_time = start;
259 if (p->start_time == 0 || p->start_time > start)
260 p->start_time = start;
261
262 if (cpu > numcpus)
263 numcpus = cpu;
264}
265
266#define MAX_CPUS 4096
267
268static u64 cpus_cstate_start_times[MAX_CPUS];
269static int cpus_cstate_state[MAX_CPUS];
270static u64 cpus_pstate_start_times[MAX_CPUS];
271static u64 cpus_pstate_state[MAX_CPUS];
272
273static int
274process_comm_event(event_t *event)
275{
276 pid_set_comm(event->comm.pid, event->comm.comm);
277 return 0;
278}
279static int
280process_fork_event(event_t *event)
281{
282 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
283 return 0;
284}
285
286static int
287process_exit_event(event_t *event)
288{
289 pid_exit(event->fork.pid, event->fork.time);
290 return 0;
291}
292
293struct trace_entry {
294 u32 size;
295 unsigned short type;
296 unsigned char flags;
297 unsigned char preempt_count;
298 int pid;
299 int tgid;
300};
301
302struct power_entry {
303 struct trace_entry te;
304 s64 type;
305 s64 value;
306};
307
308#define TASK_COMM_LEN 16
309struct wakeup_entry {
310 struct trace_entry te;
311 char comm[TASK_COMM_LEN];
312 int pid;
313 int prio;
314 int success;
315};
316
317/*
318 * trace_flag_type is an enumeration that holds different
319 * states when a trace occurs. These are:
320 * IRQS_OFF - interrupts were disabled
321 * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags
322 * NEED_RESCED - reschedule is requested
323 * HARDIRQ - inside an interrupt handler
324 * SOFTIRQ - inside a softirq handler
325 */
326enum trace_flag_type {
327 TRACE_FLAG_IRQS_OFF = 0x01,
328 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
329 TRACE_FLAG_NEED_RESCHED = 0x04,
330 TRACE_FLAG_HARDIRQ = 0x08,
331 TRACE_FLAG_SOFTIRQ = 0x10,
332};
333
334
335
336struct sched_switch {
337 struct trace_entry te;
338 char prev_comm[TASK_COMM_LEN];
339 int prev_pid;
340 int prev_prio;
341 long prev_state; /* Arjan weeps. */
342 char next_comm[TASK_COMM_LEN];
343 int next_pid;
344 int next_prio;
345};
346
347static void c_state_start(int cpu, u64 timestamp, int state)
348{
349 cpus_cstate_start_times[cpu] = timestamp;
350 cpus_cstate_state[cpu] = state;
351}
352
353static void c_state_end(int cpu, u64 timestamp)
354{
355 struct power_event *pwr;
356 pwr = malloc(sizeof(struct power_event));
357 if (!pwr)
358 return;
359 memset(pwr, 0, sizeof(struct power_event));
360
361 pwr->state = cpus_cstate_state[cpu];
362 pwr->start_time = cpus_cstate_start_times[cpu];
363 pwr->end_time = timestamp;
364 pwr->cpu = cpu;
365 pwr->type = CSTATE;
366 pwr->next = power_events;
367
368 power_events = pwr;
369}
370
371static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
372{
373 struct power_event *pwr;
374 pwr = malloc(sizeof(struct power_event));
375
376 if (new_freq > 8000000) /* detect invalid data */
377 return;
378
379 if (!pwr)
380 return;
381 memset(pwr, 0, sizeof(struct power_event));
382
383 pwr->state = cpus_pstate_state[cpu];
384 pwr->start_time = cpus_pstate_start_times[cpu];
385 pwr->end_time = timestamp;
386 pwr->cpu = cpu;
387 pwr->type = PSTATE;
388 pwr->next = power_events;
389
390 if (!pwr->start_time)
391 pwr->start_time = first_time;
392
393 power_events = pwr;
394
395 cpus_pstate_state[cpu] = new_freq;
396 cpus_pstate_start_times[cpu] = timestamp;
397
398 if ((u64)new_freq > max_freq)
399 max_freq = new_freq;
400
401 if (new_freq < min_freq || min_freq == 0)
402 min_freq = new_freq;
403
404 if (new_freq == max_freq - 1000)
405 turbo_frequency = max_freq;
406}
407
408static void
409sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te)
410{
411 struct wake_event *we;
412 struct per_pid *p;
413 struct wakeup_entry *wake = (void *)te;
414
415 we = malloc(sizeof(struct wake_event));
416 if (!we)
417 return;
418
419 memset(we, 0, sizeof(struct wake_event));
420 we->time = timestamp;
421 we->waker = pid;
422
423 if ((te->flags & TRACE_FLAG_HARDIRQ) || (te->flags & TRACE_FLAG_SOFTIRQ))
424 we->waker = -1;
425
426 we->wakee = wake->pid;
427 we->next = wake_events;
428 wake_events = we;
429 p = find_create_pid(we->wakee);
430
431 if (p && p->current && p->current->state == TYPE_NONE) {
432 p->current->state_since = timestamp;
433 p->current->state = TYPE_WAITING;
434 }
435 if (p && p->current && p->current->state == TYPE_BLOCKED) {
436 pid_put_sample(p->pid, p->current->state, cpu, p->current->state_since, timestamp);
437 p->current->state_since = timestamp;
438 p->current->state = TYPE_WAITING;
439 }
440}
441
442static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
443{
444 struct per_pid *p = NULL, *prev_p;
445 struct sched_switch *sw = (void *)te;
446
447
448 prev_p = find_create_pid(sw->prev_pid);
449
450 p = find_create_pid(sw->next_pid);
451
452 if (prev_p->current && prev_p->current->state != TYPE_NONE)
453 pid_put_sample(sw->prev_pid, TYPE_RUNNING, cpu, prev_p->current->state_since, timestamp);
454 if (p && p->current) {
455 if (p->current->state != TYPE_NONE)
456 pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp);
457
458 p->current->state_since = timestamp;
459 p->current->state = TYPE_RUNNING;
460 }
461
462 if (prev_p->current) {
463 prev_p->current->state = TYPE_NONE;
464 prev_p->current->state_since = timestamp;
465 if (sw->prev_state & 2)
466 prev_p->current->state = TYPE_BLOCKED;
467 if (sw->prev_state == 0)
468 prev_p->current->state = TYPE_WAITING;
469 }
470}
471
472
473static int
474process_sample_event(event_t *event)
475{
476 int cursor = 0;
477 u64 addr = 0;
478 u64 stamp = 0;
479 u32 cpu = 0;
480 u32 pid = 0;
481 struct trace_entry *te;
482
483 if (sample_type & PERF_SAMPLE_IP)
484 cursor++;
485
486 if (sample_type & PERF_SAMPLE_TID) {
487 pid = event->sample.array[cursor]>>32;
488 cursor++;
489 }
490 if (sample_type & PERF_SAMPLE_TIME) {
491 stamp = event->sample.array[cursor++];
492
493 if (!first_time || first_time > stamp)
494 first_time = stamp;
495 if (last_time < stamp)
496 last_time = stamp;
497
498 }
499 if (sample_type & PERF_SAMPLE_ADDR)
500 addr = event->sample.array[cursor++];
501 if (sample_type & PERF_SAMPLE_ID)
502 cursor++;
503 if (sample_type & PERF_SAMPLE_STREAM_ID)
504 cursor++;
505 if (sample_type & PERF_SAMPLE_CPU)
506 cpu = event->sample.array[cursor++] & 0xFFFFFFFF;
507 if (sample_type & PERF_SAMPLE_PERIOD)
508 cursor++;
509
510 te = (void *)&event->sample.array[cursor];
511
512 if (sample_type & PERF_SAMPLE_RAW && te->size > 0) {
513 char *event_str;
514 struct power_entry *pe;
515
516 pe = (void *)te;
517
518 event_str = perf_header__find_event(te->type);
519
520 if (!event_str)
521 return 0;
522
523 if (strcmp(event_str, "power:power_start") == 0)
524 c_state_start(cpu, stamp, pe->value);
525
526 if (strcmp(event_str, "power:power_end") == 0)
527 c_state_end(cpu, stamp);
528
529 if (strcmp(event_str, "power:power_frequency") == 0)
530 p_state_change(cpu, stamp, pe->value);
531
532 if (strcmp(event_str, "sched:sched_wakeup") == 0)
533 sched_wakeup(cpu, stamp, pid, te);
534
535 if (strcmp(event_str, "sched:sched_switch") == 0)
536 sched_switch(cpu, stamp, te);
537 }
538 return 0;
539}
540
541/*
542 * After the last sample we need to wrap up the current C/P state
543 * and close out each CPU for these.
544 */
545static void end_sample_processing(void)
546{
547 u64 cpu;
548 struct power_event *pwr;
549
550 for (cpu = 0; cpu < numcpus; cpu++) {
551 pwr = malloc(sizeof(struct power_event));
552 if (!pwr)
553 return;
554 memset(pwr, 0, sizeof(struct power_event));
555
556 /* C state */
557#if 0
558 pwr->state = cpus_cstate_state[cpu];
559 pwr->start_time = cpus_cstate_start_times[cpu];
560 pwr->end_time = last_time;
561 pwr->cpu = cpu;
562 pwr->type = CSTATE;
563 pwr->next = power_events;
564
565 power_events = pwr;
566#endif
567 /* P state */
568
569 pwr = malloc(sizeof(struct power_event));
570 if (!pwr)
571 return;
572 memset(pwr, 0, sizeof(struct power_event));
573
574 pwr->state = cpus_pstate_state[cpu];
575 pwr->start_time = cpus_pstate_start_times[cpu];
576 pwr->end_time = last_time;
577 pwr->cpu = cpu;
578 pwr->type = PSTATE;
579 pwr->next = power_events;
580
581 if (!pwr->start_time)
582 pwr->start_time = first_time;
583 if (!pwr->state)
584 pwr->state = min_freq;
585 power_events = pwr;
586 }
587}
588
589static u64 sample_time(event_t *event)
590{
591 int cursor;
592
593 cursor = 0;
594 if (sample_type & PERF_SAMPLE_IP)
595 cursor++;
596 if (sample_type & PERF_SAMPLE_TID)
597 cursor++;
598 if (sample_type & PERF_SAMPLE_TIME)
599 return event->sample.array[cursor];
600 return 0;
601}
602
603
604/*
605 * We first queue all events, sorted backwards by insertion.
606 * The order will get flipped later.
607 */
608static int
609queue_sample_event(event_t *event)
610{
611 struct sample_wrapper *copy, *prev;
612 int size;
613
614 size = event->sample.header.size + sizeof(struct sample_wrapper) + 8;
615
616 copy = malloc(size);
617 if (!copy)
618 return 1;
619
620 memset(copy, 0, size);
621
622 copy->next = NULL;
623 copy->timestamp = sample_time(event);
624
625 memcpy(&copy->data, event, event->sample.header.size);
626
627 /* insert in the right place in the list */
628
629 if (!all_samples) {
630 /* first sample ever */
631 all_samples = copy;
632 return 0;
633 }
634
635 if (all_samples->timestamp < copy->timestamp) {
636 /* insert at the head of the list */
637 copy->next = all_samples;
638 all_samples = copy;
639 return 0;
640 }
641
642 prev = all_samples;
643 while (prev->next) {
644 if (prev->next->timestamp < copy->timestamp) {
645 copy->next = prev->next;
646 prev->next = copy;
647 return 0;
648 }
649 prev = prev->next;
650 }
651 /* insert at the end of the list */
652 prev->next = copy;
653
654 return 0;
655}
656
657static void sort_queued_samples(void)
658{
659 struct sample_wrapper *cursor, *next;
660
661 cursor = all_samples;
662 all_samples = NULL;
663
664 while (cursor) {
665 next = cursor->next;
666 cursor->next = all_samples;
667 all_samples = cursor;
668 cursor = next;
669 }
670}
671
672/*
673 * Sort the pid datastructure
674 */
675static void sort_pids(void)
676{
677 struct per_pid *new_list, *p, *cursor, *prev;
678 /* sort by ppid first, then by pid, lowest to highest */
679
680 new_list = NULL;
681
682 while (all_data) {
683 p = all_data;
684 all_data = p->next;
685 p->next = NULL;
686
687 if (new_list == NULL) {
688 new_list = p;
689 p->next = NULL;
690 continue;
691 }
692 prev = NULL;
693 cursor = new_list;
694 while (cursor) {
695 if (cursor->ppid > p->ppid ||
696 (cursor->ppid == p->ppid && cursor->pid > p->pid)) {
697 /* must insert before */
698 if (prev) {
699 p->next = prev->next;
700 prev->next = p;
701 cursor = NULL;
702 continue;
703 } else {
704 p->next = new_list;
705 new_list = p;
706 cursor = NULL;
707 continue;
708 }
709 }
710
711 prev = cursor;
712 cursor = cursor->next;
713 if (!cursor)
714 prev->next = p;
715 }
716 }
717 all_data = new_list;
718}
719
720
721static void draw_c_p_states(void)
722{
723 struct power_event *pwr;
724 pwr = power_events;
725
726 /*
727 * two pass drawing so that the P state bars are on top of the C state blocks
728 */
729 while (pwr) {
730 if (pwr->type == CSTATE)
731 svg_cstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
732 pwr = pwr->next;
733 }
734
735 pwr = power_events;
736 while (pwr) {
737 if (pwr->type == PSTATE) {
738 if (!pwr->state)
739 pwr->state = min_freq;
740 svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
741 }
742 pwr = pwr->next;
743 }
744}
745
746static void draw_wakeups(void)
747{
748 struct wake_event *we;
749 struct per_pid *p;
750 struct per_pidcomm *c;
751
752 we = wake_events;
753 while (we) {
754 int from = 0, to = 0;
755 char *task_from = NULL, *task_to = NULL;
756
757 /* locate the column of the waker and wakee */
758 p = all_data;
759 while (p) {
760 if (p->pid == we->waker || p->pid == we->wakee) {
761 c = p->all;
762 while (c) {
763 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
764 if (p->pid == we->waker) {
765 from = c->Y;
766 task_from = c->comm;
767 }
768 if (p->pid == we->wakee) {
769 to = c->Y;
770 task_to = c->comm;
771 }
772 }
773 c = c->next;
774 }
775 }
776 p = p->next;
777 }
778
779 if (we->waker == -1)
780 svg_interrupt(we->time, to);
781 else if (from && to && abs(from - to) == 1)
782 svg_wakeline(we->time, from, to);
783 else
784 svg_partial_wakeline(we->time, from, task_from, to, task_to);
785 we = we->next;
786 }
787}
788
789static void draw_cpu_usage(void)
790{
791 struct per_pid *p;
792 struct per_pidcomm *c;
793 struct cpu_sample *sample;
794 p = all_data;
795 while (p) {
796 c = p->all;
797 while (c) {
798 sample = c->samples;
799 while (sample) {
800 if (sample->type == TYPE_RUNNING)
801 svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm);
802
803 sample = sample->next;
804 }
805 c = c->next;
806 }
807 p = p->next;
808 }
809}
810
811static void draw_process_bars(void)
812{
813 struct per_pid *p;
814 struct per_pidcomm *c;
815 struct cpu_sample *sample;
816 int Y = 0;
817
818 Y = 2 * numcpus + 2;
819
820 p = all_data;
821 while (p) {
822 c = p->all;
823 while (c) {
824 if (!c->display) {
825 c->Y = 0;
826 c = c->next;
827 continue;
828 }
829
830 svg_box(Y, c->start_time, c->end_time, "process");
831 sample = c->samples;
832 while (sample) {
833 if (sample->type == TYPE_RUNNING)
834 svg_sample(Y, sample->cpu, sample->start_time, sample->end_time);
835 if (sample->type == TYPE_BLOCKED)
836 svg_box(Y, sample->start_time, sample->end_time, "blocked");
837 if (sample->type == TYPE_WAITING)
838 svg_waiting(Y, sample->start_time, sample->end_time);
839 sample = sample->next;
840 }
841
842 if (c->comm) {
843 char comm[256];
844 if (c->total_time > 5000000000) /* 5 seconds */
845 sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / 1000000000.0);
846 else
847 sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / 1000000.0);
848
849 svg_text(Y, c->start_time, comm);
850 }
851 c->Y = Y;
852 Y++;
853 c = c->next;
854 }
855 p = p->next;
856 }
857}
858
859static int determine_display_tasks(u64 threshold)
860{
861 struct per_pid *p;
862 struct per_pidcomm *c;
863 int count = 0;
864
865 p = all_data;
866 while (p) {
867 p->display = 0;
868 if (p->start_time == 1)
869 p->start_time = first_time;
870
871 /* no exit marker, task kept running to the end */
872 if (p->end_time == 0)
873 p->end_time = last_time;
874 if (p->total_time >= threshold)
875 p->display = 1;
876
877 c = p->all;
878
879 while (c) {
880 c->display = 0;
881
882 if (c->start_time == 1)
883 c->start_time = first_time;
884
885 if (c->total_time >= threshold) {
886 c->display = 1;
887 count++;
888 }
889
890 if (c->end_time == 0)
891 c->end_time = last_time;
892
893 c = c->next;
894 }
895 p = p->next;
896 }
897 return count;
898}
899
900
901
902#define TIME_THRESH 10000000
903
904static void write_svg_file(const char *filename)
905{
906 u64 i;
907 int count;
908
909 numcpus++;
910
911
912 count = determine_display_tasks(TIME_THRESH);
913
914 /* We'd like to show at least 15 tasks; be less picky if we have fewer */
915 if (count < 15)
916 count = determine_display_tasks(TIME_THRESH / 10);
917
918 open_svg(filename, numcpus, count, first_time, last_time);
919
920 svg_time_grid();
921 svg_legenda();
922
923 for (i = 0; i < numcpus; i++)
924 svg_cpu_box(i, max_freq, turbo_frequency);
925
926 draw_cpu_usage();
927 draw_process_bars();
928 draw_c_p_states();
929 draw_wakeups();
930
931 svg_close();
932}
933
934static int
935process_event(event_t *event)
936{
937
938 switch (event->header.type) {
939
940 case PERF_RECORD_COMM:
941 return process_comm_event(event);
942 case PERF_RECORD_FORK:
943 return process_fork_event(event);
944 case PERF_RECORD_EXIT:
945 return process_exit_event(event);
946 case PERF_RECORD_SAMPLE:
947 return queue_sample_event(event);
948
949 /*
950 * We dont process them right now but they are fine:
951 */
952 case PERF_RECORD_MMAP:
953 case PERF_RECORD_THROTTLE:
954 case PERF_RECORD_UNTHROTTLE:
955 return 0;
956
957 default:
958 return -1;
959 }
960
961 return 0;
962}
963
964static void process_samples(void)
965{
966 struct sample_wrapper *cursor;
967 event_t *event;
968
969 sort_queued_samples();
970
971 cursor = all_samples;
972 while (cursor) {
973 event = (void *)&cursor->data;
974 cursor = cursor->next;
975 process_sample_event(event);
976 }
977}
978
979
980static int __cmd_timechart(void)
981{
982 int ret, rc = EXIT_FAILURE;
983 unsigned long offset = 0;
984 unsigned long head, shift;
985 struct stat statbuf;
986 event_t *event;
987 uint32_t size;
988 char *buf;
989 int input;
990
991 input = open(input_name, O_RDONLY);
992 if (input < 0) {
993 fprintf(stderr, " failed to open file: %s", input_name);
994 if (!strcmp(input_name, "perf.data"))
995 fprintf(stderr, " (try 'perf record' first)");
996 fprintf(stderr, "\n");
997 exit(-1);
998 }
999
1000 ret = fstat(input, &statbuf);
1001 if (ret < 0) {
1002 perror("failed to stat file");
1003 exit(-1);
1004 }
1005
1006 if (!statbuf.st_size) {
1007 fprintf(stderr, "zero-sized file, nothing to do!\n");
1008 exit(0);
1009 }
1010
1011 header = perf_header__read(input);
1012 head = header->data_offset;
1013
1014 sample_type = perf_header__sample_type(header);
1015
1016 shift = page_size * (head / page_size);
1017 offset += shift;
1018 head -= shift;
1019
1020remap:
1021 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1022 MAP_SHARED, input, offset);
1023 if (buf == MAP_FAILED) {
1024 perror("failed to mmap file");
1025 exit(-1);
1026 }
1027
1028more:
1029 event = (event_t *)(buf + head);
1030
1031 size = event->header.size;
1032 if (!size)
1033 size = 8;
1034
1035 if (head + event->header.size >= page_size * mmap_window) {
1036 int ret2;
1037
1038 shift = page_size * (head / page_size);
1039
1040 ret2 = munmap(buf, page_size * mmap_window);
1041 assert(ret2 == 0);
1042
1043 offset += shift;
1044 head -= shift;
1045 goto remap;
1046 }
1047
1048 size = event->header.size;
1049
1050 if (!size || process_event(event) < 0) {
1051
1052 printf("%p [%p]: skipping unknown header type: %d\n",
1053 (void *)(offset + head),
1054 (void *)(long)(event->header.size),
1055 event->header.type);
1056
1057 /*
1058 * assume we lost track of the stream, check alignment, and
1059 * increment a single u64 in the hope to catch on again 'soon'.
1060 */
1061
1062 if (unlikely(head & 7))
1063 head &= ~7ULL;
1064
1065 size = 8;
1066 }
1067
1068 head += size;
1069
1070 if (offset + head >= header->data_offset + header->data_size)
1071 goto done;
1072
1073 if (offset + head < (unsigned long)statbuf.st_size)
1074 goto more;
1075
1076done:
1077 rc = EXIT_SUCCESS;
1078 close(input);
1079
1080
1081 process_samples();
1082
1083 end_sample_processing();
1084
1085 sort_pids();
1086
1087 write_svg_file(output_name);
1088
1089 printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name);
1090
1091 return rc;
1092}
1093
1094static const char * const timechart_usage[] = {
1095 "perf timechart [<options>] {record}",
1096 NULL
1097};
1098
1099static const char *record_args[] = {
1100 "record",
1101 "-a",
1102 "-R",
1103 "-M",
1104 "-f",
1105 "-c", "1",
1106 "-e", "power:power_start",
1107 "-e", "power:power_end",
1108 "-e", "power:power_frequency",
1109 "-e", "sched:sched_wakeup",
1110 "-e", "sched:sched_switch",
1111};
1112
1113static int __cmd_record(int argc, const char **argv)
1114{
1115 unsigned int rec_argc, i, j;
1116 const char **rec_argv;
1117
1118 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1119 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1120
1121 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1122 rec_argv[i] = strdup(record_args[i]);
1123
1124 for (j = 1; j < (unsigned int)argc; j++, i++)
1125 rec_argv[i] = argv[j];
1126
1127 return cmd_record(i, rec_argv, NULL);
1128}
1129
1130static const struct option options[] = {
1131 OPT_STRING('i', "input", &input_name, "file",
1132 "input file name"),
1133 OPT_STRING('o', "output", &output_name, "file",
1134 "output file name"),
1135 OPT_INTEGER('w', "width", &svg_page_width,
1136 "page width"),
1137 OPT_END()
1138};
1139
1140
1141int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1142{
1143 symbol__init();
1144
1145 page_size = getpagesize();
1146
1147 argc = parse_options(argc, argv, options, timechart_usage,
1148 PARSE_OPT_STOP_AT_NON_OPTION);
1149
1150 if (argc && !strncmp(argv[0], "rec", 3))
1151 return __cmd_record(argc, argv);
1152 else if (argc)
1153 usage_with_options(timechart_usage, options);
1154
1155 setup_pager();
1156
1157 return __cmd_timechart();
1158}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5352b5e352ed..1ca88896eee4 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -23,14 +23,18 @@
23#include "util/symbol.h" 23#include "util/symbol.h"
24#include "util/color.h" 24#include "util/color.h"
25#include "util/util.h" 25#include "util/util.h"
26#include "util/rbtree.h" 26#include <linux/rbtree.h>
27#include "util/parse-options.h" 27#include "util/parse-options.h"
28#include "util/parse-events.h" 28#include "util/parse-events.h"
29 29
30#include "util/debug.h"
31
30#include <assert.h> 32#include <assert.h>
31#include <fcntl.h> 33#include <fcntl.h>
32 34
33#include <stdio.h> 35#include <stdio.h>
36#include <termios.h>
37#include <unistd.h>
34 38
35#include <errno.h> 39#include <errno.h>
36#include <time.h> 40#include <time.h>
@@ -54,10 +58,11 @@ static int system_wide = 0;
54 58
55static int default_interval = 100000; 59static int default_interval = 100000;
56 60
57static u64 count_filter = 5; 61static int count_filter = 5;
58static int print_entries = 15; 62static int print_entries = 15;
59 63
60static int target_pid = -1; 64static int target_pid = -1;
65static int inherit = 0;
61static int profile_cpu = -1; 66static int profile_cpu = -1;
62static int nr_cpus = 0; 67static int nr_cpus = 0;
63static unsigned int realtime_prio = 0; 68static unsigned int realtime_prio = 0;
@@ -65,17 +70,29 @@ static int group = 0;
65static unsigned int page_size; 70static unsigned int page_size;
66static unsigned int mmap_pages = 16; 71static unsigned int mmap_pages = 16;
67static int freq = 0; 72static int freq = 0;
68static int verbose = 0;
69
70static char *sym_filter;
71static unsigned long filter_start;
72static unsigned long filter_end;
73 73
74static int delay_secs = 2; 74static int delay_secs = 2;
75static int zero; 75static int zero;
76static int dump_symtab; 76static int dump_symtab;
77 77
78/* 78/*
79 * Source
80 */
81
82struct source_line {
83 u64 eip;
84 unsigned long count[MAX_COUNTERS];
85 char *line;
86 struct source_line *next;
87};
88
89static char *sym_filter = NULL;
90struct sym_entry *sym_filter_entry = NULL;
91static int sym_pcnt_filter = 5;
92static int sym_counter = 0;
93static int display_weighted = -1;
94
95/*
79 * Symbols 96 * Symbols
80 */ 97 */
81 98
@@ -89,11 +106,238 @@ struct sym_entry {
89 unsigned long snap_count; 106 unsigned long snap_count;
90 double weight; 107 double weight;
91 int skip; 108 int skip;
109 struct source_line *source;
110 struct source_line *lines;
111 struct source_line **lines_tail;
112 pthread_mutex_t source_lock;
92}; 113};
93 114
94struct sym_entry *sym_filter_entry; 115/*
116 * Source functions
117 */
118
119static void parse_source(struct sym_entry *syme)
120{
121 struct symbol *sym;
122 struct module *module;
123 struct section *section = NULL;
124 FILE *file;
125 char command[PATH_MAX*2];
126 const char *path = vmlinux_name;
127 u64 start, end, len;
128
129 if (!syme)
130 return;
131
132 if (syme->lines) {
133 pthread_mutex_lock(&syme->source_lock);
134 goto out_assign;
135 }
136
137 sym = (struct symbol *)(syme + 1);
138 module = sym->module;
139
140 if (module)
141 path = module->path;
142 if (!path)
143 return;
144
145 start = sym->obj_start;
146 if (!start)
147 start = sym->start;
148
149 if (module) {
150 section = module->sections->find_section(module->sections, ".text");
151 if (section)
152 start -= section->vma;
153 }
154
155 end = start + sym->end - sym->start + 1;
156 len = sym->end - sym->start;
157
158 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path);
159
160 file = popen(command, "r");
161 if (!file)
162 return;
163
164 pthread_mutex_lock(&syme->source_lock);
165 syme->lines_tail = &syme->lines;
166 while (!feof(file)) {
167 struct source_line *src;
168 size_t dummy = 0;
169 char *c;
170
171 src = malloc(sizeof(struct source_line));
172 assert(src != NULL);
173 memset(src, 0, sizeof(struct source_line));
174
175 if (getline(&src->line, &dummy, file) < 0)
176 break;
177 if (!src->line)
178 break;
179
180 c = strchr(src->line, '\n');
181 if (c)
182 *c = 0;
183
184 src->next = NULL;
185 *syme->lines_tail = src;
186 syme->lines_tail = &src->next;
187
188 if (strlen(src->line)>8 && src->line[8] == ':') {
189 src->eip = strtoull(src->line, NULL, 16);
190 if (section)
191 src->eip += section->vma;
192 }
193 if (strlen(src->line)>8 && src->line[16] == ':') {
194 src->eip = strtoull(src->line, NULL, 16);
195 if (section)
196 src->eip += section->vma;
197 }
198 }
199 pclose(file);
200out_assign:
201 sym_filter_entry = syme;
202 pthread_mutex_unlock(&syme->source_lock);
203}
204
205static void __zero_source_counters(struct sym_entry *syme)
206{
207 int i;
208 struct source_line *line;
209
210 line = syme->lines;
211 while (line) {
212 for (i = 0; i < nr_counters; i++)
213 line->count[i] = 0;
214 line = line->next;
215 }
216}
217
218static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
219{
220 struct source_line *line;
221
222 if (syme != sym_filter_entry)
223 return;
224
225 if (pthread_mutex_trylock(&syme->source_lock))
226 return;
95 227
96struct dso *kernel_dso; 228 if (!syme->source)
229 goto out_unlock;
230
231 for (line = syme->lines; line; line = line->next) {
232 if (line->eip == ip) {
233 line->count[counter]++;
234 break;
235 }
236 if (line->eip > ip)
237 break;
238 }
239out_unlock:
240 pthread_mutex_unlock(&syme->source_lock);
241}
242
243static void lookup_sym_source(struct sym_entry *syme)
244{
245 struct symbol *symbol = (struct symbol *)(syme + 1);
246 struct source_line *line;
247 char pattern[PATH_MAX];
248 char *idx;
249
250 sprintf(pattern, "<%s>:", symbol->name);
251
252 if (symbol->module) {
253 idx = strstr(pattern, "\t");
254 if (idx)
255 *idx = 0;
256 }
257
258 pthread_mutex_lock(&syme->source_lock);
259 for (line = syme->lines; line; line = line->next) {
260 if (strstr(line->line, pattern)) {
261 syme->source = line;
262 break;
263 }
264 }
265 pthread_mutex_unlock(&syme->source_lock);
266}
267
268static void show_lines(struct source_line *queue, int count, int total)
269{
270 int i;
271 struct source_line *line;
272
273 line = queue;
274 for (i = 0; i < count; i++) {
275 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
276
277 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line);
278 line = line->next;
279 }
280}
281
282#define TRACE_COUNT 3
283
284static void show_details(struct sym_entry *syme)
285{
286 struct symbol *symbol;
287 struct source_line *line;
288 struct source_line *line_queue = NULL;
289 int displayed = 0;
290 int line_queue_count = 0, total = 0, more = 0;
291
292 if (!syme)
293 return;
294
295 if (!syme->source)
296 lookup_sym_source(syme);
297
298 if (!syme->source)
299 return;
300
301 symbol = (struct symbol *)(syme + 1);
302 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
303 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
304
305 pthread_mutex_lock(&syme->source_lock);
306 line = syme->source;
307 while (line) {
308 total += line->count[sym_counter];
309 line = line->next;
310 }
311
312 line = syme->source;
313 while (line) {
314 float pcnt = 0.0;
315
316 if (!line_queue_count)
317 line_queue = line;
318 line_queue_count++;
319
320 if (line->count[sym_counter])
321 pcnt = 100.0 * line->count[sym_counter] / (float)total;
322 if (pcnt >= (float)sym_pcnt_filter) {
323 if (displayed <= print_entries)
324 show_lines(line_queue, line_queue_count, total);
325 else more++;
326 displayed += line_queue_count;
327 line_queue_count = 0;
328 line_queue = NULL;
329 } else if (line_queue_count > TRACE_COUNT) {
330 line_queue = line_queue->next;
331 line_queue_count--;
332 }
333
334 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
335 line = line->next;
336 }
337 pthread_mutex_unlock(&syme->source_lock);
338 if (more)
339 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
340}
97 341
98/* 342/*
99 * Symbols will be added here in record_ip and will get out 343 * Symbols will be added here in record_ip and will get out
@@ -110,6 +354,9 @@ static double sym_weight(const struct sym_entry *sym)
110 double weight = sym->snap_count; 354 double weight = sym->snap_count;
111 int counter; 355 int counter;
112 356
357 if (!display_weighted)
358 return weight;
359
113 for (counter = 1; counter < nr_counters-1; counter++) 360 for (counter = 1; counter < nr_counters-1; counter++)
114 weight *= sym->count[counter]; 361 weight *= sym->count[counter];
115 362
@@ -157,7 +404,7 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
157static void print_sym_table(void) 404static void print_sym_table(void)
158{ 405{
159 int printed = 0, j; 406 int printed = 0, j;
160 int counter; 407 int counter, snap = !display_weighted ? sym_counter : 0;
161 float samples_per_sec = samples/delay_secs; 408 float samples_per_sec = samples/delay_secs;
162 float ksamples_per_sec = (samples-userspace_samples)/delay_secs; 409 float ksamples_per_sec = (samples-userspace_samples)/delay_secs;
163 float sum_ksamples = 0.0; 410 float sum_ksamples = 0.0;
@@ -173,7 +420,7 @@ static void print_sym_table(void)
173 pthread_mutex_unlock(&active_symbols_lock); 420 pthread_mutex_unlock(&active_symbols_lock);
174 421
175 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 422 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
176 syme->snap_count = syme->count[0]; 423 syme->snap_count = syme->count[snap];
177 if (syme->snap_count != 0) { 424 if (syme->snap_count != 0) {
178 syme->weight = sym_weight(syme); 425 syme->weight = sym_weight(syme);
179 rb_insert_active_sym(&tmp, syme); 426 rb_insert_active_sym(&tmp, syme);
@@ -193,7 +440,7 @@ static void print_sym_table(void)
193 samples_per_sec, 440 samples_per_sec,
194 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 441 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
195 442
196 if (nr_counters == 1) { 443 if (nr_counters == 1 || !display_weighted) {
197 printf("%Ld", (u64)attrs[0].sample_period); 444 printf("%Ld", (u64)attrs[0].sample_period);
198 if (freq) 445 if (freq)
199 printf("Hz "); 446 printf("Hz ");
@@ -201,7 +448,9 @@ static void print_sym_table(void)
201 printf(" "); 448 printf(" ");
202 } 449 }
203 450
204 for (counter = 0; counter < nr_counters; counter++) { 451 if (!display_weighted)
452 printf("%s", event_name(sym_counter));
453 else for (counter = 0; counter < nr_counters; counter++) {
205 if (counter) 454 if (counter)
206 printf("/"); 455 printf("/");
207 456
@@ -226,71 +475,330 @@ static void print_sym_table(void)
226 475
227 printf("------------------------------------------------------------------------------\n\n"); 476 printf("------------------------------------------------------------------------------\n\n");
228 477
478 if (sym_filter_entry) {
479 show_details(sym_filter_entry);
480 return;
481 }
482
229 if (nr_counters == 1) 483 if (nr_counters == 1)
230 printf(" samples pcnt"); 484 printf(" samples pcnt");
231 else 485 else
232 printf(" weight samples pcnt"); 486 printf(" weight samples pcnt");
233 487
234 printf(" RIP kernel function\n" 488 if (verbose)
235 " ______ _______ _____ ________________ _______________\n\n" 489 printf(" RIP ");
236 ); 490 printf(" kernel function\n");
491 printf(" %s _______ _____",
492 nr_counters == 1 ? " " : "______");
493 if (verbose)
494 printf(" ________________");
495 printf(" _______________\n\n");
237 496
238 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 497 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
239 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); 498 struct symbol *sym;
240 struct symbol *sym = (struct symbol *)(syme + 1);
241 char *color = PERF_COLOR_NORMAL;
242 double pcnt; 499 double pcnt;
243 500
244 if (++printed > print_entries || syme->snap_count < count_filter) 501 syme = rb_entry(nd, struct sym_entry, rb_node);
502 sym = (struct symbol *)(syme + 1);
503
504 if (++printed > print_entries || (int)syme->snap_count < count_filter)
245 continue; 505 continue;
246 506
247 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 507 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
248 sum_ksamples)); 508 sum_ksamples));
249 509
250 /* 510 if (nr_counters == 1 || !display_weighted)
251 * We color high-overhead entries in red, mid-overhead
252 * entries in green - and keep the low overhead places
253 * normal:
254 */
255 if (pcnt >= 5.0) {
256 color = PERF_COLOR_RED;
257 } else {
258 if (pcnt >= 0.5)
259 color = PERF_COLOR_GREEN;
260 }
261
262 if (nr_counters == 1)
263 printf("%20.2f - ", syme->weight); 511 printf("%20.2f - ", syme->weight);
264 else 512 else
265 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 513 printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
266 514
267 color_fprintf(stdout, color, "%4.1f%%", pcnt); 515 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
268 printf(" - %016llx : %s\n", sym->start, sym->name); 516 if (verbose)
517 printf(" - %016llx", sym->start);
518 printf(" : %s", sym->name);
519 if (sym->module)
520 printf("\t[%s]", sym->module->name);
521 printf("\n");
269 } 522 }
270} 523}
271 524
272static void *display_thread(void *arg) 525static void prompt_integer(int *target, const char *msg)
526{
527 char *buf = malloc(0), *p;
528 size_t dummy = 0;
529 int tmp;
530
531 fprintf(stdout, "\n%s: ", msg);
532 if (getline(&buf, &dummy, stdin) < 0)
533 return;
534
535 p = strchr(buf, '\n');
536 if (p)
537 *p = 0;
538
539 p = buf;
540 while(*p) {
541 if (!isdigit(*p))
542 goto out_free;
543 p++;
544 }
545 tmp = strtoul(buf, NULL, 10);
546 *target = tmp;
547out_free:
548 free(buf);
549}
550
551static void prompt_percent(int *target, const char *msg)
552{
553 int tmp = 0;
554
555 prompt_integer(&tmp, msg);
556 if (tmp >= 0 && tmp <= 100)
557 *target = tmp;
558}
559
560static void prompt_symbol(struct sym_entry **target, const char *msg)
561{
562 char *buf = malloc(0), *p;
563 struct sym_entry *syme = *target, *n, *found = NULL;
564 size_t dummy = 0;
565
566 /* zero counters of active symbol */
567 if (syme) {
568 pthread_mutex_lock(&syme->source_lock);
569 __zero_source_counters(syme);
570 *target = NULL;
571 pthread_mutex_unlock(&syme->source_lock);
572 }
573
574 fprintf(stdout, "\n%s: ", msg);
575 if (getline(&buf, &dummy, stdin) < 0)
576 goto out_free;
577
578 p = strchr(buf, '\n');
579 if (p)
580 *p = 0;
581
582 pthread_mutex_lock(&active_symbols_lock);
583 syme = list_entry(active_symbols.next, struct sym_entry, node);
584 pthread_mutex_unlock(&active_symbols_lock);
585
586 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
587 struct symbol *sym = (struct symbol *)(syme + 1);
588
589 if (!strcmp(buf, sym->name)) {
590 found = syme;
591 break;
592 }
593 }
594
595 if (!found) {
596 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter);
597 sleep(1);
598 return;
599 } else
600 parse_source(found);
601
602out_free:
603 free(buf);
604}
605
606static void print_mapped_keys(void)
607{
608 char *name = NULL;
609
610 if (sym_filter_entry) {
611 struct symbol *sym = (struct symbol *)(sym_filter_entry+1);
612 name = sym->name;
613 }
614
615 fprintf(stdout, "\nMapped keys:\n");
616 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs);
617 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries);
618
619 if (nr_counters > 1)
620 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter));
621
622 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
623
624 if (vmlinux_name) {
625 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
626 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
627 fprintf(stdout, "\t[S] stop annotation.\n");
628 }
629
630 if (nr_counters > 1)
631 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
632
633 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0);
634 fprintf(stdout, "\t[qQ] quit.\n");
635}
636
637static int key_mapped(int c)
638{
639 switch (c) {
640 case 'd':
641 case 'e':
642 case 'f':
643 case 'z':
644 case 'q':
645 case 'Q':
646 return 1;
647 case 'E':
648 case 'w':
649 return nr_counters > 1 ? 1 : 0;
650 case 'F':
651 case 's':
652 case 'S':
653 return vmlinux_name ? 1 : 0;
654 default:
655 break;
656 }
657
658 return 0;
659}
660
661static void handle_keypress(int c)
662{
663 if (!key_mapped(c)) {
664 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
665 struct termios tc, save;
666
667 print_mapped_keys();
668 fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
669 fflush(stdout);
670
671 tcgetattr(0, &save);
672 tc = save;
673 tc.c_lflag &= ~(ICANON | ECHO);
674 tc.c_cc[VMIN] = 0;
675 tc.c_cc[VTIME] = 0;
676 tcsetattr(0, TCSANOW, &tc);
677
678 poll(&stdin_poll, 1, -1);
679 c = getc(stdin);
680
681 tcsetattr(0, TCSAFLUSH, &save);
682 if (!key_mapped(c))
683 return;
684 }
685
686 switch (c) {
687 case 'd':
688 prompt_integer(&delay_secs, "Enter display delay");
689 break;
690 case 'e':
691 prompt_integer(&print_entries, "Enter display entries (lines)");
692 break;
693 case 'E':
694 if (nr_counters > 1) {
695 int i;
696
697 fprintf(stderr, "\nAvailable events:");
698 for (i = 0; i < nr_counters; i++)
699 fprintf(stderr, "\n\t%d %s", i, event_name(i));
700
701 prompt_integer(&sym_counter, "Enter details event counter");
702
703 if (sym_counter >= nr_counters) {
704 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0));
705 sym_counter = 0;
706 sleep(1);
707 }
708 } else sym_counter = 0;
709 break;
710 case 'f':
711 prompt_integer(&count_filter, "Enter display event count filter");
712 break;
713 case 'F':
714 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
715 break;
716 case 'q':
717 case 'Q':
718 printf("exiting.\n");
719 exit(0);
720 case 's':
721 prompt_symbol(&sym_filter_entry, "Enter details symbol");
722 break;
723 case 'S':
724 if (!sym_filter_entry)
725 break;
726 else {
727 struct sym_entry *syme = sym_filter_entry;
728
729 pthread_mutex_lock(&syme->source_lock);
730 sym_filter_entry = NULL;
731 __zero_source_counters(syme);
732 pthread_mutex_unlock(&syme->source_lock);
733 }
734 break;
735 case 'w':
736 display_weighted = ~display_weighted;
737 break;
738 case 'z':
739 zero = ~zero;
740 break;
741 default:
742 break;
743 }
744}
745
746static void *display_thread(void *arg __used)
273{ 747{
274 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 748 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
275 int delay_msecs = delay_secs * 1000; 749 struct termios tc, save;
750 int delay_msecs, c;
276 751
277 printf("PerfTop refresh period: %d seconds\n", delay_secs); 752 tcgetattr(0, &save);
753 tc = save;
754 tc.c_lflag &= ~(ICANON | ECHO);
755 tc.c_cc[VMIN] = 0;
756 tc.c_cc[VTIME] = 0;
757
758repeat:
759 delay_msecs = delay_secs * 1000;
760 tcsetattr(0, TCSANOW, &tc);
761 /* trash return*/
762 getc(stdin);
278 763
279 do { 764 do {
280 print_sym_table(); 765 print_sym_table();
281 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 766 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
282 767
283 printf("key pressed - exiting.\n"); 768 c = getc(stdin);
284 exit(0); 769 tcsetattr(0, TCSAFLUSH, &save);
770
771 handle_keypress(c);
772 goto repeat;
285 773
286 return NULL; 774 return NULL;
287} 775}
288 776
777/* Tag samples to be skipped. */
778static const char *skip_symbols[] = {
779 "default_idle",
780 "cpu_idle",
781 "enter_idle",
782 "exit_idle",
783 "mwait_idle",
784 "mwait_idle_with_hints",
785 "ppc64_runlatch_off",
786 "pseries_dedicated_idle_sleep",
787 NULL
788};
789
289static int symbol_filter(struct dso *self, struct symbol *sym) 790static int symbol_filter(struct dso *self, struct symbol *sym)
290{ 791{
291 static int filter_match;
292 struct sym_entry *syme; 792 struct sym_entry *syme;
293 const char *name = sym->name; 793 const char *name = sym->name;
794 int i;
795
796 /*
797 * ppc64 uses function descriptors and appends a '.' to the
798 * start of every instruction address. Remove it.
799 */
800 if (name[0] == '.')
801 name++;
294 802
295 if (!strcmp(name, "_text") || 803 if (!strcmp(name, "_text") ||
296 !strcmp(name, "_etext") || 804 !strcmp(name, "_etext") ||
@@ -302,37 +810,17 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
302 return 1; 810 return 1;
303 811
304 syme = dso__sym_priv(self, sym); 812 syme = dso__sym_priv(self, sym);
305 /* Tag samples to be skipped. */ 813 pthread_mutex_init(&syme->source_lock, NULL);
306 if (!strcmp("default_idle", name) || 814 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
307 !strcmp("cpu_idle", name) || 815 sym_filter_entry = syme;
308 !strcmp("enter_idle", name) || 816
309 !strcmp("exit_idle", name) || 817 for (i = 0; skip_symbols[i]; i++) {
310 !strcmp("mwait_idle", name)) 818 if (!strcmp(skip_symbols[i], name)) {
311 syme->skip = 1; 819 syme->skip = 1;
312 820 break;
313 if (filter_match == 1) {
314 filter_end = sym->start;
315 filter_match = -1;
316 if (filter_end - filter_start > 10000) {
317 fprintf(stderr,
318 "hm, too large filter symbol <%s> - skipping.\n",
319 sym_filter);
320 fprintf(stderr, "symbol filter start: %016lx\n",
321 filter_start);
322 fprintf(stderr, " end: %016lx\n",
323 filter_end);
324 filter_end = filter_start = 0;
325 sym_filter = NULL;
326 sleep(1);
327 } 821 }
328 } 822 }
329 823
330 if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) {
331 filter_match = 1;
332 filter_start = sym->start;
333 }
334
335
336 return 0; 824 return 0;
337} 825}
338 826
@@ -340,12 +828,13 @@ static int parse_symbols(void)
340{ 828{
341 struct rb_node *node; 829 struct rb_node *node;
342 struct symbol *sym; 830 struct symbol *sym;
831 int use_modules = vmlinux_name ? 1 : 0;
343 832
344 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); 833 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
345 if (kernel_dso == NULL) 834 if (kernel_dso == NULL)
346 return -1; 835 return -1;
347 836
348 if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0) 837 if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
349 goto out_delete_dso; 838 goto out_delete_dso;
350 839
351 node = rb_first(&kernel_dso->syms); 840 node = rb_first(&kernel_dso->syms);
@@ -367,8 +856,6 @@ out_delete_dso:
367 return -1; 856 return -1;
368} 857}
369 858
370#define TRACE_COUNT 3
371
372/* 859/*
373 * Binary search in the histogram table and record the hit: 860 * Binary search in the histogram table and record the hit:
374 */ 861 */
@@ -381,6 +868,7 @@ static void record_ip(u64 ip, int counter)
381 868
382 if (!syme->skip) { 869 if (!syme->skip) {
383 syme->count[counter]++; 870 syme->count[counter]++;
871 record_precise_ip(syme, counter, ip);
384 pthread_mutex_lock(&active_symbols_lock); 872 pthread_mutex_lock(&active_symbols_lock);
385 if (list_empty(&syme->node) || !syme->node.next) 873 if (list_empty(&syme->node) || !syme->node.next)
386 __list_insert_active_sym(syme); 874 __list_insert_active_sym(syme);
@@ -392,11 +880,11 @@ static void record_ip(u64 ip, int counter)
392 samples--; 880 samples--;
393} 881}
394 882
395static void process_event(u64 ip, int counter) 883static void process_event(u64 ip, int counter, int user)
396{ 884{
397 samples++; 885 samples++;
398 886
399 if (ip < min_ip || ip > max_ip) { 887 if (user) {
400 userspace_samples++; 888 userspace_samples++;
401 return; 889 return;
402 } 890 }
@@ -407,13 +895,13 @@ static void process_event(u64 ip, int counter)
407struct mmap_data { 895struct mmap_data {
408 int counter; 896 int counter;
409 void *base; 897 void *base;
410 unsigned int mask; 898 int mask;
411 unsigned int prev; 899 unsigned int prev;
412}; 900};
413 901
414static unsigned int mmap_read_head(struct mmap_data *md) 902static unsigned int mmap_read_head(struct mmap_data *md)
415{ 903{
416 struct perf_counter_mmap_page *pc = md->base; 904 struct perf_event_mmap_page *pc = md->base;
417 int head; 905 int head;
418 906
419 head = pc->data_head; 907 head = pc->data_head;
@@ -461,26 +949,6 @@ static void mmap_read_counter(struct mmap_data *md)
461 last_read = this_read; 949 last_read = this_read;
462 950
463 for (; old != head;) { 951 for (; old != head;) {
464 struct ip_event {
465 struct perf_event_header header;
466 u64 ip;
467 u32 pid, target_pid;
468 };
469 struct mmap_event {
470 struct perf_event_header header;
471 u32 pid, target_pid;
472 u64 start;
473 u64 len;
474 u64 pgoff;
475 char filename[PATH_MAX];
476 };
477
478 typedef union event_union {
479 struct perf_event_header header;
480 struct ip_event ip;
481 struct mmap_event mmap;
482 } event_t;
483
484 event_t *event = (event_t *)&data[old & md->mask]; 952 event_t *event = (event_t *)&data[old & md->mask];
485 953
486 event_t event_copy; 954 event_t event_copy;
@@ -509,9 +977,10 @@ static void mmap_read_counter(struct mmap_data *md)
509 977
510 old += size; 978 old += size;
511 979
512 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) { 980 if (event->header.type == PERF_RECORD_SAMPLE) {
513 if (event->header.type & PERF_SAMPLE_IP) 981 int user =
514 process_event(event->ip.ip, md->counter); 982 (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
983 process_event(event->ip.ip, md->counter, user);
515 } 984 }
516 } 985 }
517 986
@@ -536,8 +1005,8 @@ int group_fd;
536 1005
537static void start_counter(int i, int counter) 1006static void start_counter(int i, int counter)
538{ 1007{
539 struct perf_counter_attr *attr; 1008 struct perf_event_attr *attr;
540 unsigned int cpu; 1009 int cpu;
541 1010
542 cpu = profile_cpu; 1011 cpu = profile_cpu;
543 if (target_pid == -1 && profile_cpu == -1) 1012 if (target_pid == -1 && profile_cpu == -1)
@@ -547,9 +1016,10 @@ static void start_counter(int i, int counter)
547 1016
548 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1017 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
549 attr->freq = freq; 1018 attr->freq = freq;
1019 attr->inherit = (cpu < 0) && inherit;
550 1020
551try_again: 1021try_again:
552 fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0); 1022 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
553 1023
554 if (fd[i][counter] < 0) { 1024 if (fd[i][counter] < 0) {
555 int err = errno; 1025 int err = errno;
@@ -574,7 +1044,7 @@ try_again:
574 printf("\n"); 1044 printf("\n");
575 error("perfcounter syscall returned with %d (%s)\n", 1045 error("perfcounter syscall returned with %d (%s)\n",
576 fd[i][counter], strerror(err)); 1046 fd[i][counter], strerror(err));
577 die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n"); 1047 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
578 exit(-1); 1048 exit(-1);
579 } 1049 }
580 assert(fd[i][counter] >= 0); 1050 assert(fd[i][counter] >= 0);
@@ -660,6 +1130,7 @@ static const struct option options[] = {
660 "system-wide collection from all CPUs"), 1130 "system-wide collection from all CPUs"),
661 OPT_INTEGER('C', "CPU", &profile_cpu, 1131 OPT_INTEGER('C', "CPU", &profile_cpu,
662 "CPU to profile on"), 1132 "CPU to profile on"),
1133 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
663 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1134 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
664 "number of mmap data pages"), 1135 "number of mmap data pages"),
665 OPT_INTEGER('r', "realtime", &realtime_prio, 1136 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -672,9 +1143,11 @@ static const struct option options[] = {
672 "only display functions with more events than this"), 1143 "only display functions with more events than this"),
673 OPT_BOOLEAN('g', "group", &group, 1144 OPT_BOOLEAN('g', "group", &group,
674 "put the counters into a counter group"), 1145 "put the counters into a counter group"),
675 OPT_STRING('s', "sym-filter", &sym_filter, "pattern", 1146 OPT_BOOLEAN('i', "inherit", &inherit,
676 "only display symbols matchig this pattern"), 1147 "child tasks inherit counters"),
677 OPT_BOOLEAN('z', "zero", &group, 1148 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1149 "symbol to annotate - requires -k option"),
1150 OPT_BOOLEAN('z', "zero", &zero,
678 "zero history across updates"), 1151 "zero history across updates"),
679 OPT_INTEGER('F', "freq", &freq, 1152 OPT_INTEGER('F', "freq", &freq,
680 "profile at this frequency"), 1153 "profile at this frequency"),
@@ -685,10 +1158,12 @@ static const struct option options[] = {
685 OPT_END() 1158 OPT_END()
686}; 1159};
687 1160
688int cmd_top(int argc, const char **argv, const char *prefix) 1161int cmd_top(int argc, const char **argv, const char *prefix __used)
689{ 1162{
690 int counter; 1163 int counter;
691 1164
1165 symbol__init();
1166
692 page_size = sysconf(_SC_PAGE_SIZE); 1167 page_size = sysconf(_SC_PAGE_SIZE);
693 1168
694 argc = parse_options(argc, argv, options, top_usage, 0); 1169 argc = parse_options(argc, argv, options, top_usage, 0);
@@ -714,6 +1189,7 @@ int cmd_top(int argc, const char **argv, const char *prefix)
714 delay_secs = 1; 1189 delay_secs = 1;
715 1190
716 parse_symbols(); 1191 parse_symbols();
1192 parse_source(sym_filter_entry);
717 1193
718 /* 1194 /*
719 * Fill in the ones not specifically initialized via -c: 1195 * Fill in the ones not specifically initialized via -c:
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
new file mode 100644
index 000000000000..e9d256e2f47d
--- /dev/null
+++ b/tools/perf/builtin-trace.c
@@ -0,0 +1,297 @@
1#include "builtin.h"
2
3#include "util/util.h"
4#include "util/cache.h"
5#include "util/symbol.h"
6#include "util/thread.h"
7#include "util/header.h"
8
9#include "util/parse-options.h"
10
11#include "perf.h"
12#include "util/debug.h"
13
14#include "util/trace-event.h"
15
16static char const *input_name = "perf.data";
17static int input;
18static unsigned long page_size;
19static unsigned long mmap_window = 32;
20
21static unsigned long total = 0;
22static unsigned long total_comm = 0;
23
24static struct rb_root threads;
25static struct thread *last_match;
26
27static struct perf_header *header;
28static u64 sample_type;
29
30
31static int
32process_comm_event(event_t *event, unsigned long offset, unsigned long head)
33{
34 struct thread *thread;
35
36 thread = threads__findnew(event->comm.pid, &threads, &last_match);
37
38 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
39 (void *)(offset + head),
40 (void *)(long)(event->header.size),
41 event->comm.comm, event->comm.pid);
42
43 if (thread == NULL ||
44 thread__set_comm(thread, event->comm.comm)) {
45 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
46 return -1;
47 }
48 total_comm++;
49
50 return 0;
51}
52
53static int
54process_sample_event(event_t *event, unsigned long offset, unsigned long head)
55{
56 char level;
57 int show = 0;
58 struct dso *dso = NULL;
59 struct thread *thread;
60 u64 ip = event->ip.ip;
61 u64 timestamp = -1;
62 u32 cpu = -1;
63 u64 period = 1;
64 void *more_data = event->ip.__more_data;
65 int cpumode;
66
67 thread = threads__findnew(event->ip.pid, &threads, &last_match);
68
69 if (sample_type & PERF_SAMPLE_TIME) {
70 timestamp = *(u64 *)more_data;
71 more_data += sizeof(u64);
72 }
73
74 if (sample_type & PERF_SAMPLE_CPU) {
75 cpu = *(u32 *)more_data;
76 more_data += sizeof(u32);
77 more_data += sizeof(u32); /* reserved */
78 }
79
80 if (sample_type & PERF_SAMPLE_PERIOD) {
81 period = *(u64 *)more_data;
82 more_data += sizeof(u64);
83 }
84
85 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
86 (void *)(offset + head),
87 (void *)(long)(event->header.size),
88 event->header.misc,
89 event->ip.pid, event->ip.tid,
90 (void *)(long)ip,
91 (long long)period);
92
93 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
94
95 if (thread == NULL) {
96 eprintf("problem processing %d event, skipping it.\n",
97 event->header.type);
98 return -1;
99 }
100
101 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
102
103 if (cpumode == PERF_RECORD_MISC_KERNEL) {
104 show = SHOW_KERNEL;
105 level = 'k';
106
107 dso = kernel_dso;
108
109 dump_printf(" ...... dso: %s\n", dso->name);
110
111 } else if (cpumode == PERF_RECORD_MISC_USER) {
112
113 show = SHOW_USER;
114 level = '.';
115
116 } else {
117 show = SHOW_HV;
118 level = 'H';
119
120 dso = hypervisor_dso;
121
122 dump_printf(" ...... dso: [hypervisor]\n");
123 }
124
125 if (sample_type & PERF_SAMPLE_RAW) {
126 struct {
127 u32 size;
128 char data[0];
129 } *raw = more_data;
130
131 /*
132 * FIXME: better resolve from pid from the struct trace_entry
133 * field, although it should be the same than this perf
134 * event pid
135 */
136 print_event(cpu, raw->data, raw->size, timestamp, thread->comm);
137 }
138 total += period;
139
140 return 0;
141}
142
143static int
144process_event(event_t *event, unsigned long offset, unsigned long head)
145{
146 trace_event(event);
147
148 switch (event->header.type) {
149 case PERF_RECORD_MMAP ... PERF_RECORD_LOST:
150 return 0;
151
152 case PERF_RECORD_COMM:
153 return process_comm_event(event, offset, head);
154
155 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
156 return 0;
157
158 case PERF_RECORD_SAMPLE:
159 return process_sample_event(event, offset, head);
160
161 case PERF_RECORD_MAX:
162 default:
163 return -1;
164 }
165
166 return 0;
167}
168
169static int __cmd_trace(void)
170{
171 int ret, rc = EXIT_FAILURE;
172 unsigned long offset = 0;
173 unsigned long head = 0;
174 struct stat perf_stat;
175 event_t *event;
176 uint32_t size;
177 char *buf;
178
179 trace_report();
180 register_idle_thread(&threads, &last_match);
181
182 input = open(input_name, O_RDONLY);
183 if (input < 0) {
184 perror("failed to open file");
185 exit(-1);
186 }
187
188 ret = fstat(input, &perf_stat);
189 if (ret < 0) {
190 perror("failed to stat file");
191 exit(-1);
192 }
193
194 if (!perf_stat.st_size) {
195 fprintf(stderr, "zero-sized file, nothing to do!\n");
196 exit(0);
197 }
198 header = perf_header__read(input);
199 head = header->data_offset;
200 sample_type = perf_header__sample_type(header);
201
202 if (!(sample_type & PERF_SAMPLE_RAW))
203 die("No trace sample to read. Did you call perf record "
204 "without -R?");
205
206 if (load_kernel() < 0) {
207 perror("failed to load kernel symbols");
208 return EXIT_FAILURE;
209 }
210
211remap:
212 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
213 MAP_SHARED, input, offset);
214 if (buf == MAP_FAILED) {
215 perror("failed to mmap file");
216 exit(-1);
217 }
218
219more:
220 event = (event_t *)(buf + head);
221
222 size = event->header.size;
223 if (!size)
224 size = 8;
225
226 if (head + event->header.size >= page_size * mmap_window) {
227 unsigned long shift = page_size * (head / page_size);
228 int res;
229
230 res = munmap(buf, page_size * mmap_window);
231 assert(res == 0);
232
233 offset += shift;
234 head -= shift;
235 goto remap;
236 }
237
238 size = event->header.size;
239
240
241 if (!size || process_event(event, offset, head) < 0) {
242
243 /*
244 * assume we lost track of the stream, check alignment, and
245 * increment a single u64 in the hope to catch on again 'soon'.
246 */
247
248 if (unlikely(head & 7))
249 head &= ~7ULL;
250
251 size = 8;
252 }
253
254 head += size;
255
256 if (offset + head < (unsigned long)perf_stat.st_size)
257 goto more;
258
259 rc = EXIT_SUCCESS;
260 close(input);
261
262 return rc;
263}
264
265static const char * const annotate_usage[] = {
266 "perf trace [<options>] <command>",
267 NULL
268};
269
270static const struct option options[] = {
271 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
272 "dump raw trace in ASCII"),
273 OPT_BOOLEAN('v', "verbose", &verbose,
274 "be more verbose (show symbol address, etc)"),
275 OPT_END()
276};
277
278int cmd_trace(int argc, const char **argv, const char *prefix __used)
279{
280 symbol__init();
281 page_size = getpagesize();
282
283 argc = parse_options(argc, argv, options, annotate_usage, 0);
284 if (argc) {
285 /*
286 * Special case: if there's an argument left then assume tha
287 * it's a symbol filter:
288 */
289 if (argc > 1)
290 usage_with_options(annotate_usage, options);
291 }
292
293
294 setup_pager();
295
296 return __cmd_trace();
297}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 51d168230ee7..e11d8d231c3b 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -16,11 +16,14 @@ extern int check_pager_config(const char *cmd);
16 16
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_help(int argc, const char **argv, const char *prefix); 18extern int cmd_help(int argc, const char **argv, const char *prefix);
19extern int cmd_sched(int argc, const char **argv, const char *prefix);
20extern int cmd_list(int argc, const char **argv, const char *prefix);
19extern int cmd_record(int argc, const char **argv, const char *prefix); 21extern int cmd_record(int argc, const char **argv, const char *prefix);
20extern int cmd_report(int argc, const char **argv, const char *prefix); 22extern int cmd_report(int argc, const char **argv, const char *prefix);
21extern int cmd_stat(int argc, const char **argv, const char *prefix); 23extern int cmd_stat(int argc, const char **argv, const char *prefix);
24extern int cmd_timechart(int argc, const char **argv, const char *prefix);
22extern int cmd_top(int argc, const char **argv, const char *prefix); 25extern int cmd_top(int argc, const char **argv, const char *prefix);
26extern int cmd_trace(int argc, const char **argv, const char *prefix);
23extern int cmd_version(int argc, const char **argv, const char *prefix); 27extern int cmd_version(int argc, const char **argv, const char *prefix);
24extern int cmd_list(int argc, const char **argv, const char *prefix);
25 28
26#endif 29#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index eebce30afbc0..00326e230d87 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -4,7 +4,10 @@
4# 4#
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-list mainporcelain common 6perf-list mainporcelain common
7perf-sched mainporcelain common
7perf-record mainporcelain common 8perf-record mainporcelain common
8perf-report mainporcelain common 9perf-report mainporcelain common
9perf-stat mainporcelain common 10perf-stat mainporcelain common
11perf-timechart mainporcelain common
10perf-top mainporcelain common 12perf-top mainporcelain common
13perf-trace mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index f71e0d245cba..f1946d107b10 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -18,10 +18,10 @@ underlying hardware counters.
18Performance counters are accessed via special file descriptors. 18Performance counters are accessed via special file descriptors.
19There's one file descriptor per virtual counter used. 19There's one file descriptor per virtual counter used.
20 20
21The special file descriptor is opened via the perf_counter_open() 21The special file descriptor is opened via the perf_event_open()
22system call: 22system call:
23 23
24 int sys_perf_counter_open(struct perf_counter_hw_event *hw_event_uptr, 24 int sys_perf_event_open(struct perf_event_hw_event *hw_event_uptr,
25 pid_t pid, int cpu, int group_fd, 25 pid_t pid, int cpu, int group_fd,
26 unsigned long flags); 26 unsigned long flags);
27 27
@@ -32,9 +32,9 @@ can be used to set the blocking mode, etc.
32Multiple counters can be kept open at a time, and the counters 32Multiple counters can be kept open at a time, and the counters
33can be poll()ed. 33can be poll()ed.
34 34
35When creating a new counter fd, 'perf_counter_hw_event' is: 35When creating a new counter fd, 'perf_event_hw_event' is:
36 36
37struct perf_counter_hw_event { 37struct perf_event_hw_event {
38 /* 38 /*
39 * The MSB of the config word signifies if the rest contains cpu 39 * The MSB of the config word signifies if the rest contains cpu
40 * specific (raw) counter configuration data, if unset, the next 40 * specific (raw) counter configuration data, if unset, the next
@@ -93,7 +93,7 @@ specified by 'event_id':
93 93
94/* 94/*
95 * Generalized performance counter event types, used by the hw_event.event_id 95 * Generalized performance counter event types, used by the hw_event.event_id
96 * parameter of the sys_perf_counter_open() syscall: 96 * parameter of the sys_perf_event_open() syscall:
97 */ 97 */
98enum hw_event_ids { 98enum hw_event_ids {
99 /* 99 /*
@@ -159,7 +159,7 @@ in size.
159 * reads on the counter should return the indicated quantities, 159 * reads on the counter should return the indicated quantities,
160 * in increasing order of bit value, after the counter value. 160 * in increasing order of bit value, after the counter value.
161 */ 161 */
162enum perf_counter_read_format { 162enum perf_event_read_format {
163 PERF_FORMAT_TOTAL_TIME_ENABLED = 1, 163 PERF_FORMAT_TOTAL_TIME_ENABLED = 1,
164 PERF_FORMAT_TOTAL_TIME_RUNNING = 2, 164 PERF_FORMAT_TOTAL_TIME_RUNNING = 2,
165}; 165};
@@ -178,7 +178,7 @@ interrupt:
178 * Bits that can be set in hw_event.record_type to request information 178 * Bits that can be set in hw_event.record_type to request information
179 * in the overflow packets. 179 * in the overflow packets.
180 */ 180 */
181enum perf_counter_record_format { 181enum perf_event_record_format {
182 PERF_RECORD_IP = 1U << 0, 182 PERF_RECORD_IP = 1U << 0,
183 PERF_RECORD_TID = 1U << 1, 183 PERF_RECORD_TID = 1U << 1,
184 PERF_RECORD_TIME = 1U << 2, 184 PERF_RECORD_TIME = 1U << 2,
@@ -228,7 +228,7 @@ these events are recorded in the ring-buffer (see below).
228The 'comm' bit allows tracking of process comm data on process creation. 228The 'comm' bit allows tracking of process comm data on process creation.
229This too is recorded in the ring-buffer (see below). 229This too is recorded in the ring-buffer (see below).
230 230
231The 'pid' parameter to the perf_counter_open() system call allows the 231The 'pid' parameter to the perf_event_open() system call allows the
232counter to be specific to a task: 232counter to be specific to a task:
233 233
234 pid == 0: if the pid parameter is zero, the counter is attached to the 234 pid == 0: if the pid parameter is zero, the counter is attached to the
@@ -258,7 +258,7 @@ The 'flags' parameter is currently unused and must be zero.
258 258
259The 'group_fd' parameter allows counter "groups" to be set up. A 259The 'group_fd' parameter allows counter "groups" to be set up. A
260counter group has one counter which is the group "leader". The leader 260counter group has one counter which is the group "leader". The leader
261is created first, with group_fd = -1 in the perf_counter_open call 261is created first, with group_fd = -1 in the perf_event_open call
262that creates it. The rest of the group members are created 262that creates it. The rest of the group members are created
263subsequently, with group_fd giving the fd of the group leader. 263subsequently, with group_fd giving the fd of the group leader.
264(A single counter on its own is created with group_fd = -1 and is 264(A single counter on its own is created with group_fd = -1 and is
@@ -277,13 +277,13 @@ tracking are logged into a ring-buffer. This ring-buffer is created and
277accessed through mmap(). 277accessed through mmap().
278 278
279The mmap size should be 1+2^n pages, where the first page is a meta-data page 279The mmap size should be 1+2^n pages, where the first page is a meta-data page
280(struct perf_counter_mmap_page) that contains various bits of information such 280(struct perf_event_mmap_page) that contains various bits of information such
281as where the ring-buffer head is. 281as where the ring-buffer head is.
282 282
283/* 283/*
284 * Structure of the page that can be mapped via mmap 284 * Structure of the page that can be mapped via mmap
285 */ 285 */
286struct perf_counter_mmap_page { 286struct perf_event_mmap_page {
287 __u32 version; /* version number of this structure */ 287 __u32 version; /* version number of this structure */
288 __u32 compat_version; /* lowest version this is compat with */ 288 __u32 compat_version; /* lowest version this is compat with */
289 289
@@ -317,7 +317,7 @@ struct perf_counter_mmap_page {
317 * Control data for the mmap() data buffer. 317 * Control data for the mmap() data buffer.
318 * 318 *
319 * User-space reading this value should issue an rmb(), on SMP capable 319 * User-space reading this value should issue an rmb(), on SMP capable
320 * platforms, after reading this value -- see perf_counter_wakeup(). 320 * platforms, after reading this value -- see perf_event_wakeup().
321 */ 321 */
322 __u32 data_head; /* head in the data section */ 322 __u32 data_head; /* head in the data section */
323}; 323};
@@ -327,9 +327,9 @@ NOTE: the hw-counter userspace bits are arch specific and are currently only
327 327
328The following 2^n pages are the ring-buffer which contains events of the form: 328The following 2^n pages are the ring-buffer which contains events of the form:
329 329
330#define PERF_EVENT_MISC_KERNEL (1 << 0) 330#define PERF_RECORD_MISC_KERNEL (1 << 0)
331#define PERF_EVENT_MISC_USER (1 << 1) 331#define PERF_RECORD_MISC_USER (1 << 1)
332#define PERF_EVENT_MISC_OVERFLOW (1 << 2) 332#define PERF_RECORD_MISC_OVERFLOW (1 << 2)
333 333
334struct perf_event_header { 334struct perf_event_header {
335 __u32 type; 335 __u32 type;
@@ -353,8 +353,8 @@ enum perf_event_type {
353 * char filename[]; 353 * char filename[];
354 * }; 354 * };
355 */ 355 */
356 PERF_EVENT_MMAP = 1, 356 PERF_RECORD_MMAP = 1,
357 PERF_EVENT_MUNMAP = 2, 357 PERF_RECORD_MUNMAP = 2,
358 358
359 /* 359 /*
360 * struct { 360 * struct {
@@ -364,10 +364,10 @@ enum perf_event_type {
364 * char comm[]; 364 * char comm[];
365 * }; 365 * };
366 */ 366 */
367 PERF_EVENT_COMM = 3, 367 PERF_RECORD_COMM = 3,
368 368
369 /* 369 /*
370 * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field 370 * When header.misc & PERF_RECORD_MISC_OVERFLOW the event_type field
371 * will be PERF_RECORD_* 371 * will be PERF_RECORD_*
372 * 372 *
373 * struct { 373 * struct {
@@ -397,7 +397,7 @@ Notification of new events is possible through poll()/select()/epoll() and
397fcntl() managing signals. 397fcntl() managing signals.
398 398
399Normally a notification is generated for every page filled, however one can 399Normally a notification is generated for every page filled, however one can
400additionally set perf_counter_hw_event.wakeup_events to generate one every 400additionally set perf_event_hw_event.wakeup_events to generate one every
401so many counter overflow events. 401so many counter overflow events.
402 402
403Future work will include a splice() interface to the ring-buffer. 403Future work will include a splice() interface to the ring-buffer.
@@ -409,11 +409,11 @@ events but does continue to exist and maintain its count value.
409 409
410An individual counter or counter group can be enabled with 410An individual counter or counter group can be enabled with
411 411
412 ioctl(fd, PERF_COUNTER_IOC_ENABLE); 412 ioctl(fd, PERF_EVENT_IOC_ENABLE);
413 413
414or disabled with 414or disabled with
415 415
416 ioctl(fd, PERF_COUNTER_IOC_DISABLE); 416 ioctl(fd, PERF_EVENT_IOC_DISABLE);
417 417
418Enabling or disabling the leader of a group enables or disables the 418Enabling or disabling the leader of a group enables or disables the
419whole group; that is, while the group leader is disabled, none of the 419whole group; that is, while the group leader is disabled, none of the
@@ -424,16 +424,16 @@ other counter.
424 424
425Additionally, non-inherited overflow counters can use 425Additionally, non-inherited overflow counters can use
426 426
427 ioctl(fd, PERF_COUNTER_IOC_REFRESH, nr); 427 ioctl(fd, PERF_EVENT_IOC_REFRESH, nr);
428 428
429to enable a counter for 'nr' events, after which it gets disabled again. 429to enable a counter for 'nr' events, after which it gets disabled again.
430 430
431A process can enable or disable all the counter groups that are 431A process can enable or disable all the counter groups that are
432attached to it, using prctl: 432attached to it, using prctl:
433 433
434 prctl(PR_TASK_PERF_COUNTERS_ENABLE); 434 prctl(PR_TASK_PERF_EVENTS_ENABLE);
435 435
436 prctl(PR_TASK_PERF_COUNTERS_DISABLE); 436 prctl(PR_TASK_PERF_EVENTS_DISABLE);
437 437
438This applies to all counters on the current process, whether created 438This applies to all counters on the current process, whether created
439by this process or by another, and doesn't affect any counters that 439by this process or by another, and doesn't affect any counters that
@@ -447,11 +447,11 @@ Arch requirements
447If your architecture does not have hardware performance metrics, you can 447If your architecture does not have hardware performance metrics, you can
448still use the generic software counters based on hrtimers for sampling. 448still use the generic software counters based on hrtimers for sampling.
449 449
450So to start with, in order to add HAVE_PERF_COUNTERS to your Kconfig, you 450So to start with, in order to add HAVE_PERF_EVENTS to your Kconfig, you
451will need at least this: 451will need at least this:
452 - asm/perf_counter.h - a basic stub will suffice at first 452 - asm/perf_event.h - a basic stub will suffice at first
453 - support for atomic64 types (and associated helper functions) 453 - support for atomic64 types (and associated helper functions)
454 - set_perf_counter_pending() implemented 454 - set_perf_event_pending() implemented
455 455
456If your architecture does have hardware capabilities, you can override the 456If your architecture does have hardware capabilities, you can override the
457weak stub hw_perf_counter_init() to register hardware counters. 457weak stub hw_perf_event_init() to register hardware counters.
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 4eb725933703..19fc7feb9d59 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -12,6 +12,8 @@
12#include "util/cache.h" 12#include "util/cache.h"
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"
16#include "util/string.h"
15 17
16const char perf_usage_string[] = 18const char perf_usage_string[] =
17 "perf [--version] [--help] COMMAND [ARGS]"; 19 "perf [--version] [--help] COMMAND [ARGS]";
@@ -25,6 +27,8 @@ struct pager_config {
25 int val; 27 int val;
26}; 28};
27 29
30static char debugfs_mntpt[MAXPATHLEN];
31
28static int pager_command_config(const char *var, const char *value, void *data) 32static int pager_command_config(const char *var, const char *value, void *data)
29{ 33{
30 struct pager_config *c = data; 34 struct pager_config *c = data;
@@ -56,6 +60,15 @@ static void commit_pager_choice(void) {
56 } 60 }
57} 61}
58 62
63static void set_debugfs_path(void)
64{
65 char *path;
66
67 path = getenv(PERF_DEBUGFS_ENVIRONMENT);
68 snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt,
69 "tracing/events");
70}
71
59static int handle_options(const char*** argv, int* argc, int* envchanged) 72static int handle_options(const char*** argv, int* argc, int* envchanged)
60{ 73{
61 int handled = 0; 74 int handled = 0;
@@ -122,6 +135,22 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
122 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1); 135 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
123 if (envchanged) 136 if (envchanged)
124 *envchanged = 1; 137 *envchanged = 1;
138 } else if (!strcmp(cmd, "--debugfs-dir")) {
139 if (*argc < 2) {
140 fprintf(stderr, "No directory given for --debugfs-dir.\n");
141 usage(perf_usage_string);
142 }
143 strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN);
144 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
145 if (envchanged)
146 *envchanged = 1;
147 (*argv)++;
148 (*argc)--;
149 } else if (!prefixcmp(cmd, "--debugfs-dir=")) {
150 strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN);
151 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
152 if (envchanged)
153 *envchanged = 1;
125 } else { 154 } else {
126 fprintf(stderr, "Unknown option: %s\n", cmd); 155 fprintf(stderr, "Unknown option: %s\n", cmd);
127 usage(perf_usage_string); 156 usage(perf_usage_string);
@@ -228,9 +257,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
228 if (use_pager == -1 && p->option & USE_PAGER) 257 if (use_pager == -1 && p->option & USE_PAGER)
229 use_pager = 1; 258 use_pager = 1;
230 commit_pager_choice(); 259 commit_pager_choice();
231 260 set_debugfs_path();
232 if (p->option & NEED_WORK_TREE)
233 /* setup_work_tree() */;
234 261
235 status = p->fn(argc, argv, prefix); 262 status = p->fn(argc, argv, prefix);
236 if (status) 263 if (status)
@@ -262,11 +289,14 @@ static void handle_internal_command(int argc, const char **argv)
262 { "record", cmd_record, 0 }, 289 { "record", cmd_record, 0 },
263 { "report", cmd_report, 0 }, 290 { "report", cmd_report, 0 },
264 { "stat", cmd_stat, 0 }, 291 { "stat", cmd_stat, 0 },
292 { "timechart", cmd_timechart, 0 },
265 { "top", cmd_top, 0 }, 293 { "top", cmd_top, 0 },
266 { "annotate", cmd_annotate, 0 }, 294 { "annotate", cmd_annotate, 0 },
267 { "version", cmd_version, 0 }, 295 { "version", cmd_version, 0 },
296 { "trace", cmd_trace, 0 },
297 { "sched", cmd_sched, 0 },
268 }; 298 };
269 int i; 299 unsigned int i;
270 static const char ext[] = STRIP_EXTENSION; 300 static const char ext[] = STRIP_EXTENSION;
271 301
272 if (sizeof(ext) > 1) { 302 if (sizeof(ext) > 1) {
@@ -349,6 +379,49 @@ static int run_argv(int *argcp, const char ***argv)
349 return done_alias; 379 return done_alias;
350} 380}
351 381
382/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
383static void get_debugfs_mntpt(void)
384{
385 FILE *file;
386 char fs_type[100];
387 char debugfs[MAXPATHLEN];
388
389 /*
390 * try the standard location
391 */
392 if (valid_debugfs_mount("/sys/kernel/debug/") == 0) {
393 strcpy(debugfs_mntpt, "/sys/kernel/debug/");
394 return;
395 }
396
397 /*
398 * try the sane location
399 */
400 if (valid_debugfs_mount("/debug/") == 0) {
401 strcpy(debugfs_mntpt, "/debug/");
402 return;
403 }
404
405 /*
406 * give up and parse /proc/mounts
407 */
408 file = fopen("/proc/mounts", "r");
409 if (file == NULL)
410 return;
411
412 while (fscanf(file, "%*s %"
413 STR(MAXPATHLEN)
414 "s %99s %*s %*d %*d\n",
415 debugfs, fs_type) == 2) {
416 if (strcmp(fs_type, "debugfs") == 0)
417 break;
418 }
419 fclose(file);
420 if (strcmp(fs_type, "debugfs") == 0) {
421 strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
422 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
423 }
424}
352 425
353int main(int argc, const char **argv) 426int main(int argc, const char **argv)
354{ 427{
@@ -357,7 +430,8 @@ int main(int argc, const char **argv)
357 cmd = perf_extract_argv0_path(argv[0]); 430 cmd = perf_extract_argv0_path(argv[0]);
358 if (!cmd) 431 if (!cmd)
359 cmd = "perf-help"; 432 cmd = "perf-help";
360 433 /* get debugfs mount point from /proc/mounts */
434 get_debugfs_mntpt();
361 /* 435 /*
362 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 436 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
363 * 437 *
@@ -380,6 +454,7 @@ int main(int argc, const char **argv)
380 argc--; 454 argc--;
381 handle_options(&argv, &argc, NULL); 455 handle_options(&argv, &argc, NULL);
382 commit_pager_choice(); 456 commit_pager_choice();
457 set_debugfs_path();
383 if (argc > 0) { 458 if (argc > 0) {
384 if (!prefixcmp(argv[0], "--")) 459 if (!prefixcmp(argv[0], "--"))
385 argv[0] += 2; 460 argv[0] += 2;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index ceb68aa51f7f..8cc4623afd6f 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -1,7 +1,13 @@
1#ifndef _PERF_PERF_H 1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H 2#define _PERF_PERF_H
3 3
4#if defined(__x86_64__) || defined(__i386__) 4#if defined(__i386__)
5#include "../../arch/x86/include/asm/unistd.h"
6#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
7#define cpu_relax() asm volatile("rep; nop" ::: "memory");
8#endif
9
10#if defined(__x86_64__)
5#include "../../arch/x86/include/asm/unistd.h" 11#include "../../arch/x86/include/asm/unistd.h"
6#define rmb() asm volatile("lfence" ::: "memory") 12#define rmb() asm volatile("lfence" ::: "memory")
7#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 13#define cpu_relax() asm volatile("rep; nop" ::: "memory");
@@ -19,20 +25,42 @@
19#define cpu_relax() asm volatile("" ::: "memory"); 25#define cpu_relax() asm volatile("" ::: "memory");
20#endif 26#endif
21 27
28#ifdef __sh__
29#include "../../arch/sh/include/asm/unistd.h"
30#if defined(__SH4A__) || defined(__SH5__)
31# define rmb() asm volatile("synco" ::: "memory")
32#else
33# define rmb() asm volatile("" ::: "memory")
34#endif
35#define cpu_relax() asm volatile("" ::: "memory")
36#endif
37
38#ifdef __hppa__
39#include "../../arch/parisc/include/asm/unistd.h"
40#define rmb() asm volatile("" ::: "memory")
41#define cpu_relax() asm volatile("" ::: "memory");
42#endif
43
44#ifdef __sparc__
45#include "../../arch/sparc/include/asm/unistd.h"
46#define rmb() asm volatile("":::"memory")
47#define cpu_relax() asm volatile("":::"memory")
48#endif
49
22#include <time.h> 50#include <time.h>
23#include <unistd.h> 51#include <unistd.h>
24#include <sys/types.h> 52#include <sys/types.h>
25#include <sys/syscall.h> 53#include <sys/syscall.h>
26 54
27#include "../../include/linux/perf_counter.h" 55#include "../../include/linux/perf_event.h"
28#include "types.h" 56#include "util/types.h"
29 57
30/* 58/*
31 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all 59 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
32 * counters in the current task. 60 * counters in the current task.
33 */ 61 */
34#define PR_TASK_PERF_COUNTERS_DISABLE 31 62#define PR_TASK_PERF_EVENTS_DISABLE 31
35#define PR_TASK_PERF_COUNTERS_ENABLE 32 63#define PR_TASK_PERF_EVENTS_ENABLE 32
36 64
37#ifndef NSEC_PER_SEC 65#ifndef NSEC_PER_SEC
38# define NSEC_PER_SEC 1000000000ULL 66# define NSEC_PER_SEC 1000000000ULL
@@ -52,6 +80,8 @@ static inline unsigned long long rdclock(void)
52#define __user 80#define __user
53#define asmlinkage 81#define asmlinkage
54 82
83#define __used __attribute__((__unused__))
84
55#define unlikely(x) __builtin_expect(!!(x), 0) 85#define unlikely(x) __builtin_expect(!!(x), 0)
56#define min(x, y) ({ \ 86#define min(x, y) ({ \
57 typeof(x) _min1 = (x); \ 87 typeof(x) _min1 = (x); \
@@ -60,22 +90,21 @@ static inline unsigned long long rdclock(void)
60 _min1 < _min2 ? _min1 : _min2; }) 90 _min1 < _min2 ? _min1 : _min2; })
61 91
62static inline int 92static inline int
63sys_perf_counter_open(struct perf_counter_attr *attr, 93sys_perf_event_open(struct perf_event_attr *attr,
64 pid_t pid, int cpu, int group_fd, 94 pid_t pid, int cpu, int group_fd,
65 unsigned long flags) 95 unsigned long flags)
66{ 96{
67 attr->size = sizeof(*attr); 97 attr->size = sizeof(*attr);
68 return syscall(__NR_perf_counter_open, attr, pid, cpu, 98 return syscall(__NR_perf_event_open, attr, pid, cpu,
69 group_fd, flags); 99 group_fd, flags);
70} 100}
71 101
72#define MAX_COUNTERS 256 102#define MAX_COUNTERS 256
73#define MAX_NR_CPUS 256 103#define MAX_NR_CPUS 256
74 104
75struct perf_file_header { 105struct ip_callchain {
76 u64 version; 106 u64 nr;
77 u64 sample_type; 107 u64 ips[0];
78 u64 data_size;
79}; 108};
80 109
81#endif 110#endif
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
index 61d33b81fc97..a791dd467261 100644
--- a/tools/perf/util/abspath.c
+++ b/tools/perf/util/abspath.c
@@ -50,7 +50,8 @@ const char *make_absolute_path(const char *path)
50 die ("Could not get current working directory"); 50 die ("Could not get current working directory");
51 51
52 if (last_elem) { 52 if (last_elem) {
53 int len = strlen(buf); 53 len = strlen(buf);
54
54 if (len + strlen(last_elem) + 2 > PATH_MAX) 55 if (len + strlen(last_elem) + 2 > PATH_MAX)
55 die ("Too long path name: '%s/%s'", 56 die ("Too long path name: '%s/%s'",
56 buf, last_elem); 57 buf, last_elem);
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
index 9b3dd2b428df..b8144e80bb1e 100644
--- a/tools/perf/util/alias.c
+++ b/tools/perf/util/alias.c
@@ -3,7 +3,7 @@
3static const char *alias_key; 3static const char *alias_key;
4static char *alias_val; 4static char *alias_val;
5 5
6static int alias_lookup_cb(const char *k, const char *v, void *cb) 6static int alias_lookup_cb(const char *k, const char *v, void *cb __used)
7{ 7{
8 if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) { 8 if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
9 if (!v) 9 if (!v)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 393d6146d13b..6f8ea9d210b6 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -3,6 +3,7 @@
3 3
4#include "util.h" 4#include "util.h"
5#include "strbuf.h" 5#include "strbuf.h"
6#include "../perf.h"
6 7
7#define PERF_DIR_ENVIRONMENT "PERF_DIR" 8#define PERF_DIR_ENVIRONMENT "PERF_DIR"
8#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" 9#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
@@ -17,6 +18,7 @@
17#define PERFATTRIBUTES_FILE ".perfattributes" 18#define PERFATTRIBUTES_FILE ".perfattributes"
18#define INFOATTRIBUTES_FILE "info/attributes" 19#define INFOATTRIBUTES_FILE "info/attributes"
19#define ATTRIBUTE_MACRO_PREFIX "[attr]" 20#define ATTRIBUTE_MACRO_PREFIX "[attr]"
21#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
20 22
21typedef int (*config_fn_t)(const char *, const char *, void *); 23typedef int (*config_fn_t)(const char *, const char *, void *);
22extern int perf_default_config(const char *, const char *, void *); 24extern int perf_default_config(const char *, const char *, void *);
@@ -50,7 +52,6 @@ extern const char *perf_mailmap_file;
50extern void maybe_flush_or_die(FILE *, const char *); 52extern void maybe_flush_or_die(FILE *, const char *);
51extern int copy_fd(int ifd, int ofd); 53extern int copy_fd(int ifd, int ofd);
52extern int copy_file(const char *dst, const char *src, int mode); 54extern int copy_file(const char *dst, const char *src, int mode);
53extern ssize_t read_in_full(int fd, void *buf, size_t count);
54extern ssize_t write_in_full(int fd, const void *buf, size_t count); 55extern ssize_t write_in_full(int fd, const void *buf, size_t count);
55extern void write_or_die(int fd, const void *buf, size_t count); 56extern void write_or_die(int fd, const void *buf, size_t count);
56extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg); 57extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
new file mode 100644
index 000000000000..3b8380f1b478
--- /dev/null
+++ b/tools/perf/util/callchain.c
@@ -0,0 +1,345 @@
1/*
2 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree.
6 *
7 * Using a radix for code path provides a fast retrieval and factorizes
8 * memory use. Also that lets us use the paths in a hierarchical graph view.
9 *
10 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <errno.h>
16#include <math.h>
17
18#include "callchain.h"
19
20#define chain_for_each_child(child, parent) \
21 list_for_each_entry(child, &parent->children, brothers)
22
23static void
24rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
25 enum chain_mode mode)
26{
27 struct rb_node **p = &root->rb_node;
28 struct rb_node *parent = NULL;
29 struct callchain_node *rnode;
30 u64 chain_cumul = cumul_hits(chain);
31
32 while (*p) {
33 u64 rnode_cumul;
34
35 parent = *p;
36 rnode = rb_entry(parent, struct callchain_node, rb_node);
37 rnode_cumul = cumul_hits(rnode);
38
39 switch (mode) {
40 case CHAIN_FLAT:
41 if (rnode->hit < chain->hit)
42 p = &(*p)->rb_left;
43 else
44 p = &(*p)->rb_right;
45 break;
46 case CHAIN_GRAPH_ABS: /* Falldown */
47 case CHAIN_GRAPH_REL:
48 if (rnode_cumul < chain_cumul)
49 p = &(*p)->rb_left;
50 else
51 p = &(*p)->rb_right;
52 break;
53 case CHAIN_NONE:
54 default:
55 break;
56 }
57 }
58
59 rb_link_node(&chain->rb_node, parent, p);
60 rb_insert_color(&chain->rb_node, root);
61}
62
63static void
64__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
65 u64 min_hit)
66{
67 struct callchain_node *child;
68
69 chain_for_each_child(child, node)
70 __sort_chain_flat(rb_root, child, min_hit);
71
72 if (node->hit && node->hit >= min_hit)
73 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
74}
75
76/*
77 * Once we get every callchains from the stream, we can now
78 * sort them by hit
79 */
80static void
81sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
82 u64 min_hit, struct callchain_param *param __used)
83{
84 __sort_chain_flat(rb_root, node, min_hit);
85}
86
87static void __sort_chain_graph_abs(struct callchain_node *node,
88 u64 min_hit)
89{
90 struct callchain_node *child;
91
92 node->rb_root = RB_ROOT;
93
94 chain_for_each_child(child, node) {
95 __sort_chain_graph_abs(child, min_hit);
96 if (cumul_hits(child) >= min_hit)
97 rb_insert_callchain(&node->rb_root, child,
98 CHAIN_GRAPH_ABS);
99 }
100}
101
102static void
103sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
104 u64 min_hit, struct callchain_param *param __used)
105{
106 __sort_chain_graph_abs(chain_root, min_hit);
107 rb_root->rb_node = chain_root->rb_root.rb_node;
108}
109
110static void __sort_chain_graph_rel(struct callchain_node *node,
111 double min_percent)
112{
113 struct callchain_node *child;
114 u64 min_hit;
115
116 node->rb_root = RB_ROOT;
117 min_hit = ceil(node->children_hit * min_percent);
118
119 chain_for_each_child(child, node) {
120 __sort_chain_graph_rel(child, min_percent);
121 if (cumul_hits(child) >= min_hit)
122 rb_insert_callchain(&node->rb_root, child,
123 CHAIN_GRAPH_REL);
124 }
125}
126
127static void
128sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
129 u64 min_hit __used, struct callchain_param *param)
130{
131 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0);
132 rb_root->rb_node = chain_root->rb_root.rb_node;
133}
134
135int register_callchain_param(struct callchain_param *param)
136{
137 switch (param->mode) {
138 case CHAIN_GRAPH_ABS:
139 param->sort = sort_chain_graph_abs;
140 break;
141 case CHAIN_GRAPH_REL:
142 param->sort = sort_chain_graph_rel;
143 break;
144 case CHAIN_FLAT:
145 param->sort = sort_chain_flat;
146 break;
147 case CHAIN_NONE:
148 default:
149 return -1;
150 }
151 return 0;
152}
153
154/*
155 * Create a child for a parent. If inherit_children, then the new child
156 * will become the new parent of it's parent children
157 */
158static struct callchain_node *
159create_child(struct callchain_node *parent, bool inherit_children)
160{
161 struct callchain_node *new;
162
163 new = malloc(sizeof(*new));
164 if (!new) {
165 perror("not enough memory to create child for code path tree");
166 return NULL;
167 }
168 new->parent = parent;
169 INIT_LIST_HEAD(&new->children);
170 INIT_LIST_HEAD(&new->val);
171
172 if (inherit_children) {
173 struct callchain_node *next;
174
175 list_splice(&parent->children, &new->children);
176 INIT_LIST_HEAD(&parent->children);
177
178 chain_for_each_child(next, new)
179 next->parent = new;
180 }
181 list_add_tail(&new->brothers, &parent->children);
182
183 return new;
184}
185
186/*
187 * Fill the node with callchain values
188 */
189static void
190fill_node(struct callchain_node *node, struct ip_callchain *chain,
191 int start, struct symbol **syms)
192{
193 unsigned int i;
194
195 for (i = start; i < chain->nr; i++) {
196 struct callchain_list *call;
197
198 call = malloc(sizeof(*call));
199 if (!call) {
200 perror("not enough memory for the code path tree");
201 return;
202 }
203 call->ip = chain->ips[i];
204 call->sym = syms[i];
205 list_add_tail(&call->list, &node->val);
206 }
207 node->val_nr = chain->nr - start;
208 if (!node->val_nr)
209 printf("Warning: empty node in callchain tree\n");
210}
211
212static void
213add_child(struct callchain_node *parent, struct ip_callchain *chain,
214 int start, struct symbol **syms)
215{
216 struct callchain_node *new;
217
218 new = create_child(parent, false);
219 fill_node(new, chain, start, syms);
220
221 new->children_hit = 0;
222 new->hit = 1;
223}
224
225/*
226 * Split the parent in two parts (a new child is created) and
227 * give a part of its callchain to the created child.
228 * Then create another child to host the given callchain of new branch
229 */
230static void
231split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
232 struct callchain_list *to_split, int idx_parents, int idx_local,
233 struct symbol **syms)
234{
235 struct callchain_node *new;
236 struct list_head *old_tail;
237 unsigned int idx_total = idx_parents + idx_local;
238
239 /* split */
240 new = create_child(parent, true);
241
242 /* split the callchain and move a part to the new child */
243 old_tail = parent->val.prev;
244 list_del_range(&to_split->list, old_tail);
245 new->val.next = &to_split->list;
246 new->val.prev = old_tail;
247 to_split->list.prev = &new->val;
248 old_tail->next = &new->val;
249
250 /* split the hits */
251 new->hit = parent->hit;
252 new->children_hit = parent->children_hit;
253 parent->children_hit = cumul_hits(new);
254 new->val_nr = parent->val_nr - idx_local;
255 parent->val_nr = idx_local;
256
257 /* create a new child for the new branch if any */
258 if (idx_total < chain->nr) {
259 parent->hit = 0;
260 add_child(parent, chain, idx_total, syms);
261 parent->children_hit++;
262 } else {
263 parent->hit = 1;
264 }
265}
266
267static int
268__append_chain(struct callchain_node *root, struct ip_callchain *chain,
269 unsigned int start, struct symbol **syms);
270
271static void
272__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
273 struct symbol **syms, unsigned int start)
274{
275 struct callchain_node *rnode;
276
277 /* lookup in childrens */
278 chain_for_each_child(rnode, root) {
279 unsigned int ret = __append_chain(rnode, chain, start, syms);
280
281 if (!ret)
282 goto inc_children_hit;
283 }
284 /* nothing in children, add to the current node */
285 add_child(root, chain, start, syms);
286
287inc_children_hit:
288 root->children_hit++;
289}
290
291static int
292__append_chain(struct callchain_node *root, struct ip_callchain *chain,
293 unsigned int start, struct symbol **syms)
294{
295 struct callchain_list *cnode;
296 unsigned int i = start;
297 bool found = false;
298
299 /*
300 * Lookup in the current node
301 * If we have a symbol, then compare the start to match
302 * anywhere inside a function.
303 */
304 list_for_each_entry(cnode, &root->val, list) {
305 if (i == chain->nr)
306 break;
307 if (cnode->sym && syms[i]) {
308 if (cnode->sym->start != syms[i]->start)
309 break;
310 } else if (cnode->ip != chain->ips[i])
311 break;
312 if (!found)
313 found = true;
314 i++;
315 }
316
317 /* matches not, relay on the parent */
318 if (!found)
319 return -1;
320
321 /* we match only a part of the node. Split it and add the new chain */
322 if (i - start < root->val_nr) {
323 split_add_child(root, chain, cnode, start, i - start, syms);
324 return 0;
325 }
326
327 /* we match 100% of the path, increment the hit */
328 if (i - start == root->val_nr && i == chain->nr) {
329 root->hit++;
330 return 0;
331 }
332
333 /* We match the node and still have a part remaining */
334 __append_chain_children(root, chain, syms, i);
335
336 return 0;
337}
338
339void append_chain(struct callchain_node *root, struct ip_callchain *chain,
340 struct symbol **syms)
341{
342 if (!chain->nr)
343 return;
344 __append_chain_children(root, chain, syms, 0);
345}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
new file mode 100644
index 000000000000..43cf3ea9e088
--- /dev/null
+++ b/tools/perf/util/callchain.h
@@ -0,0 +1,61 @@
1#ifndef __PERF_CALLCHAIN_H
2#define __PERF_CALLCHAIN_H
3
4#include "../perf.h"
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include "util.h"
8#include "symbol.h"
9
10enum chain_mode {
11 CHAIN_NONE,
12 CHAIN_FLAT,
13 CHAIN_GRAPH_ABS,
14 CHAIN_GRAPH_REL
15};
16
17struct callchain_node {
18 struct callchain_node *parent;
19 struct list_head brothers;
20 struct list_head children;
21 struct list_head val;
22 struct rb_node rb_node; /* to sort nodes in an rbtree */
23 struct rb_root rb_root; /* sorted tree of children */
24 unsigned int val_nr;
25 u64 hit;
26 u64 children_hit;
27};
28
29struct callchain_param;
30
31typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
32 u64, struct callchain_param *);
33
34struct callchain_param {
35 enum chain_mode mode;
36 double min_percent;
37 sort_chain_func_t sort;
38};
39
40struct callchain_list {
41 u64 ip;
42 struct symbol *sym;
43 struct list_head list;
44};
45
46static inline void callchain_init(struct callchain_node *node)
47{
48 INIT_LIST_HEAD(&node->brothers);
49 INIT_LIST_HEAD(&node->children);
50 INIT_LIST_HEAD(&node->val);
51}
52
53static inline u64 cumul_hits(struct callchain_node *node)
54{
55 return node->hit + node->children_hit;
56}
57
58int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms);
61#endif
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 9a8c20ccc53e..e88bca55a599 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -11,7 +11,8 @@ static int parse_color(const char *name, int len)
11 }; 11 };
12 char *end; 12 char *end;
13 int i; 13 int i;
14 for (i = 0; i < ARRAY_SIZE(color_names); i++) { 14
15 for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) {
15 const char *str = color_names[i]; 16 const char *str = color_names[i];
16 if (!strncasecmp(name, str, len) && !str[len]) 17 if (!strncasecmp(name, str, len) && !str[len])
17 return i - 1; 18 return i - 1;
@@ -28,7 +29,8 @@ static int parse_attr(const char *name, int len)
28 static const char * const attr_names[] = { 29 static const char * const attr_names[] = {
29 "bold", "dim", "ul", "blink", "reverse" 30 "bold", "dim", "ul", "blink", "reverse"
30 }; 31 };
31 int i; 32 unsigned int i;
33
32 for (i = 0; i < ARRAY_SIZE(attr_names); i++) { 34 for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
33 const char *str = attr_names[i]; 35 const char *str = attr_names[i];
34 if (!strncasecmp(name, str, len) && !str[len]) 36 if (!strncasecmp(name, str, len) && !str[len])
@@ -164,7 +166,7 @@ int perf_color_default_config(const char *var, const char *value, void *cb)
164 return perf_default_config(var, value, cb); 166 return perf_default_config(var, value, cb);
165} 167}
166 168
167static int color_vfprintf(FILE *fp, const char *color, const char *fmt, 169static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
168 va_list args, const char *trail) 170 va_list args, const char *trail)
169{ 171{
170 int r = 0; 172 int r = 0;
@@ -189,6 +191,10 @@ static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
189 return r; 191 return r;
190} 192}
191 193
194int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
195{
196 return __color_vfprintf(fp, color, fmt, args, NULL);
197}
192 198
193 199
194int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) 200int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
@@ -197,7 +203,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
197 int r; 203 int r;
198 204
199 va_start(args, fmt); 205 va_start(args, fmt);
200 r = color_vfprintf(fp, color, fmt, args, NULL); 206 r = color_vfprintf(fp, color, fmt, args);
201 va_end(args); 207 va_end(args);
202 return r; 208 return r;
203} 209}
@@ -207,7 +213,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
207 va_list args; 213 va_list args;
208 int r; 214 int r;
209 va_start(args, fmt); 215 va_start(args, fmt);
210 r = color_vfprintf(fp, color, fmt, args, "\n"); 216 r = __color_vfprintf(fp, color, fmt, args, "\n");
211 va_end(args); 217 va_end(args);
212 return r; 218 return r;
213} 219}
@@ -222,10 +228,12 @@ int color_fwrite_lines(FILE *fp, const char *color,
222{ 228{
223 if (!*color) 229 if (!*color)
224 return fwrite(buf, count, 1, fp) != 1; 230 return fwrite(buf, count, 1, fp) != 1;
231
225 while (count) { 232 while (count) {
226 char *p = memchr(buf, '\n', count); 233 char *p = memchr(buf, '\n', count);
234
227 if (p != buf && (fputs(color, fp) < 0 || 235 if (p != buf && (fputs(color, fp) < 0 ||
228 fwrite(buf, p ? p - buf : count, 1, fp) != 1 || 236 fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
229 fputs(PERF_COLOR_RESET, fp) < 0)) 237 fputs(PERF_COLOR_RESET, fp) < 0))
230 return -1; 238 return -1;
231 if (!p) 239 if (!p)
@@ -238,4 +246,31 @@ int color_fwrite_lines(FILE *fp, const char *color,
238 return 0; 246 return 0;
239} 247}
240 248
249const char *get_percent_color(double percent)
250{
251 const char *color = PERF_COLOR_NORMAL;
241 252
253 /*
254 * We color high-overhead entries in red, mid-overhead
255 * entries in green - and keep the low overhead places
256 * normal:
257 */
258 if (percent >= MIN_RED)
259 color = PERF_COLOR_RED;
260 else {
261 if (percent > MIN_GREEN)
262 color = PERF_COLOR_GREEN;
263 }
264 return color;
265}
266
267int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
268{
269 int r;
270 const char *color;
271
272 color = get_percent_color(percent);
273 r = color_fprintf(fp, color, fmt, percent);
274
275 return r;
276}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 5abfd379582b..58d597564b99 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -15,6 +15,9 @@
15#define PERF_COLOR_CYAN "\033[36m" 15#define PERF_COLOR_CYAN "\033[36m"
16#define PERF_COLOR_BG_RED "\033[41m" 16#define PERF_COLOR_BG_RED "\033[41m"
17 17
18#define MIN_GREEN 0.5
19#define MIN_RED 5.0
20
18/* 21/*
19 * This variable stores the value of color.ui 22 * This variable stores the value of color.ui
20 */ 23 */
@@ -29,8 +32,11 @@ int perf_color_default_config(const char *var, const char *value, void *cb);
29int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); 32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
30void color_parse(const char *value, const char *var, char *dst); 33void color_parse(const char *value, const char *var, char *dst);
31void color_parse_mem(const char *value, int len, const char *var, char *dst); 34void color_parse_mem(const char *value, int len, const char *var, char *dst);
35int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
32int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); 36int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
33int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 37int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
34int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 38int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent);
35 41
36#endif /* COLOR_H */ 42#endif /* COLOR_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 3dd13faa6a27..8784649109ce 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -47,10 +47,12 @@ static int get_next_char(void)
47static char *parse_value(void) 47static char *parse_value(void)
48{ 48{
49 static char value[1024]; 49 static char value[1024];
50 int quote = 0, comment = 0, len = 0, space = 0; 50 int quote = 0, comment = 0, space = 0;
51 size_t len = 0;
51 52
52 for (;;) { 53 for (;;) {
53 int c = get_next_char(); 54 int c = get_next_char();
55
54 if (len >= sizeof(value) - 1) 56 if (len >= sizeof(value) - 1)
55 return NULL; 57 return NULL;
56 if (c == '\n') { 58 if (c == '\n') {
@@ -158,17 +160,18 @@ static int get_extended_base_var(char *name, int baselen, int c)
158 name[baselen++] = '.'; 160 name[baselen++] = '.';
159 161
160 for (;;) { 162 for (;;) {
161 int c = get_next_char(); 163 int ch = get_next_char();
162 if (c == '\n') 164
165 if (ch == '\n')
163 return -1; 166 return -1;
164 if (c == '"') 167 if (ch == '"')
165 break; 168 break;
166 if (c == '\\') { 169 if (ch == '\\') {
167 c = get_next_char(); 170 ch = get_next_char();
168 if (c == '\n') 171 if (ch == '\n')
169 return -1; 172 return -1;
170 } 173 }
171 name[baselen++] = c; 174 name[baselen++] = ch;
172 if (baselen > MAXNAME / 2) 175 if (baselen > MAXNAME / 2)
173 return -1; 176 return -1;
174 } 177 }
@@ -353,13 +356,13 @@ int perf_config_string(const char **dest, const char *var, const char *value)
353 return 0; 356 return 0;
354} 357}
355 358
356static int perf_default_core_config(const char *var, const char *value) 359static int perf_default_core_config(const char *var __used, const char *value __used)
357{ 360{
358 /* Add other config variables here and to Documentation/config.txt. */ 361 /* Add other config variables here and to Documentation/config.txt. */
359 return 0; 362 return 0;
360} 363}
361 364
362int perf_default_config(const char *var, const char *value, void *dummy) 365int perf_default_config(const char *var, const char *value, void *dummy __used)
363{ 366{
364 if (!prefixcmp(var, "core.")) 367 if (!prefixcmp(var, "core."))
365 return perf_default_core_config(var, value); 368 return perf_default_core_config(var, value);
@@ -471,10 +474,10 @@ static int matches(const char* key, const char* value)
471 !regexec(store.value_regex, value, 0, NULL, 0))); 474 !regexec(store.value_regex, value, 0, NULL, 0)));
472} 475}
473 476
474static int store_aux(const char* key, const char* value, void *cb) 477static int store_aux(const char* key, const char* value, void *cb __used)
475{ 478{
479 int section_len;
476 const char *ep; 480 const char *ep;
477 size_t section_len;
478 481
479 switch (store.state) { 482 switch (store.state) {
480 case KEY_SEEN: 483 case KEY_SEEN:
@@ -528,6 +531,8 @@ static int store_aux(const char* key, const char* value, void *cb)
528 store.offset[store.seen] = ftell(config_file); 531 store.offset[store.seen] = ftell(config_file);
529 } 532 }
530 } 533 }
534 default:
535 break;
531 } 536 }
532 return 0; 537 return 0;
533} 538}
@@ -551,7 +556,7 @@ static int store_write_section(int fd, const char* key)
551 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); 556 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
552 } 557 }
553 558
554 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 559 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
555 strbuf_release(&sb); 560 strbuf_release(&sb);
556 561
557 return success; 562 return success;
@@ -599,7 +604,7 @@ static int store_write_pair(int fd, const char* key, const char* value)
599 } 604 }
600 strbuf_addf(&sb, "%s\n", quote); 605 strbuf_addf(&sb, "%s\n", quote);
601 606
602 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 607 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
603 strbuf_release(&sb); 608 strbuf_release(&sb);
604 609
605 return success; 610 return success;
@@ -617,6 +622,7 @@ contline:
617 switch (contents[offset]) { 622 switch (contents[offset]) {
618 case '=': equal_offset = offset; break; 623 case '=': equal_offset = offset; break;
619 case ']': bracket_offset = offset; break; 624 case ']': bracket_offset = offset; break;
625 default: break;
620 } 626 }
621 if (offset > 0 && contents[offset-1] == '\\') { 627 if (offset > 0 && contents[offset-1] == '\\') {
622 offset_ = offset; 628 offset_ = offset;
@@ -740,9 +746,9 @@ int perf_config_set_multivar(const char* key, const char* value,
740 goto write_err_out; 746 goto write_err_out;
741 } else { 747 } else {
742 struct stat st; 748 struct stat st;
743 char* contents; 749 char *contents;
744 size_t contents_sz, copy_begin, copy_end; 750 ssize_t contents_sz, copy_begin, copy_end;
745 int i, new_line = 0; 751 int new_line = 0;
746 752
747 if (value_regex == NULL) 753 if (value_regex == NULL)
748 store.value_regex = NULL; 754 store.value_regex = NULL;
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
new file mode 100644
index 000000000000..e8ca98fe0bd4
--- /dev/null
+++ b/tools/perf/util/debug.c
@@ -0,0 +1,95 @@
1/* For general debugging purposes */
2
3#include "../perf.h"
4
5#include <string.h>
6#include <stdarg.h>
7#include <stdio.h>
8
9#include "color.h"
10#include "event.h"
11#include "debug.h"
12
13int verbose = 0;
14int dump_trace = 0;
15
16int eprintf(const char *fmt, ...)
17{
18 va_list args;
19 int ret = 0;
20
21 if (verbose) {
22 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args);
24 va_end(args);
25 }
26
27 return ret;
28}
29
30int dump_printf(const char *fmt, ...)
31{
32 va_list args;
33 int ret = 0;
34
35 if (dump_trace) {
36 va_start(args, fmt);
37 ret = vprintf(fmt, args);
38 va_end(args);
39 }
40
41 return ret;
42}
43
44static int dump_printf_color(const char *fmt, const char *color, ...)
45{
46 va_list args;
47 int ret = 0;
48
49 if (dump_trace) {
50 va_start(args, color);
51 ret = color_vfprintf(stdout, color, fmt, args);
52 va_end(args);
53 }
54
55 return ret;
56}
57
58
59void trace_event(event_t *event)
60{
61 unsigned char *raw_event = (void *)event;
62 const char *color = PERF_COLOR_BLUE;
63 int i, j;
64
65 if (!dump_trace)
66 return;
67
68 dump_printf(".");
69 dump_printf_color("\n. ... raw event: size %d bytes\n", color,
70 event->header.size);
71
72 for (i = 0; i < event->header.size; i++) {
73 if ((i & 15) == 0) {
74 dump_printf(".");
75 dump_printf_color(" %04x: ", color, i);
76 }
77
78 dump_printf_color(" %02x", color, raw_event[i]);
79
80 if (((i & 15) == 15) || i == event->header.size-1) {
81 dump_printf_color(" ", color);
82 for (j = 0; j < 15-(i & 15); j++)
83 dump_printf_color(" ", color);
84 for (j = 0; j < (i & 15); j++) {
85 if (isprint(raw_event[i-15+j]))
86 dump_printf_color("%c", color,
87 raw_event[i-15+j]);
88 else
89 dump_printf_color(".", color);
90 }
91 dump_printf_color("\n", color);
92 }
93 }
94 dump_printf(".\n");
95}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
new file mode 100644
index 000000000000..437eea58ce40
--- /dev/null
+++ b/tools/perf/util/debug.h
@@ -0,0 +1,8 @@
1/* For debugging general purposes */
2
3extern int verbose;
4extern int dump_trace;
5
6int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
7int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
8void trace_event(event_t *event);
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
new file mode 100644
index 000000000000..2c9c26d6ded0
--- /dev/null
+++ b/tools/perf/util/event.h
@@ -0,0 +1,104 @@
1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H
3#include "../perf.h"
4#include "util.h"
5#include <linux/list.h>
6
7enum {
8 SHOW_KERNEL = 1,
9 SHOW_USER = 2,
10 SHOW_HV = 4,
11};
12
13/*
14 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
15 */
16struct ip_event {
17 struct perf_event_header header;
18 u64 ip;
19 u32 pid, tid;
20 unsigned char __more_data[];
21};
22
23struct mmap_event {
24 struct perf_event_header header;
25 u32 pid, tid;
26 u64 start;
27 u64 len;
28 u64 pgoff;
29 char filename[PATH_MAX];
30};
31
32struct comm_event {
33 struct perf_event_header header;
34 u32 pid, tid;
35 char comm[16];
36};
37
38struct fork_event {
39 struct perf_event_header header;
40 u32 pid, ppid;
41 u32 tid, ptid;
42 u64 time;
43};
44
45struct lost_event {
46 struct perf_event_header header;
47 u64 id;
48 u64 lost;
49};
50
51/*
52 * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
53 */
54struct read_event {
55 struct perf_event_header header;
56 u32 pid, tid;
57 u64 value;
58 u64 time_enabled;
59 u64 time_running;
60 u64 id;
61};
62
63struct sample_event{
64 struct perf_event_header header;
65 u64 array[];
66};
67
68
69typedef union event_union {
70 struct perf_event_header header;
71 struct ip_event ip;
72 struct mmap_event mmap;
73 struct comm_event comm;
74 struct fork_event fork;
75 struct lost_event lost;
76 struct read_event read;
77 struct sample_event sample;
78} event_t;
79
80struct map {
81 struct list_head node;
82 u64 start;
83 u64 end;
84 u64 pgoff;
85 u64 (*map_ip)(struct map *, u64);
86 struct dso *dso;
87};
88
89static inline u64 map__map_ip(struct map *map, u64 ip)
90{
91 return ip - map->start + map->pgoff;
92}
93
94static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
95{
96 return ip;
97}
98
99struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
100struct map *map__clone(struct map *self);
101int map__overlap(struct map *l, struct map *r);
102size_t map__fprintf(struct map *self, FILE *fp);
103
104#endif
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index d39292263153..2745605dba11 100644
--- a/tools/perf/util/exec_cmd.c
+++ b/tools/perf/util/exec_cmd.c
@@ -1,9 +1,11 @@
1#include "cache.h" 1#include "cache.h"
2#include "exec_cmd.h" 2#include "exec_cmd.h"
3#include "quote.h" 3#include "quote.h"
4
5#include <string.h>
6
4#define MAX_ARGS 32 7#define MAX_ARGS 32
5 8
6extern char **environ;
7static const char *argv_exec_path; 9static const char *argv_exec_path;
8static const char *argv0_path; 10static const char *argv0_path;
9 11
@@ -51,7 +53,7 @@ const char *perf_extract_argv0_path(const char *argv0)
51 slash--; 53 slash--;
52 54
53 if (slash >= argv0) { 55 if (slash >= argv0) {
54 argv0_path = strndup(argv0, slash - argv0); 56 argv0_path = xstrndup(argv0, slash - argv0);
55 return slash + 1; 57 return slash + 1;
56 } 58 }
57 59
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
new file mode 100644
index 000000000000..e306857b2c2b
--- /dev/null
+++ b/tools/perf/util/header.c
@@ -0,0 +1,339 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5
6#include "util.h"
7#include "header.h"
8
9/*
10 * Create new perf.data header attribute:
11 */
12struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
13{
14 struct perf_header_attr *self = malloc(sizeof(*self));
15
16 if (!self)
17 die("nomem");
18
19 self->attr = *attr;
20 self->ids = 0;
21 self->size = 1;
22 self->id = malloc(sizeof(u64));
23
24 if (!self->id)
25 die("nomem");
26
27 return self;
28}
29
30void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
31{
32 int pos = self->ids;
33
34 self->ids++;
35 if (self->ids > self->size) {
36 self->size *= 2;
37 self->id = realloc(self->id, self->size * sizeof(u64));
38 if (!self->id)
39 die("nomem");
40 }
41 self->id[pos] = id;
42}
43
44/*
45 * Create new perf.data header:
46 */
47struct perf_header *perf_header__new(void)
48{
49 struct perf_header *self = malloc(sizeof(*self));
50
51 if (!self)
52 die("nomem");
53
54 self->frozen = 0;
55
56 self->attrs = 0;
57 self->size = 1;
58 self->attr = malloc(sizeof(void *));
59
60 if (!self->attr)
61 die("nomem");
62
63 self->data_offset = 0;
64 self->data_size = 0;
65
66 return self;
67}
68
69void perf_header__add_attr(struct perf_header *self,
70 struct perf_header_attr *attr)
71{
72 int pos = self->attrs;
73
74 if (self->frozen)
75 die("frozen");
76
77 self->attrs++;
78 if (self->attrs > self->size) {
79 self->size *= 2;
80 self->attr = realloc(self->attr, self->size * sizeof(void *));
81 if (!self->attr)
82 die("nomem");
83 }
84 self->attr[pos] = attr;
85}
86
87#define MAX_EVENT_NAME 64
88
89struct perf_trace_event_type {
90 u64 event_id;
91 char name[MAX_EVENT_NAME];
92};
93
94static int event_count;
95static struct perf_trace_event_type *events;
96
97void perf_header__push_event(u64 id, const char *name)
98{
99 if (strlen(name) > MAX_EVENT_NAME)
100 printf("Event %s will be truncated\n", name);
101
102 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type));
104 if (!events)
105 die("nomem");
106 } else {
107 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type));
108 if (!events)
109 die("nomem");
110 }
111 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
112 events[event_count].event_id = id;
113 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
114 event_count++;
115}
116
117char *perf_header__find_event(u64 id)
118{
119 int i;
120 for (i = 0 ; i < event_count; i++) {
121 if (events[i].event_id == id)
122 return events[i].name;
123 }
124 return NULL;
125}
126
127static const char *__perf_magic = "PERFFILE";
128
129#define PERF_MAGIC (*(u64 *)__perf_magic)
130
131struct perf_file_section {
132 u64 offset;
133 u64 size;
134};
135
136struct perf_file_attr {
137 struct perf_event_attr attr;
138 struct perf_file_section ids;
139};
140
141struct perf_file_header {
142 u64 magic;
143 u64 size;
144 u64 attr_size;
145 struct perf_file_section attrs;
146 struct perf_file_section data;
147 struct perf_file_section event_types;
148};
149
150static void do_write(int fd, void *buf, size_t size)
151{
152 while (size) {
153 int ret = write(fd, buf, size);
154
155 if (ret < 0)
156 die("failed to write");
157
158 size -= ret;
159 buf += ret;
160 }
161}
162
163void perf_header__write(struct perf_header *self, int fd)
164{
165 struct perf_file_header f_header;
166 struct perf_file_attr f_attr;
167 struct perf_header_attr *attr;
168 int i;
169
170 lseek(fd, sizeof(f_header), SEEK_SET);
171
172
173 for (i = 0; i < self->attrs; i++) {
174 attr = self->attr[i];
175
176 attr->id_offset = lseek(fd, 0, SEEK_CUR);
177 do_write(fd, attr->id, attr->ids * sizeof(u64));
178 }
179
180
181 self->attr_offset = lseek(fd, 0, SEEK_CUR);
182
183 for (i = 0; i < self->attrs; i++) {
184 attr = self->attr[i];
185
186 f_attr = (struct perf_file_attr){
187 .attr = attr->attr,
188 .ids = {
189 .offset = attr->id_offset,
190 .size = attr->ids * sizeof(u64),
191 }
192 };
193 do_write(fd, &f_attr, sizeof(f_attr));
194 }
195
196 self->event_offset = lseek(fd, 0, SEEK_CUR);
197 self->event_size = event_count * sizeof(struct perf_trace_event_type);
198 if (events)
199 do_write(fd, events, self->event_size);
200
201
202 self->data_offset = lseek(fd, 0, SEEK_CUR);
203
204 f_header = (struct perf_file_header){
205 .magic = PERF_MAGIC,
206 .size = sizeof(f_header),
207 .attr_size = sizeof(f_attr),
208 .attrs = {
209 .offset = self->attr_offset,
210 .size = self->attrs * sizeof(f_attr),
211 },
212 .data = {
213 .offset = self->data_offset,
214 .size = self->data_size,
215 },
216 .event_types = {
217 .offset = self->event_offset,
218 .size = self->event_size,
219 },
220 };
221
222 lseek(fd, 0, SEEK_SET);
223 do_write(fd, &f_header, sizeof(f_header));
224 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
225
226 self->frozen = 1;
227}
228
229static void do_read(int fd, void *buf, size_t size)
230{
231 while (size) {
232 int ret = read(fd, buf, size);
233
234 if (ret < 0)
235 die("failed to read");
236 if (ret == 0)
237 die("failed to read: missing data");
238
239 size -= ret;
240 buf += ret;
241 }
242}
243
244struct perf_header *perf_header__read(int fd)
245{
246 struct perf_header *self = perf_header__new();
247 struct perf_file_header f_header;
248 struct perf_file_attr f_attr;
249 u64 f_id;
250
251 int nr_attrs, nr_ids, i, j;
252
253 lseek(fd, 0, SEEK_SET);
254 do_read(fd, &f_header, sizeof(f_header));
255
256 if (f_header.magic != PERF_MAGIC ||
257 f_header.size != sizeof(f_header) ||
258 f_header.attr_size != sizeof(f_attr))
259 die("incompatible file format");
260
261 nr_attrs = f_header.attrs.size / sizeof(f_attr);
262 lseek(fd, f_header.attrs.offset, SEEK_SET);
263
264 for (i = 0; i < nr_attrs; i++) {
265 struct perf_header_attr *attr;
266 off_t tmp;
267
268 do_read(fd, &f_attr, sizeof(f_attr));
269 tmp = lseek(fd, 0, SEEK_CUR);
270
271 attr = perf_header_attr__new(&f_attr.attr);
272
273 nr_ids = f_attr.ids.size / sizeof(u64);
274 lseek(fd, f_attr.ids.offset, SEEK_SET);
275
276 for (j = 0; j < nr_ids; j++) {
277 do_read(fd, &f_id, sizeof(f_id));
278
279 perf_header_attr__add_id(attr, f_id);
280 }
281 perf_header__add_attr(self, attr);
282 lseek(fd, tmp, SEEK_SET);
283 }
284
285 if (f_header.event_types.size) {
286 lseek(fd, f_header.event_types.offset, SEEK_SET);
287 events = malloc(f_header.event_types.size);
288 if (!events)
289 die("nomem");
290 do_read(fd, events, f_header.event_types.size);
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 }
293 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size;
295
296 self->data_offset = f_header.data.offset;
297 self->data_size = f_header.data.size;
298
299 lseek(fd, self->data_offset, SEEK_SET);
300
301 self->frozen = 1;
302
303 return self;
304}
305
306u64 perf_header__sample_type(struct perf_header *header)
307{
308 u64 type = 0;
309 int i;
310
311 for (i = 0; i < header->attrs; i++) {
312 struct perf_header_attr *attr = header->attr[i];
313
314 if (!type)
315 type = attr->attr.sample_type;
316 else if (type != attr->attr.sample_type)
317 die("non matching sample_type");
318 }
319
320 return type;
321}
322
323struct perf_event_attr *
324perf_header__find_attr(u64 id, struct perf_header *header)
325{
326 int i;
327
328 for (i = 0; i < header->attrs; i++) {
329 struct perf_header_attr *attr = header->attr[i];
330 int j;
331
332 for (j = 0; j < attr->ids; j++) {
333 if (attr->id[j] == id)
334 return &attr->attr;
335 }
336 }
337
338 return NULL;
339}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
new file mode 100644
index 000000000000..a0761bc7863c
--- /dev/null
+++ b/tools/perf/util/header.h
@@ -0,0 +1,47 @@
1#ifndef _PERF_HEADER_H
2#define _PERF_HEADER_H
3
4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h>
6#include "types.h"
7
8struct perf_header_attr {
9 struct perf_event_attr attr;
10 int ids, size;
11 u64 *id;
12 off_t id_offset;
13};
14
15struct perf_header {
16 int frozen;
17 int attrs, size;
18 struct perf_header_attr **attr;
19 s64 attr_offset;
20 u64 data_offset;
21 u64 data_size;
22 u64 event_offset;
23 u64 event_size;
24};
25
26struct perf_header *perf_header__read(int fd);
27void perf_header__write(struct perf_header *self, int fd);
28
29void perf_header__add_attr(struct perf_header *self,
30 struct perf_header_attr *attr);
31
32void perf_header__push_event(u64 id, const char *name);
33char *perf_header__find_event(u64 id);
34
35
36struct perf_header_attr *
37perf_header_attr__new(struct perf_event_attr *attr);
38void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
39
40u64 perf_header__sample_type(struct perf_header *header);
41struct perf_event_attr *
42perf_header__find_attr(u64 id, struct perf_header *header);
43
44
45struct perf_header *perf_header__new(void);
46
47#endif /* _PERF_HEADER_H */
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
index 6653f7dd1d78..fbb00978b2e2 100644
--- a/tools/perf/util/help.c
+++ b/tools/perf/util/help.c
@@ -26,7 +26,7 @@ static int term_columns(void)
26 return 80; 26 return 80;
27} 27}
28 28
29void add_cmdname(struct cmdnames *cmds, const char *name, int len) 29void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
30{ 30{
31 struct cmdname *ent = malloc(sizeof(*ent) + len + 1); 31 struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
32 32
@@ -40,7 +40,8 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len)
40 40
41static void clean_cmdnames(struct cmdnames *cmds) 41static void clean_cmdnames(struct cmdnames *cmds)
42{ 42{
43 int i; 43 unsigned int i;
44
44 for (i = 0; i < cmds->cnt; ++i) 45 for (i = 0; i < cmds->cnt; ++i)
45 free(cmds->names[i]); 46 free(cmds->names[i]);
46 free(cmds->names); 47 free(cmds->names);
@@ -57,7 +58,7 @@ static int cmdname_compare(const void *a_, const void *b_)
57 58
58static void uniq(struct cmdnames *cmds) 59static void uniq(struct cmdnames *cmds)
59{ 60{
60 int i, j; 61 unsigned int i, j;
61 62
62 if (!cmds->cnt) 63 if (!cmds->cnt)
63 return; 64 return;
@@ -71,7 +72,7 @@ static void uniq(struct cmdnames *cmds)
71 72
72void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) 73void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
73{ 74{
74 int ci, cj, ei; 75 size_t ci, cj, ei;
75 int cmp; 76 int cmp;
76 77
77 ci = cj = ei = 0; 78 ci = cj = ei = 0;
@@ -106,8 +107,9 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
106 printf(" "); 107 printf(" ");
107 108
108 for (j = 0; j < cols; j++) { 109 for (j = 0; j < cols; j++) {
109 int n = j * rows + i; 110 unsigned int n = j * rows + i;
110 int size = space; 111 unsigned int size = space;
112
111 if (n >= cmds->cnt) 113 if (n >= cmds->cnt)
112 break; 114 break;
113 if (j == cols-1 || n + rows >= cmds->cnt) 115 if (j == cols-1 || n + rows >= cmds->cnt)
@@ -126,21 +128,6 @@ static int is_executable(const char *name)
126 !S_ISREG(st.st_mode)) 128 !S_ISREG(st.st_mode))
127 return 0; 129 return 0;
128 130
129#ifdef __MINGW32__
130 /* cannot trust the executable bit, peek into the file instead */
131 char buf[3] = { 0 };
132 int n;
133 int fd = open(name, O_RDONLY);
134 st.st_mode &= ~S_IXUSR;
135 if (fd >= 0) {
136 n = read(fd, buf, 2);
137 if (n == 2)
138 /* DOS executables start with "MZ" */
139 if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
140 st.st_mode |= S_IXUSR;
141 close(fd);
142 }
143#endif
144 return st.st_mode & S_IXUSR; 131 return st.st_mode & S_IXUSR;
145} 132}
146 133
@@ -223,7 +210,7 @@ void load_command_list(const char *prefix,
223void list_commands(const char *title, struct cmdnames *main_cmds, 210void list_commands(const char *title, struct cmdnames *main_cmds,
224 struct cmdnames *other_cmds) 211 struct cmdnames *other_cmds)
225{ 212{
226 int i, longest = 0; 213 unsigned int i, longest = 0;
227 214
228 for (i = 0; i < main_cmds->cnt; i++) 215 for (i = 0; i < main_cmds->cnt; i++)
229 if (longest < main_cmds->names[i]->len) 216 if (longest < main_cmds->names[i]->len)
@@ -254,7 +241,8 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
254 241
255int is_in_cmdlist(struct cmdnames *c, const char *s) 242int is_in_cmdlist(struct cmdnames *c, const char *s)
256{ 243{
257 int i; 244 unsigned int i;
245
258 for (i = 0; i < c->cnt; i++) 246 for (i = 0; i < c->cnt; i++)
259 if (!strcmp(s, c->names[i]->name)) 247 if (!strcmp(s, c->names[i]->name))
260 return 1; 248 return 1;
@@ -286,7 +274,8 @@ static int levenshtein_compare(const void *p1, const void *p2)
286 274
287static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) 275static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
288{ 276{
289 int i; 277 unsigned int i;
278
290 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc); 279 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
291 280
292 for (i = 0; i < old->cnt; i++) 281 for (i = 0; i < old->cnt; i++)
@@ -298,7 +287,7 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
298 287
299const char *help_unknown_cmd(const char *cmd) 288const char *help_unknown_cmd(const char *cmd)
300{ 289{
301 int i, n = 0, best_similarity = 0; 290 unsigned int i, n = 0, best_similarity = 0;
302 struct cmdnames main_cmds, other_cmds; 291 struct cmdnames main_cmds, other_cmds;
303 292
304 memset(&main_cmds, 0, sizeof(main_cmds)); 293 memset(&main_cmds, 0, sizeof(main_cmds));
@@ -360,7 +349,7 @@ const char *help_unknown_cmd(const char *cmd)
360 exit(1); 349 exit(1);
361} 350}
362 351
363int cmd_version(int argc, const char **argv, const char *prefix) 352int cmd_version(int argc __used, const char **argv __used, const char *prefix __used)
364{ 353{
365 printf("perf version %s\n", perf_version_string); 354 printf("perf version %s\n", perf_version_string);
366 return 0; 355 return 0;
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
index 56bc15406ffc..7128783637b4 100644
--- a/tools/perf/util/help.h
+++ b/tools/perf/util/help.h
@@ -2,8 +2,8 @@
2#define HELP_H 2#define HELP_H
3 3
4struct cmdnames { 4struct cmdnames {
5 int alloc; 5 size_t alloc;
6 int cnt; 6 size_t cnt;
7 struct cmdname { 7 struct cmdname {
8 size_t len; /* also used for similarity index in help.c */ 8 size_t len; /* also used for similarity index in help.c */
9 char name[FLEX_ARRAY]; 9 char name[FLEX_ARRAY];
@@ -19,7 +19,7 @@ static inline void mput_char(char c, unsigned int num)
19void load_command_list(const char *prefix, 19void load_command_list(const char *prefix,
20 struct cmdnames *main_cmds, 20 struct cmdnames *main_cmds,
21 struct cmdnames *other_cmds); 21 struct cmdnames *other_cmds);
22void add_cmdname(struct cmdnames *cmds, const char *name, int len); 22void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
23/* Here we require that excludes is a sorted list. */ 23/* Here we require that excludes is a sorted list. */
24void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes); 24void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
25int is_in_cmdlist(struct cmdnames *c, const char *s); 25int is_in_cmdlist(struct cmdnames *c, const char *s);
diff --git a/tools/perf/util/include/asm/system.h b/tools/perf/util/include/asm/system.h
new file mode 100644
index 000000000000..710cecca972d
--- /dev/null
+++ b/tools/perf/util/include/asm/system.h
@@ -0,0 +1 @@
/* Empty */
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
new file mode 100644
index 000000000000..a6b87390cb52
--- /dev/null
+++ b/tools/perf/util/include/linux/kernel.h
@@ -0,0 +1,29 @@
1#ifndef PERF_LINUX_KERNEL_H_
2#define PERF_LINUX_KERNEL_H_
3
4#ifndef offsetof
5#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
6#endif
7
8#ifndef container_of
9/**
10 * container_of - cast a member of a structure out to the containing structure
11 * @ptr: the pointer to the member.
12 * @type: the type of the container struct this is embedded in.
13 * @member: the name of the member within the struct.
14 *
15 */
16#define container_of(ptr, type, member) ({ \
17 const typeof(((type *)0)->member) * __mptr = (ptr); \
18 (type *)((char *)__mptr - offsetof(type, member)); })
19#endif
20
21#ifndef max
22#define max(x, y) ({ \
23 typeof(x) _max1 = (x); \
24 typeof(y) _max2 = (y); \
25 (void) (&_max1 == &_max2); \
26 _max1 > _max2 ? _max1 : _max2; })
27#endif
28
29#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
new file mode 100644
index 000000000000..dbe4b814382a
--- /dev/null
+++ b/tools/perf/util/include/linux/list.h
@@ -0,0 +1,18 @@
1#include "../../../../include/linux/list.h"
2
3#ifndef PERF_LIST_H
4#define PERF_LIST_H
5/**
6 * list_del_range - deletes range of entries from list.
7 * @begin: first element in the range to delete from the list.
8 * @end: last element in the range to delete from the list.
9 * Note: list_empty on the range of entries does not return true after this,
10 * the entries is in an undefined state.
11 */
12static inline void list_del_range(struct list_head *begin,
13 struct list_head *end)
14{
15 begin->prev->next = end->next;
16 end->next->prev = begin->prev;
17}
18#endif
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/module.h
new file mode 100644
index 000000000000..b43e2dc21e04
--- /dev/null
+++ b/tools/perf/util/include/linux/module.h
@@ -0,0 +1,6 @@
1#ifndef PERF_LINUX_MODULE_H
2#define PERF_LINUX_MODULE_H
3
4#define EXPORT_SYMBOL(name)
5
6#endif
diff --git a/tools/perf/util/include/linux/poison.h b/tools/perf/util/include/linux/poison.h
new file mode 100644
index 000000000000..fef6dbc9ce13
--- /dev/null
+++ b/tools/perf/util/include/linux/poison.h
@@ -0,0 +1 @@
#include "../../../../include/linux/poison.h"
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
new file mode 100644
index 000000000000..7841e485d8c3
--- /dev/null
+++ b/tools/perf/util/include/linux/prefetch.h
@@ -0,0 +1,6 @@
1#ifndef PERF_LINUX_PREFETCH_H
2#define PERF_LINUX_PREFETCH_H
3
4static inline void prefetch(void *a __attribute__((unused))) { }
5
6#endif
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
new file mode 100644
index 000000000000..7a243a143037
--- /dev/null
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -0,0 +1 @@
#include "../../../../include/linux/rbtree.h"
diff --git a/tools/perf/util/list.h b/tools/perf/util/list.h
deleted file mode 100644
index e2548e8072cf..000000000000
--- a/tools/perf/util/list.h
+++ /dev/null
@@ -1,603 +0,0 @@
1#ifndef _LINUX_LIST_H
2#define _LINUX_LIST_H
3/*
4 Copyright (C) Cast of dozens, comes from the Linux kernel
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of version 2 of the GNU General Public License as
8 published by the Free Software Foundation.
9*/
10
11#include <stddef.h>
12
13/*
14 * These are non-NULL pointers that will result in page faults
15 * under normal circumstances, used to verify that nobody uses
16 * non-initialized list entries.
17 */
18#define LIST_POISON1 ((void *)0x00100100)
19#define LIST_POISON2 ((void *)0x00200200)
20
21/**
22 * container_of - cast a member of a structure out to the containing structure
23 * @ptr: the pointer to the member.
24 * @type: the type of the container struct this is embedded in.
25 * @member: the name of the member within the struct.
26 *
27 */
28#define container_of(ptr, type, member) ({ \
29 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
30 (type *)( (char *)__mptr - offsetof(type,member) );})
31
32/*
33 * Simple doubly linked list implementation.
34 *
35 * Some of the internal functions ("__xxx") are useful when
36 * manipulating whole lists rather than single entries, as
37 * sometimes we already know the next/prev entries and we can
38 * generate better code by using them directly rather than
39 * using the generic single-entry routines.
40 */
41
42struct list_head {
43 struct list_head *next, *prev;
44};
45
46#define LIST_HEAD_INIT(name) { &(name), &(name) }
47
48#define LIST_HEAD(name) \
49 struct list_head name = LIST_HEAD_INIT(name)
50
51static inline void INIT_LIST_HEAD(struct list_head *list)
52{
53 list->next = list;
54 list->prev = list;
55}
56
57/*
58 * Insert a new entry between two known consecutive entries.
59 *
60 * This is only for internal list manipulation where we know
61 * the prev/next entries already!
62 */
63static inline void __list_add(struct list_head *new,
64 struct list_head *prev,
65 struct list_head *next)
66{
67 next->prev = new;
68 new->next = next;
69 new->prev = prev;
70 prev->next = new;
71}
72
73/**
74 * list_add - add a new entry
75 * @new: new entry to be added
76 * @head: list head to add it after
77 *
78 * Insert a new entry after the specified head.
79 * This is good for implementing stacks.
80 */
81static inline void list_add(struct list_head *new, struct list_head *head)
82{
83 __list_add(new, head, head->next);
84}
85
86/**
87 * list_add_tail - add a new entry
88 * @new: new entry to be added
89 * @head: list head to add it before
90 *
91 * Insert a new entry before the specified head.
92 * This is useful for implementing queues.
93 */
94static inline void list_add_tail(struct list_head *new, struct list_head *head)
95{
96 __list_add(new, head->prev, head);
97}
98
99/*
100 * Delete a list entry by making the prev/next entries
101 * point to each other.
102 *
103 * This is only for internal list manipulation where we know
104 * the prev/next entries already!
105 */
106static inline void __list_del(struct list_head * prev, struct list_head * next)
107{
108 next->prev = prev;
109 prev->next = next;
110}
111
112/**
113 * list_del - deletes entry from list.
114 * @entry: the element to delete from the list.
115 * Note: list_empty on entry does not return true after this, the entry is
116 * in an undefined state.
117 */
118static inline void list_del(struct list_head *entry)
119{
120 __list_del(entry->prev, entry->next);
121 entry->next = LIST_POISON1;
122 entry->prev = LIST_POISON2;
123}
124
125/**
126 * list_del_range - deletes range of entries from list.
127 * @beging: first element in the range to delete from the list.
128 * @beging: first element in the range to delete from the list.
129 * Note: list_empty on the range of entries does not return true after this,
130 * the entries is in an undefined state.
131 */
132static inline void list_del_range(struct list_head *begin,
133 struct list_head *end)
134{
135 begin->prev->next = end->next;
136 end->next->prev = begin->prev;
137}
138
139/**
140 * list_replace - replace old entry by new one
141 * @old : the element to be replaced
142 * @new : the new element to insert
143 * Note: if 'old' was empty, it will be overwritten.
144 */
145static inline void list_replace(struct list_head *old,
146 struct list_head *new)
147{
148 new->next = old->next;
149 new->next->prev = new;
150 new->prev = old->prev;
151 new->prev->next = new;
152}
153
154static inline void list_replace_init(struct list_head *old,
155 struct list_head *new)
156{
157 list_replace(old, new);
158 INIT_LIST_HEAD(old);
159}
160
161/**
162 * list_del_init - deletes entry from list and reinitialize it.
163 * @entry: the element to delete from the list.
164 */
165static inline void list_del_init(struct list_head *entry)
166{
167 __list_del(entry->prev, entry->next);
168 INIT_LIST_HEAD(entry);
169}
170
171/**
172 * list_move - delete from one list and add as another's head
173 * @list: the entry to move
174 * @head: the head that will precede our entry
175 */
176static inline void list_move(struct list_head *list, struct list_head *head)
177{
178 __list_del(list->prev, list->next);
179 list_add(list, head);
180}
181
182/**
183 * list_move_tail - delete from one list and add as another's tail
184 * @list: the entry to move
185 * @head: the head that will follow our entry
186 */
187static inline void list_move_tail(struct list_head *list,
188 struct list_head *head)
189{
190 __list_del(list->prev, list->next);
191 list_add_tail(list, head);
192}
193
194/**
195 * list_is_last - tests whether @list is the last entry in list @head
196 * @list: the entry to test
197 * @head: the head of the list
198 */
199static inline int list_is_last(const struct list_head *list,
200 const struct list_head *head)
201{
202 return list->next == head;
203}
204
205/**
206 * list_empty - tests whether a list is empty
207 * @head: the list to test.
208 */
209static inline int list_empty(const struct list_head *head)
210{
211 return head->next == head;
212}
213
214/**
215 * list_empty_careful - tests whether a list is empty and not being modified
216 * @head: the list to test
217 *
218 * Description:
219 * tests whether a list is empty _and_ checks that no other CPU might be
220 * in the process of modifying either member (next or prev)
221 *
222 * NOTE: using list_empty_careful() without synchronization
223 * can only be safe if the only activity that can happen
224 * to the list entry is list_del_init(). Eg. it cannot be used
225 * if another CPU could re-list_add() it.
226 */
227static inline int list_empty_careful(const struct list_head *head)
228{
229 struct list_head *next = head->next;
230 return (next == head) && (next == head->prev);
231}
232
233static inline void __list_splice(struct list_head *list,
234 struct list_head *head)
235{
236 struct list_head *first = list->next;
237 struct list_head *last = list->prev;
238 struct list_head *at = head->next;
239
240 first->prev = head;
241 head->next = first;
242
243 last->next = at;
244 at->prev = last;
245}
246
247/**
248 * list_splice - join two lists
249 * @list: the new list to add.
250 * @head: the place to add it in the first list.
251 */
252static inline void list_splice(struct list_head *list, struct list_head *head)
253{
254 if (!list_empty(list))
255 __list_splice(list, head);
256}
257
258/**
259 * list_splice_init - join two lists and reinitialise the emptied list.
260 * @list: the new list to add.
261 * @head: the place to add it in the first list.
262 *
263 * The list at @list is reinitialised
264 */
265static inline void list_splice_init(struct list_head *list,
266 struct list_head *head)
267{
268 if (!list_empty(list)) {
269 __list_splice(list, head);
270 INIT_LIST_HEAD(list);
271 }
272}
273
274/**
275 * list_entry - get the struct for this entry
276 * @ptr: the &struct list_head pointer.
277 * @type: the type of the struct this is embedded in.
278 * @member: the name of the list_struct within the struct.
279 */
280#define list_entry(ptr, type, member) \
281 container_of(ptr, type, member)
282
283/**
284 * list_first_entry - get the first element from a list
285 * @ptr: the list head to take the element from.
286 * @type: the type of the struct this is embedded in.
287 * @member: the name of the list_struct within the struct.
288 *
289 * Note, that list is expected to be not empty.
290 */
291#define list_first_entry(ptr, type, member) \
292 list_entry((ptr)->next, type, member)
293
294/**
295 * list_for_each - iterate over a list
296 * @pos: the &struct list_head to use as a loop cursor.
297 * @head: the head for your list.
298 */
299#define list_for_each(pos, head) \
300 for (pos = (head)->next; pos != (head); \
301 pos = pos->next)
302
303/**
304 * __list_for_each - iterate over a list
305 * @pos: the &struct list_head to use as a loop cursor.
306 * @head: the head for your list.
307 *
308 * This variant differs from list_for_each() in that it's the
309 * simplest possible list iteration code, no prefetching is done.
310 * Use this for code that knows the list to be very short (empty
311 * or 1 entry) most of the time.
312 */
313#define __list_for_each(pos, head) \
314 for (pos = (head)->next; pos != (head); pos = pos->next)
315
316/**
317 * list_for_each_prev - iterate over a list backwards
318 * @pos: the &struct list_head to use as a loop cursor.
319 * @head: the head for your list.
320 */
321#define list_for_each_prev(pos, head) \
322 for (pos = (head)->prev; pos != (head); \
323 pos = pos->prev)
324
325/**
326 * list_for_each_safe - iterate over a list safe against removal of list entry
327 * @pos: the &struct list_head to use as a loop cursor.
328 * @n: another &struct list_head to use as temporary storage
329 * @head: the head for your list.
330 */
331#define list_for_each_safe(pos, n, head) \
332 for (pos = (head)->next, n = pos->next; pos != (head); \
333 pos = n, n = pos->next)
334
335/**
336 * list_for_each_entry - iterate over list of given type
337 * @pos: the type * to use as a loop cursor.
338 * @head: the head for your list.
339 * @member: the name of the list_struct within the struct.
340 */
341#define list_for_each_entry(pos, head, member) \
342 for (pos = list_entry((head)->next, typeof(*pos), member); \
343 &pos->member != (head); \
344 pos = list_entry(pos->member.next, typeof(*pos), member))
345
346/**
347 * list_for_each_entry_reverse - iterate backwards over list of given type.
348 * @pos: the type * to use as a loop cursor.
349 * @head: the head for your list.
350 * @member: the name of the list_struct within the struct.
351 */
352#define list_for_each_entry_reverse(pos, head, member) \
353 for (pos = list_entry((head)->prev, typeof(*pos), member); \
354 &pos->member != (head); \
355 pos = list_entry(pos->member.prev, typeof(*pos), member))
356
357/**
358 * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
359 * @pos: the type * to use as a start point
360 * @head: the head of the list
361 * @member: the name of the list_struct within the struct.
362 *
363 * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
364 */
365#define list_prepare_entry(pos, head, member) \
366 ((pos) ? : list_entry(head, typeof(*pos), member))
367
368/**
369 * list_for_each_entry_continue - continue iteration over list of given type
370 * @pos: the type * to use as a loop cursor.
371 * @head: the head for your list.
372 * @member: the name of the list_struct within the struct.
373 *
374 * Continue to iterate over list of given type, continuing after
375 * the current position.
376 */
377#define list_for_each_entry_continue(pos, head, member) \
378 for (pos = list_entry(pos->member.next, typeof(*pos), member); \
379 &pos->member != (head); \
380 pos = list_entry(pos->member.next, typeof(*pos), member))
381
382/**
383 * list_for_each_entry_from - iterate over list of given type from the current point
384 * @pos: the type * to use as a loop cursor.
385 * @head: the head for your list.
386 * @member: the name of the list_struct within the struct.
387 *
388 * Iterate over list of given type, continuing from current position.
389 */
390#define list_for_each_entry_from(pos, head, member) \
391 for (; &pos->member != (head); \
392 pos = list_entry(pos->member.next, typeof(*pos), member))
393
394/**
395 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
396 * @pos: the type * to use as a loop cursor.
397 * @n: another type * to use as temporary storage
398 * @head: the head for your list.
399 * @member: the name of the list_struct within the struct.
400 */
401#define list_for_each_entry_safe(pos, n, head, member) \
402 for (pos = list_entry((head)->next, typeof(*pos), member), \
403 n = list_entry(pos->member.next, typeof(*pos), member); \
404 &pos->member != (head); \
405 pos = n, n = list_entry(n->member.next, typeof(*n), member))
406
407/**
408 * list_for_each_entry_safe_continue
409 * @pos: the type * to use as a loop cursor.
410 * @n: another type * to use as temporary storage
411 * @head: the head for your list.
412 * @member: the name of the list_struct within the struct.
413 *
414 * Iterate over list of given type, continuing after current point,
415 * safe against removal of list entry.
416 */
417#define list_for_each_entry_safe_continue(pos, n, head, member) \
418 for (pos = list_entry(pos->member.next, typeof(*pos), member), \
419 n = list_entry(pos->member.next, typeof(*pos), member); \
420 &pos->member != (head); \
421 pos = n, n = list_entry(n->member.next, typeof(*n), member))
422
423/**
424 * list_for_each_entry_safe_from
425 * @pos: the type * to use as a loop cursor.
426 * @n: another type * to use as temporary storage
427 * @head: the head for your list.
428 * @member: the name of the list_struct within the struct.
429 *
430 * Iterate over list of given type from current point, safe against
431 * removal of list entry.
432 */
433#define list_for_each_entry_safe_from(pos, n, head, member) \
434 for (n = list_entry(pos->member.next, typeof(*pos), member); \
435 &pos->member != (head); \
436 pos = n, n = list_entry(n->member.next, typeof(*n), member))
437
438/**
439 * list_for_each_entry_safe_reverse
440 * @pos: the type * to use as a loop cursor.
441 * @n: another type * to use as temporary storage
442 * @head: the head for your list.
443 * @member: the name of the list_struct within the struct.
444 *
445 * Iterate backwards over list of given type, safe against removal
446 * of list entry.
447 */
448#define list_for_each_entry_safe_reverse(pos, n, head, member) \
449 for (pos = list_entry((head)->prev, typeof(*pos), member), \
450 n = list_entry(pos->member.prev, typeof(*pos), member); \
451 &pos->member != (head); \
452 pos = n, n = list_entry(n->member.prev, typeof(*n), member))
453
454/*
455 * Double linked lists with a single pointer list head.
456 * Mostly useful for hash tables where the two pointer list head is
457 * too wasteful.
458 * You lose the ability to access the tail in O(1).
459 */
460
461struct hlist_head {
462 struct hlist_node *first;
463};
464
465struct hlist_node {
466 struct hlist_node *next, **pprev;
467};
468
469#define HLIST_HEAD_INIT { .first = NULL }
470#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
471#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
472static inline void INIT_HLIST_NODE(struct hlist_node *h)
473{
474 h->next = NULL;
475 h->pprev = NULL;
476}
477
478static inline int hlist_unhashed(const struct hlist_node *h)
479{
480 return !h->pprev;
481}
482
483static inline int hlist_empty(const struct hlist_head *h)
484{
485 return !h->first;
486}
487
488static inline void __hlist_del(struct hlist_node *n)
489{
490 struct hlist_node *next = n->next;
491 struct hlist_node **pprev = n->pprev;
492 *pprev = next;
493 if (next)
494 next->pprev = pprev;
495}
496
497static inline void hlist_del(struct hlist_node *n)
498{
499 __hlist_del(n);
500 n->next = LIST_POISON1;
501 n->pprev = LIST_POISON2;
502}
503
504static inline void hlist_del_init(struct hlist_node *n)
505{
506 if (!hlist_unhashed(n)) {
507 __hlist_del(n);
508 INIT_HLIST_NODE(n);
509 }
510}
511
512static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
513{
514 struct hlist_node *first = h->first;
515 n->next = first;
516 if (first)
517 first->pprev = &n->next;
518 h->first = n;
519 n->pprev = &h->first;
520}
521
522/* next must be != NULL */
523static inline void hlist_add_before(struct hlist_node *n,
524 struct hlist_node *next)
525{
526 n->pprev = next->pprev;
527 n->next = next;
528 next->pprev = &n->next;
529 *(n->pprev) = n;
530}
531
532static inline void hlist_add_after(struct hlist_node *n,
533 struct hlist_node *next)
534{
535 next->next = n->next;
536 n->next = next;
537 next->pprev = &n->next;
538
539 if(next->next)
540 next->next->pprev = &next->next;
541}
542
543#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
544
545#define hlist_for_each(pos, head) \
546 for (pos = (head)->first; pos; \
547 pos = pos->next)
548
549#define hlist_for_each_safe(pos, n, head) \
550 for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
551 pos = n)
552
553/**
554 * hlist_for_each_entry - iterate over list of given type
555 * @tpos: the type * to use as a loop cursor.
556 * @pos: the &struct hlist_node to use as a loop cursor.
557 * @head: the head for your list.
558 * @member: the name of the hlist_node within the struct.
559 */
560#define hlist_for_each_entry(tpos, pos, head, member) \
561 for (pos = (head)->first; \
562 pos && \
563 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
564 pos = pos->next)
565
566/**
567 * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
568 * @tpos: the type * to use as a loop cursor.
569 * @pos: the &struct hlist_node to use as a loop cursor.
570 * @member: the name of the hlist_node within the struct.
571 */
572#define hlist_for_each_entry_continue(tpos, pos, member) \
573 for (pos = (pos)->next; \
574 pos && \
575 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
576 pos = pos->next)
577
578/**
579 * hlist_for_each_entry_from - iterate over a hlist continuing from current point
580 * @tpos: the type * to use as a loop cursor.
581 * @pos: the &struct hlist_node to use as a loop cursor.
582 * @member: the name of the hlist_node within the struct.
583 */
584#define hlist_for_each_entry_from(tpos, pos, member) \
585 for (; pos && \
586 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
587 pos = pos->next)
588
589/**
590 * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
591 * @tpos: the type * to use as a loop cursor.
592 * @pos: the &struct hlist_node to use as a loop cursor.
593 * @n: another &struct hlist_node to use as temporary storage
594 * @head: the head for your list.
595 * @member: the name of the hlist_node within the struct.
596 */
597#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
598 for (pos = (head)->first; \
599 pos && ({ n = pos->next; 1; }) && \
600 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
601 pos = n)
602
603#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
new file mode 100644
index 000000000000..804e02382739
--- /dev/null
+++ b/tools/perf/util/map.c
@@ -0,0 +1,97 @@
1#include "event.h"
2#include "symbol.h"
3#include <stdlib.h>
4#include <string.h>
5#include <stdio.h>
6
7static inline int is_anon_memory(const char *filename)
8{
9 return strcmp(filename, "//anon") == 0;
10}
11
12static int strcommon(const char *pathname, char *cwd, int cwdlen)
13{
14 int n = 0;
15
16 while (n < cwdlen && pathname[n] == cwd[n])
17 ++n;
18
19 return n;
20}
21
22 struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
23{
24 struct map *self = malloc(sizeof(*self));
25
26 if (self != NULL) {
27 const char *filename = event->filename;
28 char newfilename[PATH_MAX];
29 int anon;
30
31 if (cwd) {
32 int n = strcommon(filename, cwd, cwdlen);
33
34 if (n == cwdlen) {
35 snprintf(newfilename, sizeof(newfilename),
36 ".%s", filename + n);
37 filename = newfilename;
38 }
39 }
40
41 anon = is_anon_memory(filename);
42
43 if (anon) {
44 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
45 filename = newfilename;
46 }
47
48 self->start = event->start;
49 self->end = event->start + event->len;
50 self->pgoff = event->pgoff;
51
52 self->dso = dsos__findnew(filename);
53 if (self->dso == NULL)
54 goto out_delete;
55
56 if (self->dso == vdso || anon)
57 self->map_ip = vdso__map_ip;
58 else
59 self->map_ip = map__map_ip;
60 }
61 return self;
62out_delete:
63 free(self);
64 return NULL;
65}
66
67struct map *map__clone(struct map *self)
68{
69 struct map *map = malloc(sizeof(*self));
70
71 if (!map)
72 return NULL;
73
74 memcpy(map, self, sizeof(*self));
75
76 return map;
77}
78
79int map__overlap(struct map *l, struct map *r)
80{
81 if (l->start > r->start) {
82 struct map *t = l;
83 l = r;
84 r = t;
85 }
86
87 if (l->end > r->start)
88 return 1;
89
90 return 0;
91}
92
93size_t map__fprintf(struct map *self, FILE *fp)
94{
95 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
96 self->start, self->end, self->pgoff, self->dso->name);
97}
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
new file mode 100644
index 000000000000..0d8c85defcd2
--- /dev/null
+++ b/tools/perf/util/module.c
@@ -0,0 +1,545 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <libgen.h>
8#include <gelf.h>
9#include <elf.h>
10#include <dirent.h>
11#include <sys/utsname.h>
12
13static unsigned int crc32(const char *p, unsigned int len)
14{
15 int i;
16 unsigned int crc = 0;
17
18 while (len--) {
19 crc ^= *p++;
20 for (i = 0; i < 8; i++)
21 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
22 }
23 return crc;
24}
25
26/* module section methods */
27
28struct sec_dso *sec_dso__new_dso(const char *name)
29{
30 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
31
32 if (self != NULL) {
33 strcpy(self->name, name);
34 self->secs = RB_ROOT;
35 self->find_section = sec_dso__find_section;
36 }
37
38 return self;
39}
40
41static void sec_dso__delete_section(struct section *self)
42{
43 free(((void *)self));
44}
45
46void sec_dso__delete_sections(struct sec_dso *self)
47{
48 struct section *pos;
49 struct rb_node *next = rb_first(&self->secs);
50
51 while (next) {
52 pos = rb_entry(next, struct section, rb_node);
53 next = rb_next(&pos->rb_node);
54 rb_erase(&pos->rb_node, &self->secs);
55 sec_dso__delete_section(pos);
56 }
57}
58
59void sec_dso__delete_self(struct sec_dso *self)
60{
61 sec_dso__delete_sections(self);
62 free(self);
63}
64
65static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
66{
67 struct rb_node **p = &self->secs.rb_node;
68 struct rb_node *parent = NULL;
69 const u64 hash = sec->hash;
70 struct section *s;
71
72 while (*p != NULL) {
73 parent = *p;
74 s = rb_entry(parent, struct section, rb_node);
75 if (hash < s->hash)
76 p = &(*p)->rb_left;
77 else
78 p = &(*p)->rb_right;
79 }
80 rb_link_node(&sec->rb_node, parent, p);
81 rb_insert_color(&sec->rb_node, &self->secs);
82}
83
84struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
85{
86 struct rb_node *n;
87 u64 hash;
88 int len;
89
90 if (self == NULL)
91 return NULL;
92
93 len = strlen(name);
94 hash = crc32(name, len);
95
96 n = self->secs.rb_node;
97
98 while (n) {
99 struct section *s = rb_entry(n, struct section, rb_node);
100
101 if (hash < s->hash)
102 n = n->rb_left;
103 else if (hash > s->hash)
104 n = n->rb_right;
105 else {
106 if (!strcmp(name, s->name))
107 return s;
108 else
109 n = rb_next(&s->rb_node);
110 }
111 }
112
113 return NULL;
114}
115
116static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
117{
118 return fprintf(fp, "name:%s vma:%llx path:%s\n",
119 self->name, self->vma, self->path);
120}
121
122size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
123{
124 size_t ret = fprintf(fp, "dso: %s\n", self->name);
125
126 struct rb_node *nd;
127 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
128 struct section *pos = rb_entry(nd, struct section, rb_node);
129 ret += sec_dso__fprintf_section(pos, fp);
130 }
131
132 return ret;
133}
134
135static struct section *section__new(const char *name, const char *path)
136{
137 struct section *self = calloc(1, sizeof(*self));
138
139 if (!self)
140 goto out_failure;
141
142 self->name = calloc(1, strlen(name) + 1);
143 if (!self->name)
144 goto out_failure;
145
146 self->path = calloc(1, strlen(path) + 1);
147 if (!self->path)
148 goto out_failure;
149
150 strcpy(self->name, name);
151 strcpy(self->path, path);
152 self->hash = crc32(self->name, strlen(name));
153
154 return self;
155
156out_failure:
157 if (self) {
158 if (self->name)
159 free(self->name);
160 if (self->path)
161 free(self->path);
162 free(self);
163 }
164
165 return NULL;
166}
167
168/* module methods */
169
170struct mod_dso *mod_dso__new_dso(const char *name)
171{
172 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
173
174 if (self != NULL) {
175 strcpy(self->name, name);
176 self->mods = RB_ROOT;
177 self->find_module = mod_dso__find_module;
178 }
179
180 return self;
181}
182
183static void mod_dso__delete_module(struct module *self)
184{
185 free(((void *)self));
186}
187
188void mod_dso__delete_modules(struct mod_dso *self)
189{
190 struct module *pos;
191 struct rb_node *next = rb_first(&self->mods);
192
193 while (next) {
194 pos = rb_entry(next, struct module, rb_node);
195 next = rb_next(&pos->rb_node);
196 rb_erase(&pos->rb_node, &self->mods);
197 mod_dso__delete_module(pos);
198 }
199}
200
201void mod_dso__delete_self(struct mod_dso *self)
202{
203 mod_dso__delete_modules(self);
204 free(self);
205}
206
207static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
208{
209 struct rb_node **p = &self->mods.rb_node;
210 struct rb_node *parent = NULL;
211 const u64 hash = mod->hash;
212 struct module *m;
213
214 while (*p != NULL) {
215 parent = *p;
216 m = rb_entry(parent, struct module, rb_node);
217 if (hash < m->hash)
218 p = &(*p)->rb_left;
219 else
220 p = &(*p)->rb_right;
221 }
222 rb_link_node(&mod->rb_node, parent, p);
223 rb_insert_color(&mod->rb_node, &self->mods);
224}
225
226struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
227{
228 struct rb_node *n;
229 u64 hash;
230 int len;
231
232 if (self == NULL)
233 return NULL;
234
235 len = strlen(name);
236 hash = crc32(name, len);
237
238 n = self->mods.rb_node;
239
240 while (n) {
241 struct module *m = rb_entry(n, struct module, rb_node);
242
243 if (hash < m->hash)
244 n = n->rb_left;
245 else if (hash > m->hash)
246 n = n->rb_right;
247 else {
248 if (!strcmp(name, m->name))
249 return m;
250 else
251 n = rb_next(&m->rb_node);
252 }
253 }
254
255 return NULL;
256}
257
258static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
259{
260 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
261}
262
263size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
264{
265 struct rb_node *nd;
266 size_t ret;
267
268 ret = fprintf(fp, "dso: %s\n", self->name);
269
270 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
271 struct module *pos = rb_entry(nd, struct module, rb_node);
272
273 ret += mod_dso__fprintf_module(pos, fp);
274 }
275
276 return ret;
277}
278
279static struct module *module__new(const char *name, const char *path)
280{
281 struct module *self = calloc(1, sizeof(*self));
282
283 if (!self)
284 goto out_failure;
285
286 self->name = calloc(1, strlen(name) + 1);
287 if (!self->name)
288 goto out_failure;
289
290 self->path = calloc(1, strlen(path) + 1);
291 if (!self->path)
292 goto out_failure;
293
294 strcpy(self->name, name);
295 strcpy(self->path, path);
296 self->hash = crc32(self->name, strlen(name));
297
298 return self;
299
300out_failure:
301 if (self) {
302 if (self->name)
303 free(self->name);
304 if (self->path)
305 free(self->path);
306 free(self);
307 }
308
309 return NULL;
310}
311
312static int mod_dso__load_sections(struct module *mod)
313{
314 int count = 0, path_len;
315 struct dirent *entry;
316 char *line = NULL;
317 char *dir_path;
318 DIR *dir;
319 size_t n;
320
321 path_len = strlen("/sys/module/");
322 path_len += strlen(mod->name);
323 path_len += strlen("/sections/");
324
325 dir_path = calloc(1, path_len + 1);
326 if (dir_path == NULL)
327 goto out_failure;
328
329 strcat(dir_path, "/sys/module/");
330 strcat(dir_path, mod->name);
331 strcat(dir_path, "/sections/");
332
333 dir = opendir(dir_path);
334 if (dir == NULL)
335 goto out_free;
336
337 while ((entry = readdir(dir))) {
338 struct section *section;
339 char *path, *vma;
340 int line_len;
341 FILE *file;
342
343 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
344 continue;
345
346 path = calloc(1, path_len + strlen(entry->d_name) + 1);
347 if (path == NULL)
348 break;
349 strcat(path, dir_path);
350 strcat(path, entry->d_name);
351
352 file = fopen(path, "r");
353 if (file == NULL) {
354 free(path);
355 break;
356 }
357
358 line_len = getline(&line, &n, file);
359 if (line_len < 0) {
360 free(path);
361 fclose(file);
362 break;
363 }
364
365 if (!line) {
366 free(path);
367 fclose(file);
368 break;
369 }
370
371 line[--line_len] = '\0'; /* \n */
372
373 vma = strstr(line, "0x");
374 if (!vma) {
375 free(path);
376 fclose(file);
377 break;
378 }
379 vma += 2;
380
381 section = section__new(entry->d_name, path);
382 if (!section) {
383 fprintf(stderr, "load_sections: allocation error\n");
384 free(path);
385 fclose(file);
386 break;
387 }
388
389 hex2u64(vma, &section->vma);
390 sec_dso__insert_section(mod->sections, section);
391
392 free(path);
393 fclose(file);
394 count++;
395 }
396
397 closedir(dir);
398 free(line);
399 free(dir_path);
400
401 return count;
402
403out_free:
404 free(dir_path);
405
406out_failure:
407 return count;
408}
409
410static int mod_dso__load_module_paths(struct mod_dso *self)
411{
412 struct utsname uts;
413 int count = 0, len, err = -1;
414 char *line = NULL;
415 FILE *file;
416 char *dpath, *dir;
417 size_t n;
418
419 if (uname(&uts) < 0)
420 return err;
421
422 len = strlen("/lib/modules/");
423 len += strlen(uts.release);
424 len += strlen("/modules.dep");
425
426 dpath = calloc(1, len + 1);
427 if (dpath == NULL)
428 return err;
429
430 strcat(dpath, "/lib/modules/");
431 strcat(dpath, uts.release);
432 strcat(dpath, "/modules.dep");
433
434 file = fopen(dpath, "r");
435 if (file == NULL)
436 goto out_failure;
437
438 dir = dirname(dpath);
439 if (!dir)
440 goto out_failure;
441 strcat(dir, "/");
442
443 while (!feof(file)) {
444 struct module *module;
445 char *name, *path, *tmp;
446 FILE *modfile;
447 int line_len;
448
449 line_len = getline(&line, &n, file);
450 if (line_len < 0)
451 break;
452
453 if (!line)
454 break;
455
456 line[--line_len] = '\0'; /* \n */
457
458 path = strchr(line, ':');
459 if (!path)
460 break;
461 *path = '\0';
462
463 path = strdup(line);
464 if (!path)
465 break;
466
467 if (!strstr(path, dir)) {
468 if (strncmp(path, "kernel/", 7))
469 break;
470
471 free(path);
472 path = calloc(1, strlen(dir) + strlen(line) + 1);
473 if (!path)
474 break;
475 strcat(path, dir);
476 strcat(path, line);
477 }
478
479 modfile = fopen(path, "r");
480 if (modfile == NULL)
481 break;
482 fclose(modfile);
483
484 name = strdup(path);
485 if (!name)
486 break;
487
488 name = strtok(name, "/");
489 tmp = name;
490
491 while (tmp) {
492 tmp = strtok(NULL, "/");
493 if (tmp)
494 name = tmp;
495 }
496
497 name = strsep(&name, ".");
498 if (!name)
499 break;
500
501 /* Quirk: replace '-' with '_' in all modules */
502 for (len = strlen(name); len; len--) {
503 if (*(name+len) == '-')
504 *(name+len) = '_';
505 }
506
507 module = module__new(name, path);
508 if (!module)
509 break;
510 mod_dso__insert_module(self, module);
511
512 module->sections = sec_dso__new_dso("sections");
513 if (!module->sections)
514 break;
515
516 module->active = mod_dso__load_sections(module);
517
518 if (module->active > 0)
519 count++;
520 }
521
522 if (feof(file))
523 err = count;
524 else
525 fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
526
527out_failure:
528 if (dpath)
529 free(dpath);
530 if (file)
531 fclose(file);
532 if (line)
533 free(line);
534
535 return err;
536}
537
538int mod_dso__load_modules(struct mod_dso *dso)
539{
540 int err;
541
542 err = mod_dso__load_module_paths(dso);
543
544 return err;
545}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
new file mode 100644
index 000000000000..8a592ef641ca
--- /dev/null
+++ b/tools/perf/util/module.h
@@ -0,0 +1,53 @@
1#ifndef _PERF_MODULE_
2#define _PERF_MODULE_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8
9struct section {
10 struct rb_node rb_node;
11 u64 hash;
12 u64 vma;
13 char *name;
14 char *path;
15};
16
17struct sec_dso {
18 struct list_head node;
19 struct rb_root secs;
20 struct section *(*find_section)(struct sec_dso *, const char *name);
21 char name[0];
22};
23
24struct module {
25 struct rb_node rb_node;
26 u64 hash;
27 char *name;
28 char *path;
29 struct sec_dso *sections;
30 int active;
31};
32
33struct mod_dso {
34 struct list_head node;
35 struct rb_root mods;
36 struct module *(*find_module)(struct mod_dso *, const char *name);
37 char name[0];
38};
39
40struct sec_dso *sec_dso__new_dso(const char *name);
41void sec_dso__delete_sections(struct sec_dso *self);
42void sec_dso__delete_self(struct sec_dso *self);
43size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
44struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
45
46struct mod_dso *mod_dso__new_dso(const char *name);
47void mod_dso__delete_modules(struct mod_dso *self);
48void mod_dso__delete_self(struct mod_dso *self);
49size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
50struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
51int mod_dso__load_modules(struct mod_dso *dso);
52
53#endif /* _PERF_MODULE_ */
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
index a28bccae5458..1915de20dcac 100644
--- a/tools/perf/util/pager.c
+++ b/tools/perf/util/pager.c
@@ -9,7 +9,6 @@
9 9
10static int spawned_pager; 10static int spawned_pager;
11 11
12#ifndef __MINGW32__
13static void pager_preexec(void) 12static void pager_preexec(void)
14{ 13{
15 /* 14 /*
@@ -24,7 +23,6 @@ static void pager_preexec(void)
24 23
25 setenv("LESS", "FRSX", 0); 24 setenv("LESS", "FRSX", 0);
26} 25}
27#endif
28 26
29static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; 27static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
30static struct child_process pager_process; 28static struct child_process pager_process;
@@ -70,9 +68,8 @@ void setup_pager(void)
70 pager_argv[2] = pager; 68 pager_argv[2] = pager;
71 pager_process.argv = pager_argv; 69 pager_process.argv = pager_argv;
72 pager_process.in = -1; 70 pager_process.in = -1;
73#ifndef __MINGW32__
74 pager_process.preexec_cb = pager_preexec; 71 pager_process.preexec_cb = pager_preexec;
75#endif 72
76 if (start_command(&pager_process)) 73 if (start_command(&pager_process))
77 return; 74 return;
78 75
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 35d04da38d6a..87c424de79ee 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,58 +1,62 @@
1 1
2#include "../perf.h"
3#include "util.h" 2#include "util.h"
3#include "../perf.h"
4#include "parse-options.h" 4#include "parse-options.h"
5#include "parse-events.h" 5#include "parse-events.h"
6#include "exec_cmd.h" 6#include "exec_cmd.h"
7#include "string.h" 7#include "string.h"
8 8#include "cache.h"
9extern char *strcasestr(const char *haystack, const char *needle); 9#include "header.h"
10 10
11int nr_counters; 11int nr_counters;
12 12
13struct perf_counter_attr attrs[MAX_COUNTERS]; 13struct perf_event_attr attrs[MAX_COUNTERS];
14 14
15struct event_symbol { 15struct event_symbol {
16 u8 type; 16 u8 type;
17 u64 config; 17 u64 config;
18 char *symbol; 18 const char *symbol;
19 const char *alias;
20};
21
22enum event_result {
23 EVT_FAILED,
24 EVT_HANDLED,
25 EVT_HANDLED_ALL
19}; 26};
20 27
21#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y 28char debugfs_path[MAXPATHLEN];
22#define CR(x, y) .type = PERF_TYPE_##x, .config = y 29
30#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
31#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
23 32
24static struct event_symbol event_symbols[] = { 33static struct event_symbol event_symbols[] = {
25 { C(HARDWARE, HW_CPU_CYCLES), "cpu-cycles", }, 34 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
26 { C(HARDWARE, HW_CPU_CYCLES), "cycles", }, 35 { CHW(INSTRUCTIONS), "instructions", "" },
27 { C(HARDWARE, HW_INSTRUCTIONS), "instructions", }, 36 { CHW(CACHE_REFERENCES), "cache-references", "" },
28 { C(HARDWARE, HW_CACHE_REFERENCES), "cache-references", }, 37 { CHW(CACHE_MISSES), "cache-misses", "" },
29 { C(HARDWARE, HW_CACHE_MISSES), "cache-misses", }, 38 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
30 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", }, 39 { CHW(BRANCH_MISSES), "branch-misses", "" },
31 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches", }, 40 { CHW(BUS_CYCLES), "bus-cycles", "" },
32 { C(HARDWARE, HW_BRANCH_MISSES), "branch-misses", }, 41
33 { C(HARDWARE, HW_BUS_CYCLES), "bus-cycles", }, 42 { CSW(CPU_CLOCK), "cpu-clock", "" },
34 43 { CSW(TASK_CLOCK), "task-clock", "" },
35 { C(SOFTWARE, SW_CPU_CLOCK), "cpu-clock", }, 44 { CSW(PAGE_FAULTS), "page-faults", "faults" },
36 { C(SOFTWARE, SW_TASK_CLOCK), "task-clock", }, 45 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
37 { C(SOFTWARE, SW_PAGE_FAULTS), "page-faults", }, 46 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
38 { C(SOFTWARE, SW_PAGE_FAULTS), "faults", }, 47 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
39 { C(SOFTWARE, SW_PAGE_FAULTS_MIN), "minor-faults", }, 48 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
40 { C(SOFTWARE, SW_PAGE_FAULTS_MAJ), "major-faults", },
41 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "context-switches", },
42 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "cs", },
43 { C(SOFTWARE, SW_CPU_MIGRATIONS), "cpu-migrations", },
44 { C(SOFTWARE, SW_CPU_MIGRATIONS), "migrations", },
45}; 49};
46 50
47#define __PERF_COUNTER_FIELD(config, name) \ 51#define __PERF_EVENT_FIELD(config, name) \
48 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT) 52 ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT)
49 53
50#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW) 54#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW)
51#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG) 55#define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG)
52#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) 56#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
53#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) 57#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
54 58
55static char *hw_event_names[] = { 59static const char *hw_event_names[] = {
56 "cycles", 60 "cycles",
57 "instructions", 61 "instructions",
58 "cache-references", 62 "cache-references",
@@ -62,7 +66,7 @@ static char *hw_event_names[] = {
62 "bus-cycles", 66 "bus-cycles",
63}; 67};
64 68
65static char *sw_event_names[] = { 69static const char *sw_event_names[] = {
66 "cpu-clock-msecs", 70 "cpu-clock-msecs",
67 "task-clock-msecs", 71 "task-clock-msecs",
68 "page-faults", 72 "page-faults",
@@ -74,33 +78,210 @@ static char *sw_event_names[] = {
74 78
75#define MAX_ALIASES 8 79#define MAX_ALIASES 8
76 80
77static char *hw_cache [][MAX_ALIASES] = { 81static const char *hw_cache[][MAX_ALIASES] = {
78 { "L1-data" , "l1-d", "l1d" }, 82 { "L1-dcache", "l1-d", "l1d", "L1-data", },
79 { "L1-instruction" , "l1-i", "l1i" }, 83 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
80 { "L2" , "l2" }, 84 { "LLC", "L2" },
81 { "Data-TLB" , "dtlb", "d-tlb" }, 85 { "dTLB", "d-tlb", "Data-TLB", },
82 { "Instruction-TLB" , "itlb", "i-tlb" }, 86 { "iTLB", "i-tlb", "Instruction-TLB", },
83 { "Branch" , "bpu" , "btb", "bpc" }, 87 { "branch", "branches", "bpu", "btb", "bpc", },
88};
89
90static const char *hw_cache_op[][MAX_ALIASES] = {
91 { "load", "loads", "read", },
92 { "store", "stores", "write", },
93 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
84}; 94};
85 95
86static char *hw_cache_op [][MAX_ALIASES] = { 96static const char *hw_cache_result[][MAX_ALIASES] = {
87 { "Load" , "read" }, 97 { "refs", "Reference", "ops", "access", },
88 { "Store" , "write" }, 98 { "misses", "miss", },
89 { "Prefetch" , "speculative-read", "speculative-load" },
90}; 99};
91 100
92static char *hw_cache_result [][MAX_ALIASES] = { 101#define C(x) PERF_COUNT_HW_CACHE_##x
93 { "Reference" , "ops", "access" }, 102#define CACHE_READ (1 << C(OP_READ))
94 { "Miss" }, 103#define CACHE_WRITE (1 << C(OP_WRITE))
104#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
105#define COP(x) (1 << x)
106
107/*
108 * cache operartion stat
109 * L1I : Read and prefetch only
110 * ITLB and BPU : Read-only
111 */
112static unsigned long hw_cache_stat[C(MAX)] = {
113 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
114 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
115 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
116 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
117 [C(ITLB)] = (CACHE_READ),
118 [C(BPU)] = (CACHE_READ),
95}; 119};
96 120
97char *event_name(int counter) 121#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
122 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
123 if (sys_dirent.d_type == DT_DIR && \
124 (strcmp(sys_dirent.d_name, ".")) && \
125 (strcmp(sys_dirent.d_name, "..")))
126
127static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
128{
129 char evt_path[MAXPATHLEN];
130 int fd;
131
132 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
133 sys_dir->d_name, evt_dir->d_name);
134 fd = open(evt_path, O_RDONLY);
135 if (fd < 0)
136 return -EINVAL;
137 close(fd);
138
139 return 0;
140}
141
142#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \
143 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
144 if (evt_dirent.d_type == DT_DIR && \
145 (strcmp(evt_dirent.d_name, ".")) && \
146 (strcmp(evt_dirent.d_name, "..")) && \
147 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
148
149#define MAX_EVENT_LENGTH 512
150
151int valid_debugfs_mount(const char *debugfs)
152{
153 struct statfs st_fs;
154
155 if (statfs(debugfs, &st_fs) < 0)
156 return -ENOENT;
157 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
158 return -ENOENT;
159 return 0;
160}
161
162struct tracepoint_path *tracepoint_id_to_path(u64 config)
163{
164 struct tracepoint_path *path = NULL;
165 DIR *sys_dir, *evt_dir;
166 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
167 char id_buf[4];
168 int fd;
169 u64 id;
170 char evt_path[MAXPATHLEN];
171 char dir_path[MAXPATHLEN];
172
173 if (valid_debugfs_mount(debugfs_path))
174 return NULL;
175
176 sys_dir = opendir(debugfs_path);
177 if (!sys_dir)
178 return NULL;
179
180 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
181
182 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
183 sys_dirent.d_name);
184 evt_dir = opendir(dir_path);
185 if (!evt_dir)
186 continue;
187
188 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
189
190 snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path,
191 evt_dirent.d_name);
192 fd = open(evt_path, O_RDONLY);
193 if (fd < 0)
194 continue;
195 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
196 close(fd);
197 continue;
198 }
199 close(fd);
200 id = atoll(id_buf);
201 if (id == config) {
202 closedir(evt_dir);
203 closedir(sys_dir);
204 path = calloc(1, sizeof(path));
205 path->system = malloc(MAX_EVENT_LENGTH);
206 if (!path->system) {
207 free(path);
208 return NULL;
209 }
210 path->name = malloc(MAX_EVENT_LENGTH);
211 if (!path->name) {
212 free(path->system);
213 free(path);
214 return NULL;
215 }
216 strncpy(path->system, sys_dirent.d_name,
217 MAX_EVENT_LENGTH);
218 strncpy(path->name, evt_dirent.d_name,
219 MAX_EVENT_LENGTH);
220 return path;
221 }
222 }
223 closedir(evt_dir);
224 }
225
226 closedir(sys_dir);
227 return NULL;
228}
229
230#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
231static const char *tracepoint_id_to_name(u64 config)
232{
233 static char buf[TP_PATH_LEN];
234 struct tracepoint_path *path;
235
236 path = tracepoint_id_to_path(config);
237 if (path) {
238 snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
239 free(path->name);
240 free(path->system);
241 free(path);
242 } else
243 snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
244
245 return buf;
246}
247
248static int is_cache_op_valid(u8 cache_type, u8 cache_op)
249{
250 if (hw_cache_stat[cache_type] & COP(cache_op))
251 return 1; /* valid */
252 else
253 return 0; /* invalid */
254}
255
256static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
257{
258 static char name[50];
259
260 if (cache_result) {
261 sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
262 hw_cache_op[cache_op][0],
263 hw_cache_result[cache_result][0]);
264 } else {
265 sprintf(name, "%s-%s", hw_cache[cache_type][0],
266 hw_cache_op[cache_op][1]);
267 }
268
269 return name;
270}
271
272const char *event_name(int counter)
98{ 273{
99 u64 config = attrs[counter].config; 274 u64 config = attrs[counter].config;
100 int type = attrs[counter].type; 275 int type = attrs[counter].type;
276
277 return __event_name(type, config);
278}
279
280const char *__event_name(int type, u64 config)
281{
101 static char buf[32]; 282 static char buf[32];
102 283
103 if (attrs[counter].type == PERF_TYPE_RAW) { 284 if (type == PERF_TYPE_RAW) {
104 sprintf(buf, "raw 0x%llx", config); 285 sprintf(buf, "raw 0x%llx", config);
105 return buf; 286 return buf;
106 } 287 }
@@ -113,7 +294,6 @@ char *event_name(int counter)
113 294
114 case PERF_TYPE_HW_CACHE: { 295 case PERF_TYPE_HW_CACHE: {
115 u8 cache_type, cache_op, cache_result; 296 u8 cache_type, cache_op, cache_result;
116 static char name[100];
117 297
118 cache_type = (config >> 0) & 0xff; 298 cache_type = (config >> 0) & 0xff;
119 if (cache_type > PERF_COUNT_HW_CACHE_MAX) 299 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
@@ -127,12 +307,10 @@ char *event_name(int counter)
127 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX) 307 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
128 return "unknown-ext-hardware-cache-result"; 308 return "unknown-ext-hardware-cache-result";
129 309
130 sprintf(name, "%s-Cache-%s-%ses", 310 if (!is_cache_op_valid(cache_type, cache_op))
131 hw_cache[cache_type][0], 311 return "invalid-cache";
132 hw_cache_op[cache_op][0],
133 hw_cache_result[cache_result][0]);
134 312
135 return name; 313 return event_cache_name(cache_type, cache_op, cache_result);
136 } 314 }
137 315
138 case PERF_TYPE_SOFTWARE: 316 case PERF_TYPE_SOFTWARE:
@@ -140,6 +318,9 @@ char *event_name(int counter)
140 return sw_event_names[config]; 318 return sw_event_names[config];
141 return "unknown-software"; 319 return "unknown-software";
142 320
321 case PERF_TYPE_TRACEPOINT:
322 return tracepoint_id_to_name(config);
323
143 default: 324 default:
144 break; 325 break;
145 } 326 }
@@ -147,43 +328,74 @@ char *event_name(int counter)
147 return "unknown"; 328 return "unknown";
148} 329}
149 330
150static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) 331static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
151{ 332{
152 int i, j; 333 int i, j;
334 int n, longest = -1;
153 335
154 for (i = 0; i < size; i++) { 336 for (i = 0; i < size; i++) {
155 for (j = 0; j < MAX_ALIASES; j++) { 337 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
156 if (!names[i][j]) 338 n = strlen(names[i][j]);
157 break; 339 if (n > longest && !strncasecmp(*str, names[i][j], n))
158 if (strcasestr(str, names[i][j])) 340 longest = n;
159 return i; 341 }
342 if (longest > 0) {
343 *str += longest;
344 return i;
160 } 345 }
161 } 346 }
162 347
163 return -1; 348 return -1;
164} 349}
165 350
166static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) 351static enum event_result
352parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
167{ 353{
168 int cache_type = -1, cache_op = 0, cache_result = 0; 354 const char *s = *str;
355 int cache_type = -1, cache_op = -1, cache_result = -1;
169 356
170 cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); 357 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
171 /* 358 /*
172 * No fallback - if we cannot get a clear cache type 359 * No fallback - if we cannot get a clear cache type
173 * then bail out: 360 * then bail out:
174 */ 361 */
175 if (cache_type == -1) 362 if (cache_type == -1)
176 return -EINVAL; 363 return EVT_FAILED;
364
365 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
366 ++s;
367
368 if (cache_op == -1) {
369 cache_op = parse_aliases(&s, hw_cache_op,
370 PERF_COUNT_HW_CACHE_OP_MAX);
371 if (cache_op >= 0) {
372 if (!is_cache_op_valid(cache_type, cache_op))
373 return 0;
374 continue;
375 }
376 }
377
378 if (cache_result == -1) {
379 cache_result = parse_aliases(&s, hw_cache_result,
380 PERF_COUNT_HW_CACHE_RESULT_MAX);
381 if (cache_result >= 0)
382 continue;
383 }
384
385 /*
386 * Can't parse this as a cache op or result, so back up
387 * to the '-'.
388 */
389 --s;
390 break;
391 }
177 392
178 cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
179 /* 393 /*
180 * Fall back to reads: 394 * Fall back to reads:
181 */ 395 */
182 if (cache_op == -1) 396 if (cache_op == -1)
183 cache_op = PERF_COUNT_HW_CACHE_OP_READ; 397 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
184 398
185 cache_result = parse_aliases(str, hw_cache_result,
186 PERF_COUNT_HW_CACHE_RESULT_MAX);
187 /* 399 /*
188 * Fall back to accesses: 400 * Fall back to accesses:
189 */ 401 */
@@ -193,82 +405,338 @@ static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *a
193 attr->config = cache_type | (cache_op << 8) | (cache_result << 16); 405 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
194 attr->type = PERF_TYPE_HW_CACHE; 406 attr->type = PERF_TYPE_HW_CACHE;
195 407
196 return 0; 408 *str = s;
409 return EVT_HANDLED;
197} 410}
198 411
199/* 412static enum event_result
200 * Each event can have multiple symbolic names. 413parse_single_tracepoint_event(char *sys_name,
201 * Symbolic names are (almost) exactly matched. 414 const char *evt_name,
202 */ 415 unsigned int evt_length,
203static int parse_event_symbols(const char *str, struct perf_counter_attr *attr) 416 char *flags,
417 struct perf_event_attr *attr,
418 const char **strp)
204{ 419{
205 u64 config, id; 420 char evt_path[MAXPATHLEN];
206 int type; 421 char id_buf[4];
207 unsigned int i; 422 u64 id;
208 const char *sep, *pstr; 423 int fd;
424
425 if (flags) {
426 if (!strncmp(flags, "record", strlen(flags))) {
427 attr->sample_type |= PERF_SAMPLE_RAW;
428 attr->sample_type |= PERF_SAMPLE_TIME;
429 attr->sample_type |= PERF_SAMPLE_CPU;
430 }
431 }
209 432
210 if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { 433 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
211 attr->type = PERF_TYPE_RAW; 434 sys_name, evt_name);
212 attr->config = config;
213 435
214 return 0; 436 fd = open(evt_path, O_RDONLY);
437 if (fd < 0)
438 return EVT_FAILED;
439
440 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
441 close(fd);
442 return EVT_FAILED;
215 } 443 }
216 444
217 pstr = str; 445 close(fd);
218 sep = strchr(pstr, ':'); 446 id = atoll(id_buf);
219 if (sep) { 447 attr->config = id;
220 type = atoi(pstr); 448 attr->type = PERF_TYPE_TRACEPOINT;
221 pstr = sep + 1; 449 *strp = evt_name + evt_length;
222 id = atoi(pstr); 450
223 sep = strchr(pstr, ':'); 451 return EVT_HANDLED;
224 if (sep) { 452}
225 pstr = sep + 1; 453
226 if (strchr(pstr, 'k')) 454/* sys + ':' + event + ':' + flags*/
227 attr->exclude_user = 1; 455#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
228 if (strchr(pstr, 'u')) 456static enum event_result
229 attr->exclude_kernel = 1; 457parse_subsystem_tracepoint_event(char *sys_name, char *flags)
458{
459 char evt_path[MAXPATHLEN];
460 struct dirent *evt_ent;
461 DIR *evt_dir;
462
463 snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name);
464 evt_dir = opendir(evt_path);
465
466 if (!evt_dir) {
467 perror("Can't open event dir");
468 return EVT_FAILED;
469 }
470
471 while ((evt_ent = readdir(evt_dir))) {
472 char event_opt[MAX_EVOPT_LEN + 1];
473 int len;
474 unsigned int rem = MAX_EVOPT_LEN;
475
476 if (!strcmp(evt_ent->d_name, ".")
477 || !strcmp(evt_ent->d_name, "..")
478 || !strcmp(evt_ent->d_name, "enable")
479 || !strcmp(evt_ent->d_name, "filter"))
480 continue;
481
482 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name,
483 evt_ent->d_name);
484 if (len < 0)
485 return EVT_FAILED;
486
487 rem -= len;
488 if (flags) {
489 if (rem < strlen(flags) + 1)
490 return EVT_FAILED;
491
492 strcat(event_opt, ":");
493 strcat(event_opt, flags);
230 } 494 }
231 attr->type = type;
232 attr->config = id;
233 495
496 if (parse_events(NULL, event_opt, 0))
497 return EVT_FAILED;
498 }
499
500 return EVT_HANDLED_ALL;
501}
502
503
504static enum event_result parse_tracepoint_event(const char **strp,
505 struct perf_event_attr *attr)
506{
507 const char *evt_name;
508 char *flags;
509 char sys_name[MAX_EVENT_LENGTH];
510 unsigned int sys_length, evt_length;
511
512 if (valid_debugfs_mount(debugfs_path))
513 return 0;
514
515 evt_name = strchr(*strp, ':');
516 if (!evt_name)
517 return EVT_FAILED;
518
519 sys_length = evt_name - *strp;
520 if (sys_length >= MAX_EVENT_LENGTH)
234 return 0; 521 return 0;
522
523 strncpy(sys_name, *strp, sys_length);
524 sys_name[sys_length] = '\0';
525 evt_name = evt_name + 1;
526
527 flags = strchr(evt_name, ':');
528 if (flags) {
529 /* split it out: */
530 evt_name = strndup(evt_name, flags - evt_name);
531 flags++;
235 } 532 }
236 533
237 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 534 evt_length = strlen(evt_name);
238 if (!strncmp(str, event_symbols[i].symbol, 535 if (evt_length >= MAX_EVENT_LENGTH)
239 strlen(event_symbols[i].symbol))) { 536 return EVT_FAILED;
537
538 if (!strcmp(evt_name, "*")) {
539 *strp = evt_name + evt_length;
540 return parse_subsystem_tracepoint_event(sys_name, flags);
541 } else
542 return parse_single_tracepoint_event(sys_name, evt_name,
543 evt_length, flags,
544 attr, strp);
545}
546
547static int check_events(const char *str, unsigned int i)
548{
549 int n;
240 550
551 n = strlen(event_symbols[i].symbol);
552 if (!strncmp(str, event_symbols[i].symbol, n))
553 return n;
554
555 n = strlen(event_symbols[i].alias);
556 if (n)
557 if (!strncmp(str, event_symbols[i].alias, n))
558 return n;
559 return 0;
560}
561
562static enum event_result
563parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
564{
565 const char *str = *strp;
566 unsigned int i;
567 int n;
568
569 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
570 n = check_events(str, i);
571 if (n > 0) {
241 attr->type = event_symbols[i].type; 572 attr->type = event_symbols[i].type;
242 attr->config = event_symbols[i].config; 573 attr->config = event_symbols[i].config;
574 *strp = str + n;
575 return EVT_HANDLED;
576 }
577 }
578 return EVT_FAILED;
579}
243 580
244 return 0; 581static enum event_result
582parse_raw_event(const char **strp, struct perf_event_attr *attr)
583{
584 const char *str = *strp;
585 u64 config;
586 int n;
587
588 if (*str != 'r')
589 return EVT_FAILED;
590 n = hex2u64(str + 1, &config);
591 if (n > 0) {
592 *strp = str + n + 1;
593 attr->type = PERF_TYPE_RAW;
594 attr->config = config;
595 return EVT_HANDLED;
596 }
597 return EVT_FAILED;
598}
599
600static enum event_result
601parse_numeric_event(const char **strp, struct perf_event_attr *attr)
602{
603 const char *str = *strp;
604 char *endp;
605 unsigned long type;
606 u64 config;
607
608 type = strtoul(str, &endp, 0);
609 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
610 str = endp + 1;
611 config = strtoul(str, &endp, 0);
612 if (endp > str) {
613 attr->type = type;
614 attr->config = config;
615 *strp = endp;
616 return EVT_HANDLED;
245 } 617 }
246 } 618 }
619 return EVT_FAILED;
620}
621
622static enum event_result
623parse_event_modifier(const char **strp, struct perf_event_attr *attr)
624{
625 const char *str = *strp;
626 int eu = 1, ek = 1, eh = 1;
627
628 if (*str++ != ':')
629 return 0;
630 while (*str) {
631 if (*str == 'u')
632 eu = 0;
633 else if (*str == 'k')
634 ek = 0;
635 else if (*str == 'h')
636 eh = 0;
637 else
638 break;
639 ++str;
640 }
641 if (str >= *strp + 2) {
642 *strp = str;
643 attr->exclude_user = eu;
644 attr->exclude_kernel = ek;
645 attr->exclude_hv = eh;
646 return 1;
647 }
648 return 0;
649}
650
651/*
652 * Each event can have multiple symbolic names.
653 * Symbolic names are (almost) exactly matched.
654 */
655static enum event_result
656parse_event_symbols(const char **str, struct perf_event_attr *attr)
657{
658 enum event_result ret;
659
660 ret = parse_tracepoint_event(str, attr);
661 if (ret != EVT_FAILED)
662 goto modifier;
663
664 ret = parse_raw_event(str, attr);
665 if (ret != EVT_FAILED)
666 goto modifier;
667
668 ret = parse_numeric_event(str, attr);
669 if (ret != EVT_FAILED)
670 goto modifier;
247 671
248 return parse_generic_hw_symbols(str, attr); 672 ret = parse_symbolic_event(str, attr);
673 if (ret != EVT_FAILED)
674 goto modifier;
675
676 ret = parse_generic_hw_event(str, attr);
677 if (ret != EVT_FAILED)
678 goto modifier;
679
680 return EVT_FAILED;
681
682modifier:
683 parse_event_modifier(str, attr);
684
685 return ret;
249} 686}
250 687
251int parse_events(const struct option *opt, const char *str, int unset) 688static void store_event_type(const char *orgname)
252{ 689{
253 struct perf_counter_attr attr; 690 char filename[PATH_MAX], *c;
254 int ret; 691 FILE *file;
692 int id;
693
694 sprintf(filename, "/sys/kernel/debug/tracing/events/%s/id", orgname);
695 c = strchr(filename, ':');
696 if (c)
697 *c = '/';
698
699 file = fopen(filename, "r");
700 if (!file)
701 return;
702 if (fscanf(file, "%i", &id) < 1)
703 die("cannot store event ID");
704 fclose(file);
705 perf_header__push_event(id, orgname);
706}
255 707
256 memset(&attr, 0, sizeof(attr));
257again:
258 if (nr_counters == MAX_COUNTERS)
259 return -1;
260 708
261 ret = parse_event_symbols(str, &attr); 709int parse_events(const struct option *opt __used, const char *str, int unset __used)
262 if (ret < 0) 710{
263 return ret; 711 struct perf_event_attr attr;
712 enum event_result ret;
713
714 if (strchr(str, ':'))
715 store_event_type(str);
716
717 for (;;) {
718 if (nr_counters == MAX_COUNTERS)
719 return -1;
720
721 memset(&attr, 0, sizeof(attr));
722 ret = parse_event_symbols(&str, &attr);
723 if (ret == EVT_FAILED)
724 return -1;
725
726 if (!(*str == 0 || *str == ',' || isspace(*str)))
727 return -1;
264 728
265 attrs[nr_counters] = attr; 729 if (ret != EVT_HANDLED_ALL) {
266 nr_counters++; 730 attrs[nr_counters] = attr;
731 nr_counters++;
732 }
267 733
268 str = strstr(str, ","); 734 if (*str == 0)
269 if (str) { 735 break;
270 str++; 736 if (*str == ',')
271 goto again; 737 ++str;
738 while (isspace(*str))
739 ++str;
272 } 740 }
273 741
274 return 0; 742 return 0;
@@ -283,34 +751,93 @@ static const char * const event_type_descriptors[] = {
283}; 751};
284 752
285/* 753/*
754 * Print the events from <debugfs_mount_point>/tracing/events
755 */
756
757static void print_tracepoint_events(void)
758{
759 DIR *sys_dir, *evt_dir;
760 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
761 char evt_path[MAXPATHLEN];
762 char dir_path[MAXPATHLEN];
763
764 if (valid_debugfs_mount(debugfs_path))
765 return;
766
767 sys_dir = opendir(debugfs_path);
768 if (!sys_dir)
769 return;
770
771 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
772
773 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
774 sys_dirent.d_name);
775 evt_dir = opendir(dir_path);
776 if (!evt_dir)
777 continue;
778
779 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
780 snprintf(evt_path, MAXPATHLEN, "%s:%s",
781 sys_dirent.d_name, evt_dirent.d_name);
782 fprintf(stderr, " %-42s [%s]\n", evt_path,
783 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
784 }
785 closedir(evt_dir);
786 }
787 closedir(sys_dir);
788}
789
790/*
286 * Print the help text for the event symbols: 791 * Print the help text for the event symbols:
287 */ 792 */
288void print_events(void) 793void print_events(void)
289{ 794{
290 struct event_symbol *syms = event_symbols; 795 struct event_symbol *syms = event_symbols;
291 unsigned int i, type, prev_type = -1; 796 unsigned int i, type, op, prev_type = -1;
797 char name[40];
292 798
293 fprintf(stderr, "\n"); 799 fprintf(stderr, "\n");
294 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 800 fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
295 801
296 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 802 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
297 type = syms->type + 1; 803 type = syms->type + 1;
298 if (type > ARRAY_SIZE(event_type_descriptors)) 804 if (type >= ARRAY_SIZE(event_type_descriptors))
299 type = 0; 805 type = 0;
300 806
301 if (type != prev_type) 807 if (type != prev_type)
302 fprintf(stderr, "\n"); 808 fprintf(stderr, "\n");
303 809
304 fprintf(stderr, " %-30s [%s]\n", syms->symbol, 810 if (strlen(syms->alias))
811 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
812 else
813 strcpy(name, syms->symbol);
814 fprintf(stderr, " %-42s [%s]\n", name,
305 event_type_descriptors[type]); 815 event_type_descriptors[type]);
306 816
307 prev_type = type; 817 prev_type = type;
308 } 818 }
309 819
310 fprintf(stderr, "\n"); 820 fprintf(stderr, "\n");
311 fprintf(stderr, " %-30s [raw hardware event descriptor]\n", 821 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
822 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
823 /* skip invalid cache type */
824 if (!is_cache_op_valid(type, op))
825 continue;
826
827 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
828 fprintf(stderr, " %-42s [%s]\n",
829 event_cache_name(type, op, i),
830 event_type_descriptors[4]);
831 }
832 }
833 }
834
835 fprintf(stderr, "\n");
836 fprintf(stderr, " %-42s [raw hardware event descriptor]\n",
312 "rNNN"); 837 "rNNN");
313 fprintf(stderr, "\n"); 838 fprintf(stderr, "\n");
314 839
840 print_tracepoint_events();
841
315 exit(129); 842 exit(129);
316} 843}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index e3d552908e60..30c608112845 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -1,13 +1,25 @@
1 1#ifndef _PARSE_EVENTS_H
2#define _PARSE_EVENTS_H
2/* 3/*
3 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
4 */ 5 */
5 6
7struct option;
8
9struct tracepoint_path {
10 char *system;
11 char *name;
12 struct tracepoint_path *next;
13};
14
15extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
16
6extern int nr_counters; 17extern int nr_counters;
7 18
8extern struct perf_counter_attr attrs[MAX_COUNTERS]; 19extern struct perf_event_attr attrs[MAX_COUNTERS];
9 20
10extern char *event_name(int ctr); 21extern const char *event_name(int ctr);
22extern const char *__event_name(int type, u64 config);
11 23
12extern int parse_events(const struct option *opt, const char *str, int unset); 24extern int parse_events(const struct option *opt, const char *str, int unset);
13 25
@@ -15,3 +27,8 @@ extern int parse_events(const struct option *opt, const char *str, int unset);
15 27
16extern void print_events(void); 28extern void print_events(void);
17 29
30extern char debugfs_path[];
31extern int valid_debugfs_mount(const char *debugfs);
32
33
34#endif /* _PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index b3affb1658d2..6d8af48c925e 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -20,7 +20,8 @@ static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
20 if (p->opt) { 20 if (p->opt) {
21 *arg = p->opt; 21 *arg = p->opt;
22 p->opt = NULL; 22 p->opt = NULL;
23 } else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) { 23 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
24 **(p->argv + 1) == '-')) {
24 *arg = (const char *)opt->defval; 25 *arg = (const char *)opt->defval;
25 } else if (p->argc > 1) { 26 } else if (p->argc > 1) {
26 p->argc--; 27 p->argc--;
@@ -52,6 +53,12 @@ static int get_value(struct parse_opt_ctx_t *p,
52 case OPTION_SET_INT: 53 case OPTION_SET_INT:
53 case OPTION_SET_PTR: 54 case OPTION_SET_PTR:
54 return opterror(opt, "takes no value", flags); 55 return opterror(opt, "takes no value", flags);
56 case OPTION_END:
57 case OPTION_ARGUMENT:
58 case OPTION_GROUP:
59 case OPTION_STRING:
60 case OPTION_INTEGER:
61 case OPTION_LONG:
55 default: 62 default:
56 break; 63 break;
57 } 64 }
@@ -129,6 +136,9 @@ static int get_value(struct parse_opt_ctx_t *p,
129 return opterror(opt, "expects a numerical value", flags); 136 return opterror(opt, "expects a numerical value", flags);
130 return 0; 137 return 0;
131 138
139 case OPTION_END:
140 case OPTION_ARGUMENT:
141 case OPTION_GROUP:
132 default: 142 default:
133 die("should not happen, someone must be hit on the forehead"); 143 die("should not happen, someone must be hit on the forehead");
134 } 144 }
@@ -295,6 +305,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
295 return parse_options_usage(usagestr, options); 305 return parse_options_usage(usagestr, options);
296 case -2: 306 case -2:
297 goto unknown; 307 goto unknown;
308 default:
309 break;
298 } 310 }
299 if (ctx->opt) 311 if (ctx->opt)
300 check_typos(arg + 1, options); 312 check_typos(arg + 1, options);
@@ -313,6 +325,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
313 ctx->argv[0] = strdup(ctx->opt - 1); 325 ctx->argv[0] = strdup(ctx->opt - 1);
314 *(char *)ctx->argv[0] = '-'; 326 *(char *)ctx->argv[0] = '-';
315 goto unknown; 327 goto unknown;
328 default:
329 break;
316 } 330 }
317 } 331 }
318 continue; 332 continue;
@@ -335,6 +349,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
335 return parse_options_usage(usagestr, options); 349 return parse_options_usage(usagestr, options);
336 case -2: 350 case -2:
337 goto unknown; 351 goto unknown;
352 default:
353 break;
338 } 354 }
339 continue; 355 continue;
340unknown: 356unknown:
@@ -455,6 +471,13 @@ int usage_with_options_internal(const char * const *usagestr,
455 } 471 }
456 break; 472 break;
457 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */ 473 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
474 case OPTION_END:
475 case OPTION_GROUP:
476 case OPTION_BIT:
477 case OPTION_BOOLEAN:
478 case OPTION_SET_INT:
479 case OPTION_SET_PTR:
480 case OPTION_LONG:
458 break; 481 break;
459 } 482 }
460 483
@@ -485,7 +508,7 @@ int parse_options_usage(const char * const *usagestr,
485} 508}
486 509
487 510
488int parse_opt_verbosity_cb(const struct option *opt, const char *arg, 511int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
489 int unset) 512 int unset)
490{ 513{
491 int *target = opt->value; 514 int *target = opt->value;
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index a1039a6ce0eb..2ee248ff27e5 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -90,21 +90,24 @@ struct option {
90 intptr_t defval; 90 intptr_t defval;
91}; 91};
92 92
93#define OPT_END() { OPTION_END } 93#define OPT_END() { .type = OPTION_END }
94#define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) } 94#define OPT_ARGUMENT(l, h) { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
95#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) } 95#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) }
96#define OPT_BIT(s, l, v, h, b) { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) } 96#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (b) }
97#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) } 97#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
98#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) } 98#define OPT_SET_INT(s, l, v, h, i) { .type = OPTION_SET_INT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (i) }
99#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) } 99#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
100#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), NULL, (h) } 100#define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
101#define OPT_LONG(s, l, v, h) { OPTION_LONG, (s), (l), (v), NULL, (h) } 101#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
102#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) } 102#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h) }
103#define OPT_DATE(s, l, v, h) \ 103#define OPT_DATE(s, l, v, h) \
104 { OPTION_CALLBACK, (s), (l), (v), "time",(h), 0, \ 104 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
105 parse_opt_approxidate_cb }
106#define OPT_CALLBACK(s, l, v, a, h, f) \ 105#define OPT_CALLBACK(s, l, v, a, h, f) \
107 { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) } 106 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
107#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
108 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
109#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
110 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
108 111
109/* parse_options() will filter out the processed options and leave the 112/* parse_options() will filter out the processed options and leave the
110 * non-option argments in argv[]. 113 * non-option argments in argv[].
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index a501a40dd2cb..fd1f2faaade4 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -17,7 +17,7 @@ static char bad_path[] = "/bad-path/";
17 * Two hacks: 17 * Two hacks:
18 */ 18 */
19 19
20static char *get_perf_dir(void) 20static const char *get_perf_dir(void)
21{ 21{
22 return "."; 22 return ".";
23} 23}
@@ -38,8 +38,9 @@ size_t strlcpy(char *dest, const char *src, size_t size)
38static char *get_pathname(void) 38static char *get_pathname(void)
39{ 39{
40 static char pathname_array[4][PATH_MAX]; 40 static char pathname_array[4][PATH_MAX];
41 static int index; 41 static int idx;
42 return pathname_array[3 & ++index]; 42
43 return pathname_array[3 & ++idx];
43} 44}
44 45
45static char *cleanup_path(char *path) 46static char *cleanup_path(char *path)
@@ -161,20 +162,24 @@ int perf_mkstemp(char *path, size_t len, const char *template)
161} 162}
162 163
163 164
164const char *make_relative_path(const char *abs, const char *base) 165const char *make_relative_path(const char *abs_path, const char *base)
165{ 166{
166 static char buf[PATH_MAX + 1]; 167 static char buf[PATH_MAX + 1];
167 int baselen; 168 int baselen;
169
168 if (!base) 170 if (!base)
169 return abs; 171 return abs_path;
172
170 baselen = strlen(base); 173 baselen = strlen(base);
171 if (prefixcmp(abs, base)) 174 if (prefixcmp(abs_path, base))
172 return abs; 175 return abs_path;
173 if (abs[baselen] == '/') 176 if (abs_path[baselen] == '/')
174 baselen++; 177 baselen++;
175 else if (base[baselen - 1] != '/') 178 else if (base[baselen - 1] != '/')
176 return abs; 179 return abs_path;
177 strcpy(buf, abs + baselen); 180
181 strcpy(buf, abs_path + baselen);
182
178 return buf; 183 return buf;
179} 184}
180 185
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
index f18c5212bc92..2726fe40eb5d 100644
--- a/tools/perf/util/quote.c
+++ b/tools/perf/util/quote.c
@@ -162,12 +162,16 @@ static inline int sq_must_quote(char c)
162 return sq_lookup[(unsigned char)c] + quote_path_fully > 0; 162 return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
163} 163}
164 164
165/* returns the longest prefix not needing a quote up to maxlen if positive. 165/*
166 This stops at the first \0 because it's marked as a character needing an 166 * Returns the longest prefix not needing a quote up to maxlen if
167 escape */ 167 * positive.
168static size_t next_quote_pos(const char *s, ssize_t maxlen) 168 * This stops at the first \0 because it's marked as a character
169 * needing an escape.
170 */
171static ssize_t next_quote_pos(const char *s, ssize_t maxlen)
169{ 172{
170 size_t len; 173 ssize_t len;
174
171 if (maxlen < 0) { 175 if (maxlen < 0) {
172 for (len = 0; !sq_must_quote(s[len]); len++); 176 for (len = 0; !sq_must_quote(s[len]); len++);
173 } else { 177 } else {
@@ -192,22 +196,22 @@ static size_t next_quote_pos(const char *s, ssize_t maxlen)
192static size_t quote_c_style_counted(const char *name, ssize_t maxlen, 196static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
193 struct strbuf *sb, FILE *fp, int no_dq) 197 struct strbuf *sb, FILE *fp, int no_dq)
194{ 198{
195#undef EMIT 199#define EMIT(c) \
196#define EMIT(c) \ 200 do { \
197 do { \ 201 if (sb) strbuf_addch(sb, (c)); \
198 if (sb) strbuf_addch(sb, (c)); \ 202 if (fp) fputc((c), fp); \
199 if (fp) fputc((c), fp); \ 203 count++; \
200 count++; \
201 } while (0) 204 } while (0)
202#define EMITBUF(s, l) \ 205
203 do { \ 206#define EMITBUF(s, l) \
204 int __ret; \ 207 do { \
205 if (sb) strbuf_add(sb, (s), (l)); \ 208 int __ret; \
206 if (fp) __ret = fwrite((s), (l), 1, fp); \ 209 if (sb) strbuf_add(sb, (s), (l)); \
207 count += (l); \ 210 if (fp) __ret = fwrite((s), (l), 1, fp); \
211 count += (l); \
208 } while (0) 212 } while (0)
209 213
210 size_t len, count = 0; 214 ssize_t len, count = 0;
211 const char *p = name; 215 const char *p = name;
212 216
213 for (;;) { 217 for (;;) {
@@ -273,8 +277,8 @@ void write_name_quoted(const char *name, FILE *fp, int terminator)
273 fputc(terminator, fp); 277 fputc(terminator, fp);
274} 278}
275 279
276extern void write_name_quotedpfx(const char *pfx, size_t pfxlen, 280void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
277 const char *name, FILE *fp, int terminator) 281 const char *name, FILE *fp, int terminator)
278{ 282{
279 int needquote = 0; 283 int needquote = 0;
280 284
@@ -306,7 +310,7 @@ char *quote_path_relative(const char *in, int len,
306 len = strlen(in); 310 len = strlen(in);
307 311
308 /* "../" prefix itself does not need quoting, but "in" might. */ 312 /* "../" prefix itself does not need quoting, but "in" might. */
309 needquote = next_quote_pos(in, len) < len; 313 needquote = (next_quote_pos(in, len) < len);
310 strbuf_setlen(out, 0); 314 strbuf_setlen(out, 0);
311 strbuf_grow(out, len); 315 strbuf_grow(out, len);
312 316
@@ -314,7 +318,7 @@ char *quote_path_relative(const char *in, int len,
314 strbuf_addch(out, '"'); 318 strbuf_addch(out, '"');
315 if (prefix) { 319 if (prefix) {
316 int off = 0; 320 int off = 0;
317 while (prefix[off] && off < len && prefix[off] == in[off]) 321 while (off < len && prefix[off] && prefix[off] == in[off])
318 if (prefix[off] == '/') { 322 if (prefix[off] == '/') {
319 prefix += off + 1; 323 prefix += off + 1;
320 in += off + 1; 324 in += off + 1;
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index 5dfad89816db..a5454a1d1c13 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -53,7 +53,7 @@ extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq
53extern void quote_two_c_style(struct strbuf *, const char *, const char *, int); 53extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
54 54
55extern void write_name_quoted(const char *name, FILE *, int terminator); 55extern void write_name_quoted(const char *name, FILE *, int terminator);
56extern void write_name_quotedpfx(const char *pfx, size_t pfxlen, 56extern void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
57 const char *name, FILE *, int terminator); 57 const char *name, FILE *, int terminator);
58 58
59/* quote path as relative to the given prefix */ 59/* quote path as relative to the given prefix */
diff --git a/tools/perf/util/rbtree.c b/tools/perf/util/rbtree.c
deleted file mode 100644
index b15ba9c7cb3f..000000000000
--- a/tools/perf/util/rbtree.c
+++ /dev/null
@@ -1,383 +0,0 @@
1/*
2 Red Black Trees
3 (C) 1999 Andrea Arcangeli <andrea@suse.de>
4 (C) 2002 David Woodhouse <dwmw2@infradead.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 linux/lib/rbtree.c
21*/
22
23#include "rbtree.h"
24
25static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
26{
27 struct rb_node *right = node->rb_right;
28 struct rb_node *parent = rb_parent(node);
29
30 if ((node->rb_right = right->rb_left))
31 rb_set_parent(right->rb_left, node);
32 right->rb_left = node;
33
34 rb_set_parent(right, parent);
35
36 if (parent)
37 {
38 if (node == parent->rb_left)
39 parent->rb_left = right;
40 else
41 parent->rb_right = right;
42 }
43 else
44 root->rb_node = right;
45 rb_set_parent(node, right);
46}
47
48static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
49{
50 struct rb_node *left = node->rb_left;
51 struct rb_node *parent = rb_parent(node);
52
53 if ((node->rb_left = left->rb_right))
54 rb_set_parent(left->rb_right, node);
55 left->rb_right = node;
56
57 rb_set_parent(left, parent);
58
59 if (parent)
60 {
61 if (node == parent->rb_right)
62 parent->rb_right = left;
63 else
64 parent->rb_left = left;
65 }
66 else
67 root->rb_node = left;
68 rb_set_parent(node, left);
69}
70
71void rb_insert_color(struct rb_node *node, struct rb_root *root)
72{
73 struct rb_node *parent, *gparent;
74
75 while ((parent = rb_parent(node)) && rb_is_red(parent))
76 {
77 gparent = rb_parent(parent);
78
79 if (parent == gparent->rb_left)
80 {
81 {
82 register struct rb_node *uncle = gparent->rb_right;
83 if (uncle && rb_is_red(uncle))
84 {
85 rb_set_black(uncle);
86 rb_set_black(parent);
87 rb_set_red(gparent);
88 node = gparent;
89 continue;
90 }
91 }
92
93 if (parent->rb_right == node)
94 {
95 register struct rb_node *tmp;
96 __rb_rotate_left(parent, root);
97 tmp = parent;
98 parent = node;
99 node = tmp;
100 }
101
102 rb_set_black(parent);
103 rb_set_red(gparent);
104 __rb_rotate_right(gparent, root);
105 } else {
106 {
107 register struct rb_node *uncle = gparent->rb_left;
108 if (uncle && rb_is_red(uncle))
109 {
110 rb_set_black(uncle);
111 rb_set_black(parent);
112 rb_set_red(gparent);
113 node = gparent;
114 continue;
115 }
116 }
117
118 if (parent->rb_left == node)
119 {
120 register struct rb_node *tmp;
121 __rb_rotate_right(parent, root);
122 tmp = parent;
123 parent = node;
124 node = tmp;
125 }
126
127 rb_set_black(parent);
128 rb_set_red(gparent);
129 __rb_rotate_left(gparent, root);
130 }
131 }
132
133 rb_set_black(root->rb_node);
134}
135
136static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
137 struct rb_root *root)
138{
139 struct rb_node *other;
140
141 while ((!node || rb_is_black(node)) && node != root->rb_node)
142 {
143 if (parent->rb_left == node)
144 {
145 other = parent->rb_right;
146 if (rb_is_red(other))
147 {
148 rb_set_black(other);
149 rb_set_red(parent);
150 __rb_rotate_left(parent, root);
151 other = parent->rb_right;
152 }
153 if ((!other->rb_left || rb_is_black(other->rb_left)) &&
154 (!other->rb_right || rb_is_black(other->rb_right)))
155 {
156 rb_set_red(other);
157 node = parent;
158 parent = rb_parent(node);
159 }
160 else
161 {
162 if (!other->rb_right || rb_is_black(other->rb_right))
163 {
164 rb_set_black(other->rb_left);
165 rb_set_red(other);
166 __rb_rotate_right(other, root);
167 other = parent->rb_right;
168 }
169 rb_set_color(other, rb_color(parent));
170 rb_set_black(parent);
171 rb_set_black(other->rb_right);
172 __rb_rotate_left(parent, root);
173 node = root->rb_node;
174 break;
175 }
176 }
177 else
178 {
179 other = parent->rb_left;
180 if (rb_is_red(other))
181 {
182 rb_set_black(other);
183 rb_set_red(parent);
184 __rb_rotate_right(parent, root);
185 other = parent->rb_left;
186 }
187 if ((!other->rb_left || rb_is_black(other->rb_left)) &&
188 (!other->rb_right || rb_is_black(other->rb_right)))
189 {
190 rb_set_red(other);
191 node = parent;
192 parent = rb_parent(node);
193 }
194 else
195 {
196 if (!other->rb_left || rb_is_black(other->rb_left))
197 {
198 rb_set_black(other->rb_right);
199 rb_set_red(other);
200 __rb_rotate_left(other, root);
201 other = parent->rb_left;
202 }
203 rb_set_color(other, rb_color(parent));
204 rb_set_black(parent);
205 rb_set_black(other->rb_left);
206 __rb_rotate_right(parent, root);
207 node = root->rb_node;
208 break;
209 }
210 }
211 }
212 if (node)
213 rb_set_black(node);
214}
215
216void rb_erase(struct rb_node *node, struct rb_root *root)
217{
218 struct rb_node *child, *parent;
219 int color;
220
221 if (!node->rb_left)
222 child = node->rb_right;
223 else if (!node->rb_right)
224 child = node->rb_left;
225 else
226 {
227 struct rb_node *old = node, *left;
228
229 node = node->rb_right;
230 while ((left = node->rb_left) != NULL)
231 node = left;
232 child = node->rb_right;
233 parent = rb_parent(node);
234 color = rb_color(node);
235
236 if (child)
237 rb_set_parent(child, parent);
238 if (parent == old) {
239 parent->rb_right = child;
240 parent = node;
241 } else
242 parent->rb_left = child;
243
244 node->rb_parent_color = old->rb_parent_color;
245 node->rb_right = old->rb_right;
246 node->rb_left = old->rb_left;
247
248 if (rb_parent(old))
249 {
250 if (rb_parent(old)->rb_left == old)
251 rb_parent(old)->rb_left = node;
252 else
253 rb_parent(old)->rb_right = node;
254 } else
255 root->rb_node = node;
256
257 rb_set_parent(old->rb_left, node);
258 if (old->rb_right)
259 rb_set_parent(old->rb_right, node);
260 goto color;
261 }
262
263 parent = rb_parent(node);
264 color = rb_color(node);
265
266 if (child)
267 rb_set_parent(child, parent);
268 if (parent)
269 {
270 if (parent->rb_left == node)
271 parent->rb_left = child;
272 else
273 parent->rb_right = child;
274 }
275 else
276 root->rb_node = child;
277
278 color:
279 if (color == RB_BLACK)
280 __rb_erase_color(child, parent, root);
281}
282
283/*
284 * This function returns the first node (in sort order) of the tree.
285 */
286struct rb_node *rb_first(const struct rb_root *root)
287{
288 struct rb_node *n;
289
290 n = root->rb_node;
291 if (!n)
292 return NULL;
293 while (n->rb_left)
294 n = n->rb_left;
295 return n;
296}
297
298struct rb_node *rb_last(const struct rb_root *root)
299{
300 struct rb_node *n;
301
302 n = root->rb_node;
303 if (!n)
304 return NULL;
305 while (n->rb_right)
306 n = n->rb_right;
307 return n;
308}
309
310struct rb_node *rb_next(const struct rb_node *node)
311{
312 struct rb_node *parent;
313
314 if (rb_parent(node) == node)
315 return NULL;
316
317 /* If we have a right-hand child, go down and then left as far
318 as we can. */
319 if (node->rb_right) {
320 node = node->rb_right;
321 while (node->rb_left)
322 node=node->rb_left;
323 return (struct rb_node *)node;
324 }
325
326 /* No right-hand children. Everything down and left is
327 smaller than us, so any 'next' node must be in the general
328 direction of our parent. Go up the tree; any time the
329 ancestor is a right-hand child of its parent, keep going
330 up. First time it's a left-hand child of its parent, said
331 parent is our 'next' node. */
332 while ((parent = rb_parent(node)) && node == parent->rb_right)
333 node = parent;
334
335 return parent;
336}
337
338struct rb_node *rb_prev(const struct rb_node *node)
339{
340 struct rb_node *parent;
341
342 if (rb_parent(node) == node)
343 return NULL;
344
345 /* If we have a left-hand child, go down and then right as far
346 as we can. */
347 if (node->rb_left) {
348 node = node->rb_left;
349 while (node->rb_right)
350 node=node->rb_right;
351 return (struct rb_node *)node;
352 }
353
354 /* No left-hand children. Go up till we find an ancestor which
355 is a right-hand child of its parent */
356 while ((parent = rb_parent(node)) && node == parent->rb_left)
357 node = parent;
358
359 return parent;
360}
361
362void rb_replace_node(struct rb_node *victim, struct rb_node *new,
363 struct rb_root *root)
364{
365 struct rb_node *parent = rb_parent(victim);
366
367 /* Set the surrounding nodes to point to the replacement */
368 if (parent) {
369 if (victim == parent->rb_left)
370 parent->rb_left = new;
371 else
372 parent->rb_right = new;
373 } else {
374 root->rb_node = new;
375 }
376 if (victim->rb_left)
377 rb_set_parent(victim->rb_left, new);
378 if (victim->rb_right)
379 rb_set_parent(victim->rb_right, new);
380
381 /* Copy the pointers/colour from the victim to the replacement */
382 *new = *victim;
383}
diff --git a/tools/perf/util/rbtree.h b/tools/perf/util/rbtree.h
deleted file mode 100644
index 6bdc488a47fb..000000000000
--- a/tools/perf/util/rbtree.h
+++ /dev/null
@@ -1,171 +0,0 @@
1/*
2 Red Black Trees
3 (C) 1999 Andrea Arcangeli <andrea@suse.de>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 linux/include/linux/rbtree.h
20
21 To use rbtrees you'll have to implement your own insert and search cores.
22 This will avoid us to use callbacks and to drop drammatically performances.
23 I know it's not the cleaner way, but in C (not in C++) to get
24 performances and genericity...
25
26 Some example of insert and search follows here. The search is a plain
27 normal search over an ordered tree. The insert instead must be implemented
28 int two steps: as first thing the code must insert the element in
29 order as a red leaf in the tree, then the support library function
30 rb_insert_color() must be called. Such function will do the
31 not trivial work to rebalance the rbtree if necessary.
32
33-----------------------------------------------------------------------
34static inline struct page * rb_search_page_cache(struct inode * inode,
35 unsigned long offset)
36{
37 struct rb_node * n = inode->i_rb_page_cache.rb_node;
38 struct page * page;
39
40 while (n)
41 {
42 page = rb_entry(n, struct page, rb_page_cache);
43
44 if (offset < page->offset)
45 n = n->rb_left;
46 else if (offset > page->offset)
47 n = n->rb_right;
48 else
49 return page;
50 }
51 return NULL;
52}
53
54static inline struct page * __rb_insert_page_cache(struct inode * inode,
55 unsigned long offset,
56 struct rb_node * node)
57{
58 struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
59 struct rb_node * parent = NULL;
60 struct page * page;
61
62 while (*p)
63 {
64 parent = *p;
65 page = rb_entry(parent, struct page, rb_page_cache);
66
67 if (offset < page->offset)
68 p = &(*p)->rb_left;
69 else if (offset > page->offset)
70 p = &(*p)->rb_right;
71 else
72 return page;
73 }
74
75 rb_link_node(node, parent, p);
76
77 return NULL;
78}
79
80static inline struct page * rb_insert_page_cache(struct inode * inode,
81 unsigned long offset,
82 struct rb_node * node)
83{
84 struct page * ret;
85 if ((ret = __rb_insert_page_cache(inode, offset, node)))
86 goto out;
87 rb_insert_color(node, &inode->i_rb_page_cache);
88 out:
89 return ret;
90}
91-----------------------------------------------------------------------
92*/
93
94#ifndef _LINUX_RBTREE_H
95#define _LINUX_RBTREE_H
96
97#include <stddef.h>
98
99/**
100 * container_of - cast a member of a structure out to the containing structure
101 * @ptr: the pointer to the member.
102 * @type: the type of the container struct this is embedded in.
103 * @member: the name of the member within the struct.
104 *
105 */
106#define container_of(ptr, type, member) ({ \
107 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
108 (type *)( (char *)__mptr - offsetof(type,member) );})
109
110struct rb_node
111{
112 unsigned long rb_parent_color;
113#define RB_RED 0
114#define RB_BLACK 1
115 struct rb_node *rb_right;
116 struct rb_node *rb_left;
117} __attribute__((aligned(sizeof(long))));
118 /* The alignment might seem pointless, but allegedly CRIS needs it */
119
120struct rb_root
121{
122 struct rb_node *rb_node;
123};
124
125
126#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
127#define rb_color(r) ((r)->rb_parent_color & 1)
128#define rb_is_red(r) (!rb_color(r))
129#define rb_is_black(r) rb_color(r)
130#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
131#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
132
133static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
134{
135 rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
136}
137static inline void rb_set_color(struct rb_node *rb, int color)
138{
139 rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
140}
141
142#define RB_ROOT (struct rb_root) { NULL, }
143#define rb_entry(ptr, type, member) container_of(ptr, type, member)
144
145#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
146#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
147#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
148
149extern void rb_insert_color(struct rb_node *, struct rb_root *);
150extern void rb_erase(struct rb_node *, struct rb_root *);
151
152/* Find logical next and previous nodes in a tree */
153extern struct rb_node *rb_next(const struct rb_node *);
154extern struct rb_node *rb_prev(const struct rb_node *);
155extern struct rb_node *rb_first(const struct rb_root *);
156extern struct rb_node *rb_last(const struct rb_root *);
157
158/* Fast replacement of a single node without remove/rebalance/add/rebalance */
159extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
160 struct rb_root *root);
161
162static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
163 struct rb_node ** rb_link)
164{
165 node->rb_parent_color = (unsigned long )parent;
166 node->rb_left = node->rb_right = NULL;
167
168 *rb_link = node;
169}
170
171#endif /* _LINUX_RBTREE_H */
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
index b2f5e854f40a..2b615acf94d7 100644
--- a/tools/perf/util/run-command.c
+++ b/tools/perf/util/run-command.c
@@ -65,7 +65,6 @@ int start_command(struct child_process *cmd)
65 cmd->err = fderr[0]; 65 cmd->err = fderr[0];
66 } 66 }
67 67
68#ifndef __MINGW32__
69 fflush(NULL); 68 fflush(NULL);
70 cmd->pid = fork(); 69 cmd->pid = fork();
71 if (!cmd->pid) { 70 if (!cmd->pid) {
@@ -118,71 +117,6 @@ int start_command(struct child_process *cmd)
118 } 117 }
119 exit(127); 118 exit(127);
120 } 119 }
121#else
122 int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
123 const char **sargv = cmd->argv;
124 char **env = environ;
125
126 if (cmd->no_stdin) {
127 s0 = dup(0);
128 dup_devnull(0);
129 } else if (need_in) {
130 s0 = dup(0);
131 dup2(fdin[0], 0);
132 } else if (cmd->in) {
133 s0 = dup(0);
134 dup2(cmd->in, 0);
135 }
136
137 if (cmd->no_stderr) {
138 s2 = dup(2);
139 dup_devnull(2);
140 } else if (need_err) {
141 s2 = dup(2);
142 dup2(fderr[1], 2);
143 }
144
145 if (cmd->no_stdout) {
146 s1 = dup(1);
147 dup_devnull(1);
148 } else if (cmd->stdout_to_stderr) {
149 s1 = dup(1);
150 dup2(2, 1);
151 } else if (need_out) {
152 s1 = dup(1);
153 dup2(fdout[1], 1);
154 } else if (cmd->out > 1) {
155 s1 = dup(1);
156 dup2(cmd->out, 1);
157 }
158
159 if (cmd->dir)
160 die("chdir in start_command() not implemented");
161 if (cmd->env) {
162 env = copy_environ();
163 for (; *cmd->env; cmd->env++)
164 env = env_setenv(env, *cmd->env);
165 }
166
167 if (cmd->perf_cmd) {
168 cmd->argv = prepare_perf_cmd(cmd->argv);
169 }
170
171 cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
172
173 if (cmd->env)
174 free_environ(env);
175 if (cmd->perf_cmd)
176 free(cmd->argv);
177
178 cmd->argv = sargv;
179 if (s0 >= 0)
180 dup2(s0, 0), close(s0);
181 if (s1 >= 0)
182 dup2(s1, 1), close(s1);
183 if (s2 >= 0)
184 dup2(s2, 2), close(s2);
185#endif
186 120
187 if (cmd->pid < 0) { 121 if (cmd->pid < 0) {
188 int err = errno; 122 int err = errno;
@@ -288,14 +222,6 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
288 return run_command(&cmd); 222 return run_command(&cmd);
289} 223}
290 224
291#ifdef __MINGW32__
292static __stdcall unsigned run_thread(void *data)
293{
294 struct async *async = data;
295 return async->proc(async->fd_for_proc, async->data);
296}
297#endif
298
299int start_async(struct async *async) 225int start_async(struct async *async)
300{ 226{
301 int pipe_out[2]; 227 int pipe_out[2];
@@ -304,7 +230,6 @@ int start_async(struct async *async)
304 return error("cannot create pipe: %s", strerror(errno)); 230 return error("cannot create pipe: %s", strerror(errno));
305 async->out = pipe_out[0]; 231 async->out = pipe_out[0];
306 232
307#ifndef __MINGW32__
308 /* Flush stdio before fork() to avoid cloning buffers */ 233 /* Flush stdio before fork() to avoid cloning buffers */
309 fflush(NULL); 234 fflush(NULL);
310 235
@@ -319,33 +244,17 @@ int start_async(struct async *async)
319 exit(!!async->proc(pipe_out[1], async->data)); 244 exit(!!async->proc(pipe_out[1], async->data));
320 } 245 }
321 close(pipe_out[1]); 246 close(pipe_out[1]);
322#else 247
323 async->fd_for_proc = pipe_out[1];
324 async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
325 if (!async->tid) {
326 error("cannot create thread: %s", strerror(errno));
327 close_pair(pipe_out);
328 return -1;
329 }
330#endif
331 return 0; 248 return 0;
332} 249}
333 250
334int finish_async(struct async *async) 251int finish_async(struct async *async)
335{ 252{
336#ifndef __MINGW32__
337 int ret = 0; 253 int ret = 0;
338 254
339 if (wait_or_whine(async->pid)) 255 if (wait_or_whine(async->pid))
340 ret = error("waitpid (async) failed"); 256 ret = error("waitpid (async) failed");
341#else 257
342 DWORD ret = 0;
343 if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0)
344 ret = error("waiting for thread failed: %lu", GetLastError());
345 else if (!GetExitCodeThread(async->tid, &ret))
346 ret = error("cannot get thread exit code: %lu", GetLastError());
347 CloseHandle(async->tid);
348#endif
349 return ret; 258 return ret;
350} 259}
351 260
@@ -353,7 +262,7 @@ int run_hook(const char *index_file, const char *name, ...)
353{ 262{
354 struct child_process hook; 263 struct child_process hook;
355 const char **argv = NULL, *env[2]; 264 const char **argv = NULL, *env[2];
356 char index[PATH_MAX]; 265 char idx[PATH_MAX];
357 va_list args; 266 va_list args;
358 int ret; 267 int ret;
359 size_t i = 0, alloc = 0; 268 size_t i = 0, alloc = 0;
@@ -375,8 +284,8 @@ int run_hook(const char *index_file, const char *name, ...)
375 hook.no_stdin = 1; 284 hook.no_stdin = 1;
376 hook.stdout_to_stderr = 1; 285 hook.stdout_to_stderr = 1;
377 if (index_file) { 286 if (index_file) {
378 snprintf(index, sizeof(index), "PERF_INDEX_FILE=%s", index_file); 287 snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file);
379 env[0] = index; 288 env[0] = idx;
380 env[1] = NULL; 289 env[1] = NULL;
381 hook.env = env; 290 hook.env = env;
382 } 291 }
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index 328289f23669..cc1837deba88 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -79,12 +79,7 @@ struct async {
79 int (*proc)(int fd, void *data); 79 int (*proc)(int fd, void *data);
80 void *data; 80 void *data;
81 int out; /* caller reads from here and closes it */ 81 int out; /* caller reads from here and closes it */
82#ifndef __MINGW32__
83 pid_t pid; 82 pid_t pid;
84#else
85 HANDLE tid;
86 int fd_for_proc;
87#endif
88}; 83};
89 84
90int start_async(struct async *async); 85int start_async(struct async *async);
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index eaba09306802..5249d5a1b0c2 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -16,7 +16,7 @@ int prefixcmp(const char *str, const char *prefix)
16 */ 16 */
17char strbuf_slopbuf[1]; 17char strbuf_slopbuf[1];
18 18
19void strbuf_init(struct strbuf *sb, size_t hint) 19void strbuf_init(struct strbuf *sb, ssize_t hint)
20{ 20{
21 sb->alloc = sb->len = 0; 21 sb->alloc = sb->len = 0;
22 sb->buf = strbuf_slopbuf; 22 sb->buf = strbuf_slopbuf;
@@ -92,7 +92,8 @@ void strbuf_ltrim(struct strbuf *sb)
92 92
93void strbuf_tolower(struct strbuf *sb) 93void strbuf_tolower(struct strbuf *sb)
94{ 94{
95 int i; 95 unsigned int i;
96
96 for (i = 0; i < sb->len; i++) 97 for (i = 0; i < sb->len; i++)
97 sb->buf[i] = tolower(sb->buf[i]); 98 sb->buf[i] = tolower(sb->buf[i]);
98} 99}
@@ -259,12 +260,12 @@ size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
259 res = fread(sb->buf + sb->len, 1, size, f); 260 res = fread(sb->buf + sb->len, 1, size, f);
260 if (res > 0) 261 if (res > 0)
261 strbuf_setlen(sb, sb->len + res); 262 strbuf_setlen(sb, sb->len + res);
262 else if (res < 0 && oldalloc == 0) 263 else if (oldalloc == 0)
263 strbuf_release(sb); 264 strbuf_release(sb);
264 return res; 265 return res;
265} 266}
266 267
267ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) 268ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
268{ 269{
269 size_t oldlen = sb->len; 270 size_t oldlen = sb->len;
270 size_t oldalloc = sb->alloc; 271 size_t oldalloc = sb->alloc;
@@ -293,7 +294,7 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
293 294
294#define STRBUF_MAXLINK (2*PATH_MAX) 295#define STRBUF_MAXLINK (2*PATH_MAX)
295 296
296int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint) 297int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint)
297{ 298{
298 size_t oldalloc = sb->alloc; 299 size_t oldalloc = sb->alloc;
299 300
@@ -301,7 +302,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
301 hint = 32; 302 hint = 32;
302 303
303 while (hint < STRBUF_MAXLINK) { 304 while (hint < STRBUF_MAXLINK) {
304 int len; 305 ssize_t len;
305 306
306 strbuf_grow(sb, hint); 307 strbuf_grow(sb, hint);
307 len = readlink(path, sb->buf, hint); 308 len = readlink(path, sb->buf, hint);
@@ -343,7 +344,7 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
343 return 0; 344 return 0;
344} 345}
345 346
346int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint) 347int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint)
347{ 348{
348 int fd, len; 349 int fd, len;
349 350
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index 9ee908a3ec5d..d2aa86c014c1 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -50,7 +50,7 @@ struct strbuf {
50#define STRBUF_INIT { 0, 0, strbuf_slopbuf } 50#define STRBUF_INIT { 0, 0, strbuf_slopbuf }
51 51
52/*----- strbuf life cycle -----*/ 52/*----- strbuf life cycle -----*/
53extern void strbuf_init(struct strbuf *, size_t); 53extern void strbuf_init(struct strbuf *buf, ssize_t hint);
54extern void strbuf_release(struct strbuf *); 54extern void strbuf_release(struct strbuf *);
55extern char *strbuf_detach(struct strbuf *, size_t *); 55extern char *strbuf_detach(struct strbuf *, size_t *);
56extern void strbuf_attach(struct strbuf *, void *, size_t, size_t); 56extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
@@ -61,7 +61,7 @@ static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
61} 61}
62 62
63/*----- strbuf size related -----*/ 63/*----- strbuf size related -----*/
64static inline size_t strbuf_avail(const struct strbuf *sb) { 64static inline ssize_t strbuf_avail(const struct strbuf *sb) {
65 return sb->alloc ? sb->alloc - sb->len - 1 : 0; 65 return sb->alloc ? sb->alloc - sb->len - 1 : 0;
66} 66}
67 67
@@ -122,9 +122,9 @@ extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
122 122
123extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); 123extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
124/* XXX: if read fails, any partial read is undone */ 124/* XXX: if read fails, any partial read is undone */
125extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); 125extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
126extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint); 126extern int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint);
127extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint); 127extern int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint);
128 128
129extern int strbuf_getline(struct strbuf *, FILE *, int); 129extern int strbuf_getline(struct strbuf *, FILE *, int);
130 130
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 37b03255b425..bf39dfadfd24 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,8 +1,11 @@
1#ifndef _PERF_STRING_H_ 1#ifndef _PERF_STRING_H_
2#define _PERF_STRING_H_ 2#define _PERF_STRING_H_
3 3
4#include "../types.h" 4#include "types.h"
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7 7
8#define _STR(x) #x
9#define STR(x) _STR(x)
10
8#endif 11#endif
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
new file mode 100644
index 000000000000..7ad38171dc2b
--- /dev/null
+++ b/tools/perf/util/strlist.c
@@ -0,0 +1,200 @@
1/*
2 * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Licensed under the GPLv2.
5 */
6
7#include "strlist.h"
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13static struct str_node *str_node__new(const char *s, bool dupstr)
14{
15 struct str_node *self = malloc(sizeof(*self));
16
17 if (self != NULL) {
18 if (dupstr) {
19 s = strdup(s);
20 if (s == NULL)
21 goto out_delete;
22 }
23 self->s = s;
24 }
25
26 return self;
27
28out_delete:
29 free(self);
30 return NULL;
31}
32
33static void str_node__delete(struct str_node *self, bool dupstr)
34{
35 if (dupstr)
36 free((void *)self->s);
37 free(self);
38}
39
40int strlist__add(struct strlist *self, const char *new_entry)
41{
42 struct rb_node **p = &self->entries.rb_node;
43 struct rb_node *parent = NULL;
44 struct str_node *sn;
45
46 while (*p != NULL) {
47 int rc;
48
49 parent = *p;
50 sn = rb_entry(parent, struct str_node, rb_node);
51 rc = strcmp(sn->s, new_entry);
52
53 if (rc > 0)
54 p = &(*p)->rb_left;
55 else if (rc < 0)
56 p = &(*p)->rb_right;
57 else
58 return -EEXIST;
59 }
60
61 sn = str_node__new(new_entry, self->dupstr);
62 if (sn == NULL)
63 return -ENOMEM;
64
65 rb_link_node(&sn->rb_node, parent, p);
66 rb_insert_color(&sn->rb_node, &self->entries);
67 ++self->nr_entries;
68
69 return 0;
70}
71
72int strlist__load(struct strlist *self, const char *filename)
73{
74 char entry[1024];
75 int err;
76 FILE *fp = fopen(filename, "r");
77
78 if (fp == NULL)
79 return errno;
80
81 while (fgets(entry, sizeof(entry), fp) != NULL) {
82 const size_t len = strlen(entry);
83
84 if (len == 0)
85 continue;
86 entry[len - 1] = '\0';
87
88 err = strlist__add(self, entry);
89 if (err != 0)
90 goto out;
91 }
92
93 err = 0;
94out:
95 fclose(fp);
96 return err;
97}
98
99void strlist__remove(struct strlist *self, struct str_node *sn)
100{
101 rb_erase(&sn->rb_node, &self->entries);
102 str_node__delete(sn, self->dupstr);
103}
104
105bool strlist__has_entry(struct strlist *self, const char *entry)
106{
107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL;
109
110 while (*p != NULL) {
111 struct str_node *sn;
112 int rc;
113
114 parent = *p;
115 sn = rb_entry(parent, struct str_node, rb_node);
116 rc = strcmp(sn->s, entry);
117
118 if (rc > 0)
119 p = &(*p)->rb_left;
120 else if (rc < 0)
121 p = &(*p)->rb_right;
122 else
123 return true;
124 }
125
126 return false;
127}
128
129static int strlist__parse_list_entry(struct strlist *self, const char *s)
130{
131 if (strncmp(s, "file://", 7) == 0)
132 return strlist__load(self, s + 7);
133
134 return strlist__add(self, s);
135}
136
137int strlist__parse_list(struct strlist *self, const char *s)
138{
139 char *sep;
140 int err;
141
142 while ((sep = strchr(s, ',')) != NULL) {
143 *sep = '\0';
144 err = strlist__parse_list_entry(self, s);
145 *sep = ',';
146 if (err != 0)
147 return err;
148 s = sep + 1;
149 }
150
151 return *s ? strlist__parse_list_entry(self, s) : 0;
152}
153
154struct strlist *strlist__new(bool dupstr, const char *slist)
155{
156 struct strlist *self = malloc(sizeof(*self));
157
158 if (self != NULL) {
159 self->entries = RB_ROOT;
160 self->dupstr = dupstr;
161 self->nr_entries = 0;
162 if (slist && strlist__parse_list(self, slist) != 0)
163 goto out_error;
164 }
165
166 return self;
167out_error:
168 free(self);
169 return NULL;
170}
171
172void strlist__delete(struct strlist *self)
173{
174 if (self != NULL) {
175 struct str_node *pos;
176 struct rb_node *next = rb_first(&self->entries);
177
178 while (next) {
179 pos = rb_entry(next, struct str_node, rb_node);
180 next = rb_next(&pos->rb_node);
181 strlist__remove(self, pos);
182 }
183 self->entries = RB_ROOT;
184 free(self);
185 }
186}
187
188struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
189{
190 struct rb_node *nd;
191
192 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
193 struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
194
195 if (!idx--)
196 return pos;
197 }
198
199 return NULL;
200}
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
new file mode 100644
index 000000000000..921818e44a54
--- /dev/null
+++ b/tools/perf/util/strlist.h
@@ -0,0 +1,39 @@
1#ifndef STRLIST_H_
2#define STRLIST_H_
3
4#include <linux/rbtree.h>
5#include <stdbool.h>
6
7struct str_node {
8 struct rb_node rb_node;
9 const char *s;
10};
11
12struct strlist {
13 struct rb_root entries;
14 unsigned int nr_entries;
15 bool dupstr;
16};
17
18struct strlist *strlist__new(bool dupstr, const char *slist);
19void strlist__delete(struct strlist *self);
20
21void strlist__remove(struct strlist *self, struct str_node *sn);
22int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str);
24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry);
27
28static inline bool strlist__empty(const struct strlist *self)
29{
30 return self->nr_entries == 0;
31}
32
33static inline unsigned int strlist__nr_entries(const struct strlist *self)
34{
35 return self->nr_entries;
36}
37
38int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* STRLIST_H_ */
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
new file mode 100644
index 000000000000..a778fd0f4ae4
--- /dev/null
+++ b/tools/perf/util/svghelper.c
@@ -0,0 +1,488 @@
1/*
2 * svghelper.c - helper functions for outputting svg
3 *
4 * (C) Copyright 2009 Intel Corporation
5 *
6 * Authors:
7 * Arjan van de Ven <arjan@linux.intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; version 2
12 * of the License.
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <unistd.h>
18#include <string.h>
19
20#include "svghelper.h"
21
22static u64 first_time, last_time;
23static u64 turbo_frequency, max_freq;
24
25
26#define SLOT_MULT 30.0
27#define SLOT_HEIGHT 25.0
28
29int svg_page_width = 1000;
30
31#define MIN_TEXT_SIZE 0.001
32
33static u64 total_height;
34static FILE *svgfile;
35
36static double cpu2slot(int cpu)
37{
38 return 2 * cpu + 1;
39}
40
41static double cpu2y(int cpu)
42{
43 return cpu2slot(cpu) * SLOT_MULT;
44}
45
46static double time2pixels(u64 time)
47{
48 double X;
49
50 X = 1.0 * svg_page_width * (time - first_time) / (last_time - first_time);
51 return X;
52}
53
54/*
55 * Round text sizes so that the svg viewer only needs a discrete
56 * number of renderings of the font
57 */
58static double round_text_size(double size)
59{
60 int loop = 100;
61 double target = 10.0;
62
63 if (size >= 10.0)
64 return size;
65 while (loop--) {
66 if (size >= target)
67 return target;
68 target = target / 2.0;
69 }
70 return size;
71}
72
73void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
74{
75 int new_width;
76
77 svgfile = fopen(filename, "w");
78 if (!svgfile) {
79 fprintf(stderr, "Cannot open %s for output\n", filename);
80 return;
81 }
82 first_time = start;
83 first_time = first_time / 100000000 * 100000000;
84 last_time = end;
85
86 /*
87 * if the recording is short, we default to a width of 1000, but
88 * for longer recordings we want at least 200 units of width per second
89 */
90 new_width = (last_time - first_time) / 5000000;
91
92 if (new_width > svg_page_width)
93 svg_page_width = new_width;
94
95 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
96 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
97 fprintf(svgfile, "<svg width=\"%i\" height=\"%llu\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
98
99 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
100
101 fprintf(svgfile, " rect { stroke-width: 1; }\n");
102 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
103 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
104 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
105 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
106 fprintf(svgfile, " rect.waiting { fill:rgb(214,214, 0); fill-opacity:0.3; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
107 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
108 fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n");
109 fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n");
110 fprintf(svgfile, " rect.c1 { fill:rgb(255,214,214); fill-opacity:0.5; stroke-width:0; } \n");
111 fprintf(svgfile, " rect.c2 { fill:rgb(255,172,172); fill-opacity:0.5; stroke-width:0; } \n");
112 fprintf(svgfile, " rect.c3 { fill:rgb(255,130,130); fill-opacity:0.5; stroke-width:0; } \n");
113 fprintf(svgfile, " rect.c4 { fill:rgb(255, 88, 88); fill-opacity:0.5; stroke-width:0; } \n");
114 fprintf(svgfile, " rect.c5 { fill:rgb(255, 44, 44); fill-opacity:0.5; stroke-width:0; } \n");
115 fprintf(svgfile, " rect.c6 { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; } \n");
116 fprintf(svgfile, " line.pstate { stroke:rgb(255,255, 0); stroke-opacity:0.8; stroke-width:2; } \n");
117
118 fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
119}
120
121void svg_box(int Yslot, u64 start, u64 end, const char *type)
122{
123 if (!svgfile)
124 return;
125
126 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
127 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
128}
129
130void svg_sample(int Yslot, int cpu, u64 start, u64 end)
131{
132 double text_size;
133 if (!svgfile)
134 return;
135
136 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n",
137 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT);
138
139 text_size = (time2pixels(end)-time2pixels(start));
140 if (cpu > 9)
141 text_size = text_size/2;
142 if (text_size > 1.25)
143 text_size = 1.25;
144 text_size = round_text_size(text_size);
145
146 if (text_size > MIN_TEXT_SIZE)
147 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n",
148 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
149
150}
151
152static char *time_to_string(u64 duration)
153{
154 static char text[80];
155
156 text[0] = 0;
157
158 if (duration < 1000) /* less than 1 usec */
159 return text;
160
161 if (duration < 1000 * 1000) { /* less than 1 msec */
162 sprintf(text, "%4.1f us", duration / 1000.0);
163 return text;
164 }
165 sprintf(text, "%4.1f ms", duration / 1000.0 / 1000);
166
167 return text;
168}
169
170void svg_waiting(int Yslot, u64 start, u64 end)
171{
172 char *text;
173 const char *style;
174 double font_size;
175
176 if (!svgfile)
177 return;
178
179 style = "waiting";
180
181 if (end-start > 10 * 1000000) /* 10 msec */
182 style = "WAITING";
183
184 text = time_to_string(end-start);
185
186 font_size = 1.0 * (time2pixels(end)-time2pixels(start));
187
188 if (font_size > 3)
189 font_size = 3;
190
191 font_size = round_text_size(font_size);
192
193 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
194 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
195 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
196 if (font_size > MIN_TEXT_SIZE)
197 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%1.8fpt\"> %s</text>\n",
198 font_size, text);
199 fprintf(svgfile, "</g>\n");
200}
201
202static char *cpu_model(void)
203{
204 static char cpu_m[255];
205 char buf[256];
206 FILE *file;
207
208 cpu_m[0] = 0;
209 /* CPU type */
210 file = fopen("/proc/cpuinfo", "r");
211 if (file) {
212 while (fgets(buf, 255, file)) {
213 if (strstr(buf, "model name")) {
214 strncpy(cpu_m, &buf[13], 255);
215 break;
216 }
217 }
218 fclose(file);
219 }
220 return cpu_m;
221}
222
223void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
224{
225 char cpu_string[80];
226 if (!svgfile)
227 return;
228
229 max_freq = __max_freq;
230 turbo_frequency = __turbo_freq;
231
232 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n",
233 time2pixels(first_time),
234 time2pixels(last_time)-time2pixels(first_time),
235 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
236
237 sprintf(cpu_string, "CPU %i", (int)cpu+1);
238 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
239 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
240
241 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n",
242 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
243}
244
245void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name)
246{
247 double width;
248
249 if (!svgfile)
250 return;
251
252
253 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu));
254 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
255 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
256 width = time2pixels(end)-time2pixels(start);
257 if (width > 6)
258 width = 6;
259
260 width = round_text_size(width);
261
262 if (width > MIN_TEXT_SIZE)
263 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%3.8fpt\">%s</text>\n",
264 width, name);
265
266 fprintf(svgfile, "</g>\n");
267}
268
269void svg_cstate(int cpu, u64 start, u64 end, int type)
270{
271 double width;
272 char style[128];
273
274 if (!svgfile)
275 return;
276
277
278 if (type > 6)
279 type = 6;
280 sprintf(style, "c%i", type);
281
282 fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n",
283 style,
284 time2pixels(start), time2pixels(end)-time2pixels(start),
285 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
286
287 width = (time2pixels(end)-time2pixels(start))/2.0;
288 if (width > 6)
289 width = 6;
290
291 width = round_text_size(width);
292
293 if (width > MIN_TEXT_SIZE)
294 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n",
295 time2pixels(start), cpu2y(cpu)+width, width, type);
296}
297
298static char *HzToHuman(unsigned long hz)
299{
300 static char buffer[1024];
301 unsigned long long Hz;
302
303 memset(buffer, 0, 1024);
304
305 Hz = hz;
306
307 /* default: just put the Number in */
308 sprintf(buffer, "%9lli", Hz);
309
310 if (Hz > 1000)
311 sprintf(buffer, " %6lli Mhz", (Hz+500)/1000);
312
313 if (Hz > 1500000)
314 sprintf(buffer, " %6.2f Ghz", (Hz+5000.0)/1000000);
315
316 if (Hz == turbo_frequency)
317 sprintf(buffer, "Turbo");
318
319 return buffer;
320}
321
322void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
323{
324 double height = 0;
325
326 if (!svgfile)
327 return;
328
329 if (max_freq)
330 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
331 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
332 fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n",
333 time2pixels(start), time2pixels(end), height, height);
334 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n",
335 time2pixels(start), height+0.9, HzToHuman(freq));
336
337}
338
339
340void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2)
341{
342 double height;
343
344 if (!svgfile)
345 return;
346
347
348 if (row1 < row2) {
349 if (row1) {
350 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
351 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
352 if (desc2)
353 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
354 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2);
355 }
356 if (row2) {
357 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
358 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT);
359 if (desc1)
360 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
361 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1);
362 }
363 } else {
364 if (row2) {
365 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
366 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
367 if (desc1)
368 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
369 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1);
370 }
371 if (row1) {
372 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
373 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT);
374 if (desc2)
375 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
376 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2);
377 }
378 }
379 height = row1 * SLOT_MULT;
380 if (row2 > row1)
381 height += SLOT_HEIGHT;
382 if (row1)
383 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
384 time2pixels(start), height);
385}
386
387void svg_wakeline(u64 start, int row1, int row2)
388{
389 double height;
390
391 if (!svgfile)
392 return;
393
394
395 if (row1 < row2)
396 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
397 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
398 else
399 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
400 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT);
401
402 height = row1 * SLOT_MULT;
403 if (row2 > row1)
404 height += SLOT_HEIGHT;
405 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
406 time2pixels(start), height);
407}
408
409void svg_interrupt(u64 start, int row)
410{
411 if (!svgfile)
412 return;
413
414 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
415 time2pixels(start), row * SLOT_MULT);
416 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
417 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
418}
419
420void svg_text(int Yslot, u64 start, const char *text)
421{
422 if (!svgfile)
423 return;
424
425 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
426 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text);
427}
428
429static void svg_legenda_box(int X, const char *text, const char *style)
430{
431 double boxsize;
432 boxsize = SLOT_HEIGHT / 2;
433
434 fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
435 X, boxsize, boxsize, style);
436 fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.8fpt\">%s</text>\n",
437 X + boxsize + 5, boxsize, 0.8 * boxsize, text);
438}
439
440void svg_legenda(void)
441{
442 if (!svgfile)
443 return;
444
445 svg_legenda_box(0, "Running", "sample");
446 svg_legenda_box(100, "Idle","rect.c1");
447 svg_legenda_box(200, "Deeper Idle", "rect.c3");
448 svg_legenda_box(350, "Deepest Idle", "rect.c6");
449 svg_legenda_box(550, "Sleeping", "process2");
450 svg_legenda_box(650, "Waiting for cpu", "waiting");
451 svg_legenda_box(800, "Blocked on IO", "blocked");
452}
453
454void svg_time_grid(void)
455{
456 u64 i;
457
458 if (!svgfile)
459 return;
460
461 i = first_time;
462 while (i < last_time) {
463 int color = 220;
464 double thickness = 0.075;
465 if ((i % 100000000) == 0) {
466 thickness = 0.5;
467 color = 192;
468 }
469 if ((i % 1000000000) == 0) {
470 thickness = 2.0;
471 color = 128;
472 }
473
474 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%llu\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
475 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness);
476
477 i += 10000000;
478 }
479}
480
481void svg_close(void)
482{
483 if (svgfile) {
484 fprintf(svgfile, "</svg>\n");
485 fclose(svgfile);
486 svgfile = NULL;
487 }
488}
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
new file mode 100644
index 000000000000..cd93195aedb3
--- /dev/null
+++ b/tools/perf/util/svghelper.h
@@ -0,0 +1,28 @@
1#ifndef _INCLUDE_GUARD_SVG_HELPER_
2#define _INCLUDE_GUARD_SVG_HELPER_
3
4#include "types.h"
5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
8extern void svg_sample(int Yslot, int cpu, u64 start, u64 end);
9extern void svg_waiting(int Yslot, u64 start, u64 end);
10extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency);
11
12
13extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name);
14extern void svg_cstate(int cpu, u64 start, u64 end, int type);
15extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
16
17
18extern void svg_time_grid(void);
19extern void svg_legenda(void);
20extern void svg_wakeline(u64 start, int row1, int row2);
21extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2);
22extern void svg_interrupt(u64 start, int row);
23extern void svg_text(int Yslot, u64 start, const char *text);
24extern void svg_close(void);
25
26extern int svg_page_width;
27
28#endif
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 86e14375e74e..559fb06210f5 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -3,15 +3,27 @@
3#include "string.h" 3#include "string.h"
4#include "symbol.h" 4#include "symbol.h"
5 5
6#include "debug.h"
7
6#include <libelf.h> 8#include <libelf.h>
7#include <gelf.h> 9#include <gelf.h>
8#include <elf.h> 10#include <elf.h>
9 11
10const char *sym_hist_filter; 12const char *sym_hist_filter;
11 13
14enum dso_origin {
15 DSO__ORIG_KERNEL = 0,
16 DSO__ORIG_JAVA_JIT,
17 DSO__ORIG_FEDORA,
18 DSO__ORIG_UBUNTU,
19 DSO__ORIG_BUILDID,
20 DSO__ORIG_DSO,
21 DSO__ORIG_NOT_FOUND,
22};
23
12static struct symbol *symbol__new(u64 start, u64 len, 24static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size, 25 const char *name, unsigned int priv_size,
14 u64 obj_start, int verbose) 26 u64 obj_start, int v)
15{ 27{
16 size_t namelen = strlen(name) + 1; 28 size_t namelen = strlen(name) + 1;
17 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
@@ -19,7 +31,7 @@ static struct symbol *symbol__new(u64 start, u64 len,
19 if (!self) 31 if (!self)
20 return NULL; 32 return NULL;
21 33
22 if (verbose >= 2) 34 if (v >= 2)
23 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
24 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
25 37
@@ -35,7 +47,7 @@ static struct symbol *symbol__new(u64 start, u64 len,
35 self = ((void *)self) + priv_size; 47 self = ((void *)self) + priv_size;
36 } 48 }
37 self->start = start; 49 self->start = start;
38 self->end = start + len - 1; 50 self->end = len ? start + len - 1 : start;
39 memcpy(self->name, name, namelen); 51 memcpy(self->name, name, namelen);
40 52
41 return self; 53 return self;
@@ -48,8 +60,12 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
48 60
49static size_t symbol__fprintf(struct symbol *self, FILE *fp) 61static size_t symbol__fprintf(struct symbol *self, FILE *fp)
50{ 62{
51 return fprintf(fp, " %llx-%llx %s\n", 63 if (!self->module)
64 return fprintf(fp, " %llx-%llx %s\n",
52 self->start, self->end, self->name); 65 self->start, self->end, self->name);
66 else
67 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
68 self->start, self->end, self->name, self->module->name);
53} 69}
54 70
55struct dso *dso__new(const char *name, unsigned int sym_priv_size) 71struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -61,6 +77,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
61 self->syms = RB_ROOT; 77 self->syms = RB_ROOT;
62 self->sym_priv_size = sym_priv_size; 78 self->sym_priv_size = sym_priv_size;
63 self->find_symbol = dso__find_symbol; 79 self->find_symbol = dso__find_symbol;
80 self->slen_calculated = 0;
81 self->origin = DSO__ORIG_NOT_FOUND;
64 } 82 }
65 83
66 return self; 84 return self;
@@ -140,12 +158,13 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
140 return ret; 158 return ret;
141} 159}
142 160
143static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose) 161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
144{ 162{
145 struct rb_node *nd, *prevnd; 163 struct rb_node *nd, *prevnd;
146 char *line = NULL; 164 char *line = NULL;
147 size_t n; 165 size_t n;
148 FILE *file = fopen("/proc/kallsyms", "r"); 166 FILE *file = fopen("/proc/kallsyms", "r");
167 int count = 0;
149 168
150 if (file == NULL) 169 if (file == NULL)
151 goto out_failure; 170 goto out_failure;
@@ -181,15 +200,17 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
181 * Well fix up the end later, when we have all sorted. 200 * Well fix up the end later, when we have all sorted.
182 */ 201 */
183 sym = symbol__new(start, 0xdead, line + len + 2, 202 sym = symbol__new(start, 0xdead, line + len + 2,
184 self->sym_priv_size, 0, verbose); 203 self->sym_priv_size, 0, v);
185 204
186 if (sym == NULL) 205 if (sym == NULL)
187 goto out_delete_line; 206 goto out_delete_line;
188 207
189 if (filter && filter(self, sym)) 208 if (filter && filter(self, sym))
190 symbol__delete(sym, self->sym_priv_size); 209 symbol__delete(sym, self->sym_priv_size);
191 else 210 else {
192 dso__insert_symbol(self, sym); 211 dso__insert_symbol(self, sym);
212 count++;
213 }
193 } 214 }
194 215
195 /* 216 /*
@@ -212,7 +233,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
212 free(line); 233 free(line);
213 fclose(file); 234 fclose(file);
214 235
215 return 0; 236 return count;
216 237
217out_delete_line: 238out_delete_line:
218 free(line); 239 free(line);
@@ -220,7 +241,7 @@ out_failure:
220 return -1; 241 return -1;
221} 242}
222 243
223static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose) 244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
224{ 245{
225 char *line = NULL; 246 char *line = NULL;
226 size_t n; 247 size_t n;
@@ -258,7 +279,7 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verb
258 continue; 279 continue;
259 280
260 sym = symbol__new(start, size, line + len, 281 sym = symbol__new(start, size, line + len,
261 self->sym_priv_size, start, verbose); 282 self->sym_priv_size, start, v);
262 283
263 if (sym == NULL) 284 if (sym == NULL)
264 goto out_delete_line; 285 goto out_delete_line;
@@ -286,13 +307,13 @@ out_failure:
286 * elf_symtab__for_each_symbol - iterate thru all the symbols 307 * elf_symtab__for_each_symbol - iterate thru all the symbols
287 * 308 *
288 * @self: struct elf_symtab instance to iterate 309 * @self: struct elf_symtab instance to iterate
289 * @index: uint32_t index 310 * @idx: uint32_t idx
290 * @sym: GElf_Sym iterator 311 * @sym: GElf_Sym iterator
291 */ 312 */
292#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \ 313#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
293 for (index = 0, gelf_getsym(syms, index, &sym);\ 314 for (idx = 0, gelf_getsym(syms, idx, &sym);\
294 index < nr_syms; \ 315 idx < nr_syms; \
295 index++, gelf_getsym(syms, index, &sym)) 316 idx++, gelf_getsym(syms, idx, &sym))
296 317
297static inline uint8_t elf_sym__type(const GElf_Sym *sym) 318static inline uint8_t elf_sym__type(const GElf_Sym *sym)
298{ 319{
@@ -307,6 +328,26 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
307 sym->st_size != 0; 328 sym->st_size != 0;
308} 329}
309 330
331static inline int elf_sym__is_label(const GElf_Sym *sym)
332{
333 return elf_sym__type(sym) == STT_NOTYPE &&
334 sym->st_name != 0 &&
335 sym->st_shndx != SHN_UNDEF &&
336 sym->st_shndx != SHN_ABS;
337}
338
339static inline const char *elf_sec__name(const GElf_Shdr *shdr,
340 const Elf_Data *secstrs)
341{
342 return secstrs->d_buf + shdr->sh_name;
343}
344
345static inline int elf_sec__is_text(const GElf_Shdr *shdr,
346 const Elf_Data *secstrs)
347{
348 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
349}
350
310static inline const char *elf_sym__name(const GElf_Sym *sym, 351static inline const char *elf_sym__name(const GElf_Sym *sym,
311 const Elf_Data *symstrs) 352 const Elf_Data *symstrs)
312{ 353{
@@ -315,7 +356,7 @@ static inline const char *elf_sym__name(const GElf_Sym *sym,
315 356
316static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 357static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
317 GElf_Shdr *shp, const char *name, 358 GElf_Shdr *shp, const char *name,
318 size_t *index) 359 size_t *idx)
319{ 360{
320 Elf_Scn *sec = NULL; 361 Elf_Scn *sec = NULL;
321 size_t cnt = 1; 362 size_t cnt = 1;
@@ -326,8 +367,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
326 gelf_getshdr(sec, shp); 367 gelf_getshdr(sec, shp);
327 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 368 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
328 if (!strcmp(name, str)) { 369 if (!strcmp(name, str)) {
329 if (index) 370 if (idx)
330 *index = cnt; 371 *idx = cnt;
331 break; 372 break;
332 } 373 }
333 ++cnt; 374 ++cnt;
@@ -346,56 +387,81 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
346 idx < nr_entries; \ 387 idx < nr_entries; \
347 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 388 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
348 389
349static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 390/*
350 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 391 * We need to check if we have a .dynsym, so that we can handle the
351 GElf_Shdr *shdr_dynsym, 392 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
352 size_t dynsym_idx, int verbose) 393 * .dynsym or .symtab).
394 * And always look at the original dso, not at debuginfo packages, that
395 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
396 */
397static int dso__synthesize_plt_symbols(struct dso *self, int v)
353{ 398{
354 uint32_t nr_rel_entries, idx; 399 uint32_t nr_rel_entries, idx;
355 GElf_Sym sym; 400 GElf_Sym sym;
356 u64 plt_offset; 401 u64 plt_offset;
357 GElf_Shdr shdr_plt; 402 GElf_Shdr shdr_plt;
358 struct symbol *f; 403 struct symbol *f;
359 GElf_Shdr shdr_rel_plt; 404 GElf_Shdr shdr_rel_plt, shdr_dynsym;
360 Elf_Data *reldata, *syms, *symstrs; 405 Elf_Data *reldata, *syms, *symstrs;
361 Elf_Scn *scn_plt_rel, *scn_symstrs; 406 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
407 size_t dynsym_idx;
408 GElf_Ehdr ehdr;
362 char sympltname[1024]; 409 char sympltname[1024];
363 int nr = 0, symidx; 410 Elf *elf;
411 int nr = 0, symidx, fd, err = 0;
412
413 fd = open(self->name, O_RDONLY);
414 if (fd < 0)
415 goto out;
416
417 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
418 if (elf == NULL)
419 goto out_close;
420
421 if (gelf_getehdr(elf, &ehdr) == NULL)
422 goto out_elf_end;
364 423
365 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 424 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
425 ".dynsym", &dynsym_idx);
426 if (scn_dynsym == NULL)
427 goto out_elf_end;
428
429 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
366 ".rela.plt", NULL); 430 ".rela.plt", NULL);
367 if (scn_plt_rel == NULL) { 431 if (scn_plt_rel == NULL) {
368 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 432 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
369 ".rel.plt", NULL); 433 ".rel.plt", NULL);
370 if (scn_plt_rel == NULL) 434 if (scn_plt_rel == NULL)
371 return 0; 435 goto out_elf_end;
372 } 436 }
373 437
438 err = -1;
439
374 if (shdr_rel_plt.sh_link != dynsym_idx) 440 if (shdr_rel_plt.sh_link != dynsym_idx)
375 return 0; 441 goto out_elf_end;
376 442
377 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 443 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
378 return 0; 444 goto out_elf_end;
379 445
380 /* 446 /*
381 * Fetch the relocation section to find the indexes to the GOT 447 * Fetch the relocation section to find the idxes to the GOT
382 * and the symbols in the .dynsym they refer to. 448 * and the symbols in the .dynsym they refer to.
383 */ 449 */
384 reldata = elf_getdata(scn_plt_rel, NULL); 450 reldata = elf_getdata(scn_plt_rel, NULL);
385 if (reldata == NULL) 451 if (reldata == NULL)
386 return -1; 452 goto out_elf_end;
387 453
388 syms = elf_getdata(scn_dynsym, NULL); 454 syms = elf_getdata(scn_dynsym, NULL);
389 if (syms == NULL) 455 if (syms == NULL)
390 return -1; 456 goto out_elf_end;
391 457
392 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 458 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
393 if (scn_symstrs == NULL) 459 if (scn_symstrs == NULL)
394 return -1; 460 goto out_elf_end;
395 461
396 symstrs = elf_getdata(scn_symstrs, NULL); 462 symstrs = elf_getdata(scn_symstrs, NULL);
397 if (symstrs == NULL) 463 if (symstrs == NULL)
398 return -1; 464 goto out_elf_end;
399 465
400 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 466 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
401 plt_offset = shdr_plt.sh_offset; 467 plt_offset = shdr_plt.sh_offset;
@@ -412,9 +478,9 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
412 "%s@plt", elf_sym__name(&sym, symstrs)); 478 "%s@plt", elf_sym__name(&sym, symstrs));
413 479
414 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 480 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
415 sympltname, self->sym_priv_size, 0, verbose); 481 sympltname, self->sym_priv_size, 0, v);
416 if (!f) 482 if (!f)
417 return -1; 483 goto out_elf_end;
418 484
419 dso__insert_symbol(self, f); 485 dso__insert_symbol(self, f);
420 ++nr; 486 ++nr;
@@ -430,79 +496,63 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
430 "%s@plt", elf_sym__name(&sym, symstrs)); 496 "%s@plt", elf_sym__name(&sym, symstrs));
431 497
432 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 498 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
433 sympltname, self->sym_priv_size, 0, verbose); 499 sympltname, self->sym_priv_size, 0, v);
434 if (!f) 500 if (!f)
435 return -1; 501 goto out_elf_end;
436 502
437 dso__insert_symbol(self, f); 503 dso__insert_symbol(self, f);
438 ++nr; 504 ++nr;
439 } 505 }
440 } else {
441 /*
442 * TODO: There are still one more shdr_rel_plt.sh_type
443 * I have to investigate, but probably should be ignored.
444 */
445 } 506 }
446 507
447 return nr; 508 err = 0;
509out_elf_end:
510 elf_end(elf);
511out_close:
512 close(fd);
513
514 if (err == 0)
515 return nr;
516out:
517 fprintf(stderr, "%s: problems reading %s PLT info.\n",
518 __func__, self->name);
519 return 0;
448} 520}
449 521
450static int dso__load_sym(struct dso *self, int fd, const char *name, 522static int dso__load_sym(struct dso *self, int fd, const char *name,
451 symbol_filter_t filter, int verbose) 523 symbol_filter_t filter, int v, struct module *mod)
452{ 524{
453 Elf_Data *symstrs; 525 Elf_Data *symstrs, *secstrs;
454 uint32_t nr_syms; 526 uint32_t nr_syms;
455 int err = -1; 527 int err = -1;
456 uint32_t index; 528 uint32_t idx;
457 GElf_Ehdr ehdr; 529 GElf_Ehdr ehdr;
458 GElf_Shdr shdr; 530 GElf_Shdr shdr;
459 Elf_Data *syms; 531 Elf_Data *syms;
460 GElf_Sym sym; 532 GElf_Sym sym;
461 Elf_Scn *sec, *sec_dynsym; 533 Elf_Scn *sec, *sec_strndx;
462 Elf *elf; 534 Elf *elf;
463 size_t dynsym_idx; 535 int nr = 0, kernel = !strcmp("[kernel]", self->name);
464 int nr = 0;
465 536
466 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 537 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
467 if (elf == NULL) { 538 if (elf == NULL) {
468 if (verbose) 539 if (v)
469 fprintf(stderr, "%s: cannot read %s ELF file.\n", 540 fprintf(stderr, "%s: cannot read %s ELF file.\n",
470 __func__, name); 541 __func__, name);
471 goto out_close; 542 goto out_close;
472 } 543 }
473 544
474 if (gelf_getehdr(elf, &ehdr) == NULL) { 545 if (gelf_getehdr(elf, &ehdr) == NULL) {
475 if (verbose) 546 if (v)
476 fprintf(stderr, "%s: cannot get elf header.\n", __func__); 547 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
477 goto out_elf_end; 548 goto out_elf_end;
478 } 549 }
479 550
480 /*
481 * We need to check if we have a .dynsym, so that we can handle the
482 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
483 * .dynsym or .symtab)
484 */
485 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
486 ".dynsym", &dynsym_idx);
487 if (sec_dynsym != NULL) {
488 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
489 sec_dynsym, &shdr,
490 dynsym_idx, verbose);
491 if (nr < 0)
492 goto out_elf_end;
493 }
494
495 /*
496 * But if we have a full .symtab (that is a superset of .dynsym) we
497 * should add the symbols not in the .dynsyn
498 */
499 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 551 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
500 if (sec == NULL) { 552 if (sec == NULL) {
501 if (sec_dynsym == NULL) 553 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
554 if (sec == NULL)
502 goto out_elf_end; 555 goto out_elf_end;
503
504 sec = sec_dynsym;
505 gelf_getshdr(sec, &shdr);
506 } 556 }
507 557
508 syms = elf_getdata(sec, NULL); 558 syms = elf_getdata(sec, NULL);
@@ -517,15 +567,34 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
517 if (symstrs == NULL) 567 if (symstrs == NULL)
518 goto out_elf_end; 568 goto out_elf_end;
519 569
570 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
571 if (sec_strndx == NULL)
572 goto out_elf_end;
573
574 secstrs = elf_getdata(sec_strndx, NULL);
575 if (secstrs == NULL)
576 goto out_elf_end;
577
520 nr_syms = shdr.sh_size / shdr.sh_entsize; 578 nr_syms = shdr.sh_size / shdr.sh_entsize;
521 579
522 memset(&sym, 0, sizeof(sym)); 580 memset(&sym, 0, sizeof(sym));
523 581 if (!kernel) {
524 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 582 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
583 elf_section_by_name(elf, &ehdr, &shdr,
584 ".gnu.prelink_undo",
585 NULL) != NULL);
586 } else self->adjust_symbols = 0;
587
588 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
525 struct symbol *f; 589 struct symbol *f;
590 const char *elf_name;
591 char *demangled;
526 u64 obj_start; 592 u64 obj_start;
593 struct section *section = NULL;
594 int is_label = elf_sym__is_label(&sym);
595 const char *section_name;
527 596
528 if (!elf_sym__is_function(&sym)) 597 if (!is_label && !elf_sym__is_function(&sym))
529 continue; 598 continue;
530 599
531 sec = elf_getscn(elf, sym.st_shndx); 600 sec = elf_getscn(elf, sym.st_shndx);
@@ -533,19 +602,51 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
533 goto out_elf_end; 602 goto out_elf_end;
534 603
535 gelf_getshdr(sec, &shdr); 604 gelf_getshdr(sec, &shdr);
605
606 if (is_label && !elf_sec__is_text(&shdr, secstrs))
607 continue;
608
609 section_name = elf_sec__name(&shdr, secstrs);
536 obj_start = sym.st_value; 610 obj_start = sym.st_value;
537 611
538 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 612 if (self->adjust_symbols) {
613 if (v >= 2)
614 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
615 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
539 616
540 f = symbol__new(sym.st_value, sym.st_size, 617 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
541 elf_sym__name(&sym, symstrs), 618 }
542 self->sym_priv_size, obj_start, verbose); 619
620 if (mod) {
621 section = mod->sections->find_section(mod->sections, section_name);
622 if (section)
623 sym.st_value += section->vma;
624 else {
625 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
626 mod->name, section_name);
627 goto out_elf_end;
628 }
629 }
630 /*
631 * We need to figure out if the object was created from C++ sources
632 * DWARF DW_compile_unit has this, but we don't always have access
633 * to it...
634 */
635 elf_name = elf_sym__name(&sym, symstrs);
636 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
637 if (demangled != NULL)
638 elf_name = demangled;
639
640 f = symbol__new(sym.st_value, sym.st_size, elf_name,
641 self->sym_priv_size, obj_start, v);
642 free(demangled);
543 if (!f) 643 if (!f)
544 goto out_elf_end; 644 goto out_elf_end;
545 645
546 if (filter && filter(self, f)) 646 if (filter && filter(self, f))
547 symbol__delete(f, self->sym_priv_size); 647 symbol__delete(f, self->sym_priv_size);
548 else { 648 else {
649 f->module = mod;
549 dso__insert_symbol(self, f); 650 dso__insert_symbol(self, f);
550 nr++; 651 nr++;
551 } 652 }
@@ -558,42 +659,135 @@ out_close:
558 return err; 659 return err;
559} 660}
560 661
561int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 662#define BUILD_ID_SIZE 128
663
664static char *dso__read_build_id(struct dso *self, int v)
562{ 665{
563 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 666 int i;
564 char *name = malloc(size); 667 GElf_Ehdr ehdr;
565 int variant = 0; 668 GElf_Shdr shdr;
669 Elf_Data *build_id_data;
670 Elf_Scn *sec;
671 char *build_id = NULL, *bid;
672 unsigned char *raw;
673 Elf *elf;
674 int fd = open(self->name, O_RDONLY);
675
676 if (fd < 0)
677 goto out;
678
679 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
680 if (elf == NULL) {
681 if (v)
682 fprintf(stderr, "%s: cannot read %s ELF file.\n",
683 __func__, self->name);
684 goto out_close;
685 }
686
687 if (gelf_getehdr(elf, &ehdr) == NULL) {
688 if (v)
689 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
690 goto out_elf_end;
691 }
692
693 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
694 if (sec == NULL)
695 goto out_elf_end;
696
697 build_id_data = elf_getdata(sec, NULL);
698 if (build_id_data == NULL)
699 goto out_elf_end;
700 build_id = malloc(BUILD_ID_SIZE);
701 if (build_id == NULL)
702 goto out_elf_end;
703 raw = build_id_data->d_buf + 16;
704 bid = build_id;
705
706 for (i = 0; i < 20; ++i) {
707 sprintf(bid, "%02x", *raw);
708 ++raw;
709 bid += 2;
710 }
711 if (v >= 2)
712 printf("%s(%s): %s\n", __func__, self->name, build_id);
713out_elf_end:
714 elf_end(elf);
715out_close:
716 close(fd);
717out:
718 return build_id;
719}
720
721char dso__symtab_origin(const struct dso *self)
722{
723 static const char origin[] = {
724 [DSO__ORIG_KERNEL] = 'k',
725 [DSO__ORIG_JAVA_JIT] = 'j',
726 [DSO__ORIG_FEDORA] = 'f',
727 [DSO__ORIG_UBUNTU] = 'u',
728 [DSO__ORIG_BUILDID] = 'b',
729 [DSO__ORIG_DSO] = 'd',
730 };
731
732 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
733 return '!';
734 return origin[self->origin];
735}
736
737int dso__load(struct dso *self, symbol_filter_t filter, int v)
738{
739 int size = PATH_MAX;
740 char *name = malloc(size), *build_id = NULL;
566 int ret = -1; 741 int ret = -1;
567 int fd; 742 int fd;
568 743
569 if (!name) 744 if (!name)
570 return -1; 745 return -1;
571 746
572 if (strncmp(self->name, "/tmp/perf-", 10) == 0) 747 self->adjust_symbols = 0;
573 return dso__load_perf_map(self, filter, verbose); 748
749 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
750 ret = dso__load_perf_map(self, filter, v);
751 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
752 DSO__ORIG_NOT_FOUND;
753 return ret;
754 }
755
756 self->origin = DSO__ORIG_FEDORA - 1;
574 757
575more: 758more:
576 do { 759 do {
577 switch (variant) { 760 self->origin++;
578 case 0: /* Fedora */ 761 switch (self->origin) {
762 case DSO__ORIG_FEDORA:
579 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 763 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
580 break; 764 break;
581 case 1: /* Ubuntu */ 765 case DSO__ORIG_UBUNTU:
582 snprintf(name, size, "/usr/lib/debug%s", self->name); 766 snprintf(name, size, "/usr/lib/debug%s", self->name);
583 break; 767 break;
584 case 2: /* Sane people */ 768 case DSO__ORIG_BUILDID:
769 build_id = dso__read_build_id(self, v);
770 if (build_id != NULL) {
771 snprintf(name, size,
772 "/usr/lib/debug/.build-id/%.2s/%s.debug",
773 build_id, build_id + 2);
774 free(build_id);
775 break;
776 }
777 self->origin++;
778 /* Fall thru */
779 case DSO__ORIG_DSO:
585 snprintf(name, size, "%s", self->name); 780 snprintf(name, size, "%s", self->name);
586 break; 781 break;
587 782
588 default: 783 default:
589 goto out; 784 goto out;
590 } 785 }
591 variant++;
592 786
593 fd = open(name, O_RDONLY); 787 fd = open(name, O_RDONLY);
594 } while (fd < 0); 788 } while (fd < 0);
595 789
596 ret = dso__load_sym(self, fd, name, filter, verbose); 790 ret = dso__load_sym(self, fd, name, filter, v, NULL);
597 close(fd); 791 close(fd);
598 792
599 /* 793 /*
@@ -602,39 +796,242 @@ more:
602 if (!ret) 796 if (!ret)
603 goto more; 797 goto more;
604 798
799 if (ret > 0) {
800 int nr_plt = dso__synthesize_plt_symbols(self, v);
801 if (nr_plt > 0)
802 ret += nr_plt;
803 }
605out: 804out:
606 free(name); 805 free(name);
806 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
807 return 0;
607 return ret; 808 return ret;
608} 809}
609 810
811static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
812 symbol_filter_t filter, int v)
813{
814 struct module *mod = mod_dso__find_module(mods, name);
815 int err = 0, fd;
816
817 if (mod == NULL || !mod->active)
818 return err;
819
820 fd = open(mod->path, O_RDONLY);
821
822 if (fd < 0)
823 return err;
824
825 err = dso__load_sym(self, fd, name, filter, v, mod);
826 close(fd);
827
828 return err;
829}
830
831int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
832{
833 struct mod_dso *mods = mod_dso__new_dso("modules");
834 struct module *pos;
835 struct rb_node *next;
836 int err, count = 0;
837
838 err = mod_dso__load_modules(mods);
839
840 if (err <= 0)
841 return err;
842
843 /*
844 * Iterate over modules, and load active symbols.
845 */
846 next = rb_first(&mods->mods);
847 while (next) {
848 pos = rb_entry(next, struct module, rb_node);
849 err = dso__load_module(self, mods, pos->name, filter, v);
850
851 if (err < 0)
852 break;
853
854 next = rb_next(&pos->rb_node);
855 count += err;
856 }
857
858 if (err < 0) {
859 mod_dso__delete_modules(mods);
860 mod_dso__delete_self(mods);
861 return err;
862 }
863
864 return count;
865}
866
867static inline void dso__fill_symbol_holes(struct dso *self)
868{
869 struct symbol *prev = NULL;
870 struct rb_node *nd;
871
872 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
873 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
874
875 if (prev) {
876 u64 hole = 0;
877 int alias = pos->start == prev->start;
878
879 if (!alias)
880 hole = prev->start - pos->end - 1;
881
882 if (hole || alias) {
883 if (alias)
884 pos->end = prev->end;
885 else if (hole)
886 pos->end = prev->start - 1;
887 }
888 }
889 prev = pos;
890 }
891}
892
610static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 893static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
611 symbol_filter_t filter, int verbose) 894 symbol_filter_t filter, int v)
612{ 895{
613 int err, fd = open(vmlinux, O_RDONLY); 896 int err, fd = open(vmlinux, O_RDONLY);
614 897
615 if (fd < 0) 898 if (fd < 0)
616 return -1; 899 return -1;
617 900
618 err = dso__load_sym(self, fd, vmlinux, filter, verbose); 901 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
902
903 if (err > 0)
904 dso__fill_symbol_holes(self);
905
619 close(fd); 906 close(fd);
620 907
621 return err; 908 return err;
622} 909}
623 910
624int dso__load_kernel(struct dso *self, const char *vmlinux, 911int dso__load_kernel(struct dso *self, const char *vmlinux,
625 symbol_filter_t filter, int verbose) 912 symbol_filter_t filter, int v, int use_modules)
626{ 913{
627 int err = -1; 914 int err = -1;
628 915
629 if (vmlinux) 916 if (vmlinux) {
630 err = dso__load_vmlinux(self, vmlinux, filter, verbose); 917 err = dso__load_vmlinux(self, vmlinux, filter, v);
918 if (err > 0 && use_modules) {
919 int syms = dso__load_modules(self, filter, v);
920
921 if (syms < 0) {
922 fprintf(stderr, "dso__load_modules failed!\n");
923 return syms;
924 }
925 err += syms;
926 }
927 }
631 928
632 if (err) 929 if (err <= 0)
633 err = dso__load_kallsyms(self, filter, verbose); 930 err = dso__load_kallsyms(self, filter, v);
931
932 if (err > 0)
933 self->origin = DSO__ORIG_KERNEL;
634 934
635 return err; 935 return err;
636} 936}
637 937
938LIST_HEAD(dsos);
939struct dso *kernel_dso;
940struct dso *vdso;
941struct dso *hypervisor_dso;
942
943const char *vmlinux_name = "vmlinux";
944int modules;
945
946static void dsos__add(struct dso *dso)
947{
948 list_add_tail(&dso->node, &dsos);
949}
950
951static struct dso *dsos__find(const char *name)
952{
953 struct dso *pos;
954
955 list_for_each_entry(pos, &dsos, node)
956 if (strcmp(pos->name, name) == 0)
957 return pos;
958 return NULL;
959}
960
961struct dso *dsos__findnew(const char *name)
962{
963 struct dso *dso = dsos__find(name);
964 int nr;
965
966 if (dso)
967 return dso;
968
969 dso = dso__new(name, 0);
970 if (!dso)
971 goto out_delete_dso;
972
973 nr = dso__load(dso, NULL, verbose);
974 if (nr < 0) {
975 eprintf("Failed to open: %s\n", name);
976 goto out_delete_dso;
977 }
978 if (!nr)
979 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
980
981 dsos__add(dso);
982
983 return dso;
984
985out_delete_dso:
986 dso__delete(dso);
987 return NULL;
988}
989
990void dsos__fprintf(FILE *fp)
991{
992 struct dso *pos;
993
994 list_for_each_entry(pos, &dsos, node)
995 dso__fprintf(pos, fp);
996}
997
998static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
999{
1000 return dso__find_symbol(dso, ip);
1001}
1002
1003int load_kernel(void)
1004{
1005 int err;
1006
1007 kernel_dso = dso__new("[kernel]", 0);
1008 if (!kernel_dso)
1009 return -1;
1010
1011 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
1012 if (err <= 0) {
1013 dso__delete(kernel_dso);
1014 kernel_dso = NULL;
1015 } else
1016 dsos__add(kernel_dso);
1017
1018 vdso = dso__new("[vdso]", 0);
1019 if (!vdso)
1020 return -1;
1021
1022 vdso->find_symbol = vdso__find_symbol;
1023
1024 dsos__add(vdso);
1025
1026 hypervisor_dso = dso__new("[hypervisor]", 0);
1027 if (!hypervisor_dso)
1028 return -1;
1029 dsos__add(hypervisor_dso);
1030
1031 return err;
1032}
1033
1034
638void symbol__init(void) 1035void symbol__init(void)
639{ 1036{
640 elf_version(EV_CURRENT); 1037 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ea332e56e458..6e8490716408 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -2,9 +2,35 @@
2#define _PERF_SYMBOL_ 1 2#define _PERF_SYMBOL_ 1
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include "../types.h" 5#include "types.h"
6#include "list.h" 6#include <linux/list.h>
7#include "rbtree.h" 7#include <linux/rbtree.h>
8#include "module.h"
9#include "event.h"
10
11#ifdef HAVE_CPLUS_DEMANGLE
12extern char *cplus_demangle(const char *, int);
13
14static inline char *bfd_demangle(void __used *v, const char *c, int i)
15{
16 return cplus_demangle(c, i);
17}
18#else
19#ifdef NO_DEMANGLE
20static inline char *bfd_demangle(void __used *v, const char __used *c,
21 int __used i)
22{
23 return NULL;
24}
25#else
26#include <bfd.h>
27#endif
28#endif
29
30#ifndef DMGL_PARAMS
31#define DMGL_PARAMS (1 << 0) /* Include function args */
32#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
33#endif
8 34
9struct symbol { 35struct symbol {
10 struct rb_node rb_node; 36 struct rb_node rb_node;
@@ -13,6 +39,7 @@ struct symbol {
13 u64 obj_start; 39 u64 obj_start;
14 u64 hist_sum; 40 u64 hist_sum;
15 u64 *hist; 41 u64 *hist;
42 struct module *module;
16 void *priv; 43 void *priv;
17 char name[0]; 44 char name[0];
18}; 45};
@@ -20,12 +47,15 @@ struct symbol {
20struct dso { 47struct dso {
21 struct list_head node; 48 struct list_head node;
22 struct rb_root syms; 49 struct rb_root syms;
23 unsigned int sym_priv_size;
24 struct symbol *(*find_symbol)(struct dso *, u64 ip); 50 struct symbol *(*find_symbol)(struct dso *, u64 ip);
51 unsigned int sym_priv_size;
52 unsigned char adjust_symbols;
53 unsigned char slen_calculated;
54 unsigned char origin;
25 char name[0]; 55 char name[0];
26}; 56};
27 57
28const char *sym_hist_filter; 58extern const char *sym_hist_filter;
29 59
30typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); 60typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
31 61
@@ -40,10 +70,23 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
40struct symbol *dso__find_symbol(struct dso *self, u64 ip); 70struct symbol *dso__find_symbol(struct dso *self, u64 ip);
41 71
42int dso__load_kernel(struct dso *self, const char *vmlinux, 72int dso__load_kernel(struct dso *self, const char *vmlinux,
43 symbol_filter_t filter, int verbose); 73 symbol_filter_t filter, int verbose, int modules);
74int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
44int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 75int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
76struct dso *dsos__findnew(const char *name);
77void dsos__fprintf(FILE *fp);
45 78
46size_t dso__fprintf(struct dso *self, FILE *fp); 79size_t dso__fprintf(struct dso *self, FILE *fp);
80char dso__symtab_origin(const struct dso *self);
81
82int load_kernel(void);
47 83
48void symbol__init(void); 84void symbol__init(void);
85
86extern struct list_head dsos;
87extern struct dso *kernel_dso;
88extern struct dso *vdso;
89extern struct dso *hypervisor_dso;
90extern const char *vmlinux_name;
91extern int modules;
49#endif /* _PERF_SYMBOL_ */ 92#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
new file mode 100644
index 000000000000..45efb5db0d19
--- /dev/null
+++ b/tools/perf/util/thread.c
@@ -0,0 +1,175 @@
1#include "../perf.h"
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include "thread.h"
6#include "util.h"
7#include "debug.h"
8
9static struct thread *thread__new(pid_t pid)
10{
11 struct thread *self = calloc(1, sizeof(*self));
12
13 if (self != NULL) {
14 self->pid = pid;
15 self->comm = malloc(32);
16 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid);
18 INIT_LIST_HEAD(&self->maps);
19 }
20
21 return self;
22}
23
24int thread__set_comm(struct thread *self, const char *comm)
25{
26 if (self->comm)
27 free(self->comm);
28 self->comm = strdup(comm);
29 return self->comm ? 0 : -ENOMEM;
30}
31
32static size_t thread__fprintf(struct thread *self, FILE *fp)
33{
34 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
36
37 list_for_each_entry(pos, &self->maps, node)
38 ret += map__fprintf(pos, fp);
39
40 return ret;
41}
42
43struct thread *
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45{
46 struct rb_node **p = &threads->rb_node;
47 struct rb_node *parent = NULL;
48 struct thread *th;
49
50 /*
51 * Font-end cache - PID lookups come in blocks,
52 * so most of the time we dont have to look up
53 * the full rbtree:
54 */
55 if (*last_match && (*last_match)->pid == pid)
56 return *last_match;
57
58 while (*p != NULL) {
59 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node);
61
62 if (th->pid == pid) {
63 *last_match = th;
64 return th;
65 }
66
67 if (pid < th->pid)
68 p = &(*p)->rb_left;
69 else
70 p = &(*p)->rb_right;
71 }
72
73 th = thread__new(pid);
74 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads);
77 *last_match = th;
78 }
79
80 return th;
81}
82
83struct thread *
84register_idle_thread(struct rb_root *threads, struct thread **last_match)
85{
86 struct thread *thread = threads__findnew(0, threads, last_match);
87
88 if (!thread || thread__set_comm(thread, "swapper")) {
89 fprintf(stderr, "problem inserting idle task.\n");
90 exit(-1);
91 }
92
93 return thread;
94}
95
96void thread__insert_map(struct thread *self, struct map *map)
97{
98 struct map *pos, *tmp;
99
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
101 if (map__overlap(pos, map)) {
102 if (verbose >= 2) {
103 printf("overlapping maps:\n");
104 map__fprintf(map, stdout);
105 map__fprintf(pos, stdout);
106 }
107
108 if (map->start <= pos->start && map->end > pos->start)
109 pos->start = map->end;
110
111 if (map->end >= pos->end && map->start < pos->end)
112 pos->end = map->start;
113
114 if (verbose >= 2) {
115 printf("after collision:\n");
116 map__fprintf(pos, stdout);
117 }
118
119 if (pos->start >= pos->end) {
120 list_del_init(&pos->node);
121 free(pos);
122 }
123 }
124 }
125
126 list_add_tail(&map->node, &self->maps);
127}
128
129int thread__fork(struct thread *self, struct thread *parent)
130{
131 struct map *map;
132
133 if (self->comm)
134 free(self->comm);
135 self->comm = strdup(parent->comm);
136 if (!self->comm)
137 return -ENOMEM;
138
139 list_for_each_entry(map, &parent->maps, node) {
140 struct map *new = map__clone(map);
141 if (!new)
142 return -ENOMEM;
143 thread__insert_map(self, new);
144 }
145
146 return 0;
147}
148
149struct map *thread__find_map(struct thread *self, u64 ip)
150{
151 struct map *pos;
152
153 if (self == NULL)
154 return NULL;
155
156 list_for_each_entry(pos, &self->maps, node)
157 if (ip >= pos->start && ip <= pos->end)
158 return pos;
159
160 return NULL;
161}
162
163size_t threads__fprintf(FILE *fp, struct rb_root *threads)
164{
165 size_t ret = 0;
166 struct rb_node *nd;
167
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170
171 ret += thread__fprintf(pos, fp);
172 }
173
174 return ret;
175}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
new file mode 100644
index 000000000000..32aea3c1c2ad
--- /dev/null
+++ b/tools/perf/util/thread.h
@@ -0,0 +1,22 @@
1#include <linux/rbtree.h>
2#include <linux/list.h>
3#include <unistd.h>
4#include "symbol.h"
5
6struct thread {
7 struct rb_node rb_node;
8 struct list_head maps;
9 pid_t pid;
10 char shortname[3];
11 char *comm;
12};
13
14int thread__set_comm(struct thread *self, const char *comm);
15struct thread *
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match);
17struct thread *
18register_idle_thread(struct rb_root *threads, struct thread **last_match);
19void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
new file mode 100644
index 000000000000..af4b0573b37f
--- /dev/null
+++ b/tools/perf/util/trace-event-info.c
@@ -0,0 +1,540 @@
1/*
2 * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _GNU_SOURCE
22#include <dirent.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdarg.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/wait.h>
30#include <pthread.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <ctype.h>
34#include <errno.h>
35#include <stdbool.h>
36
37#include "../perf.h"
38#include "trace-event.h"
39
40
41#define VERSION "0.5"
42
43#define _STR(x) #x
44#define STR(x) _STR(x)
45#define MAX_PATH 256
46
47#define TRACE_CTRL "tracing_on"
48#define TRACE "trace"
49#define AVAILABLE "available_tracers"
50#define CURRENT "current_tracer"
51#define ITER_CTRL "trace_options"
52#define MAX_LATENCY "tracing_max_latency"
53
54unsigned int page_size;
55
56static const char *output_file = "trace.info";
57static int output_fd;
58
59struct event_list {
60 struct event_list *next;
61 const char *event;
62};
63
64struct events {
65 struct events *sibling;
66 struct events *children;
67 struct events *next;
68 char *name;
69};
70
71
72
73static void die(const char *fmt, ...)
74{
75 va_list ap;
76 int ret = errno;
77
78 if (errno)
79 perror("trace-cmd");
80 else
81 ret = -1;
82
83 va_start(ap, fmt);
84 fprintf(stderr, " ");
85 vfprintf(stderr, fmt, ap);
86 va_end(ap);
87
88 fprintf(stderr, "\n");
89 exit(ret);
90}
91
92void *malloc_or_die(unsigned int size)
93{
94 void *data;
95
96 data = malloc(size);
97 if (!data)
98 die("malloc");
99 return data;
100}
101
102static const char *find_debugfs(void)
103{
104 static char debugfs[MAX_PATH+1];
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126
127 debugfs_found = 1;
128
129 return debugfs;
130}
131
132/*
133 * Finds the path to the debugfs/tracing
134 * Allocates the string and stores it.
135 */
136static const char *find_tracing_dir(void)
137{
138 static char *tracing;
139 static int tracing_found;
140 const char *debugfs;
141
142 if (tracing_found)
143 return tracing;
144
145 debugfs = find_debugfs();
146
147 tracing = malloc_or_die(strlen(debugfs) + 9);
148
149 sprintf(tracing, "%s/tracing", debugfs);
150
151 tracing_found = 1;
152 return tracing;
153}
154
155static char *get_tracing_file(const char *name)
156{
157 const char *tracing;
158 char *file;
159
160 tracing = find_tracing_dir();
161 if (!tracing)
162 return NULL;
163
164 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
165
166 sprintf(file, "%s/%s", tracing, name);
167 return file;
168}
169
170static void put_tracing_file(char *file)
171{
172 free(file);
173}
174
175static ssize_t write_or_die(const void *buf, size_t len)
176{
177 int ret;
178
179 ret = write(output_fd, buf, len);
180 if (ret < 0)
181 die("writing to '%s'", output_file);
182
183 return ret;
184}
185
186int bigendian(void)
187{
188 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
189 unsigned int *ptr;
190
191 ptr = (unsigned int *)(void *)str;
192 return *ptr == 0x01020304;
193}
194
195static unsigned long long copy_file_fd(int fd)
196{
197 unsigned long long size = 0;
198 char buf[BUFSIZ];
199 int r;
200
201 do {
202 r = read(fd, buf, BUFSIZ);
203 if (r > 0) {
204 size += r;
205 write_or_die(buf, r);
206 }
207 } while (r > 0);
208
209 return size;
210}
211
212static unsigned long long copy_file(const char *file)
213{
214 unsigned long long size = 0;
215 int fd;
216
217 fd = open(file, O_RDONLY);
218 if (fd < 0)
219 die("Can't read '%s'", file);
220 size = copy_file_fd(fd);
221 close(fd);
222
223 return size;
224}
225
226static unsigned long get_size_fd(int fd)
227{
228 unsigned long long size = 0;
229 char buf[BUFSIZ];
230 int r;
231
232 do {
233 r = read(fd, buf, BUFSIZ);
234 if (r > 0)
235 size += r;
236 } while (r > 0);
237
238 lseek(fd, 0, SEEK_SET);
239
240 return size;
241}
242
243static unsigned long get_size(const char *file)
244{
245 unsigned long long size = 0;
246 int fd;
247
248 fd = open(file, O_RDONLY);
249 if (fd < 0)
250 die("Can't read '%s'", file);
251 size = get_size_fd(fd);
252 close(fd);
253
254 return size;
255}
256
257static void read_header_files(void)
258{
259 unsigned long long size, check_size;
260 char *path;
261 int fd;
262
263 path = get_tracing_file("events/header_page");
264 fd = open(path, O_RDONLY);
265 if (fd < 0)
266 die("can't read '%s'", path);
267
268 /* unfortunately, you can not stat debugfs files for size */
269 size = get_size_fd(fd);
270
271 write_or_die("header_page", 12);
272 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd);
274 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size);
277 put_tracing_file(path);
278
279 path = get_tracing_file("events/header_event");
280 fd = open(path, O_RDONLY);
281 if (fd < 0)
282 die("can't read '%s'", path);
283
284 size = get_size_fd(fd);
285
286 write_or_die("header_event", 13);
287 write_or_die(&size, 8);
288 check_size = copy_file_fd(fd);
289 if (size != check_size)
290 die("wrong size for '%s'", path);
291 put_tracing_file(path);
292}
293
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
295{
296 while (tps) {
297 if (!strcmp(sys, tps->name))
298 return true;
299 tps = tps->next;
300 }
301
302 return false;
303}
304
305static void copy_event_system(const char *sys, struct tracepoint_path *tps)
306{
307 unsigned long long size, check_size;
308 struct dirent *dent;
309 struct stat st;
310 char *format;
311 DIR *dir;
312 int count = 0;
313 int ret;
314
315 dir = opendir(sys);
316 if (!dir)
317 die("can't read directory '%s'", sys);
318
319 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps))
323 continue;
324 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
325 sprintf(format, "%s/%s/format", sys, dent->d_name);
326 ret = stat(format, &st);
327 free(format);
328 if (ret < 0)
329 continue;
330 count++;
331 }
332
333 write_or_die(&count, 4);
334
335 rewinddir(dir);
336 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps))
340 continue;
341 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
342 sprintf(format, "%s/%s/format", sys, dent->d_name);
343 ret = stat(format, &st);
344
345 if (ret >= 0) {
346 /* unfortunately, you can not stat debugfs files for size */
347 size = get_size(format);
348 write_or_die(&size, 8);
349 check_size = copy_file(format);
350 if (size != check_size)
351 die("error in size of file '%s'", format);
352 }
353
354 free(format);
355 }
356}
357
358static void read_ftrace_files(struct tracepoint_path *tps)
359{
360 char *path;
361
362 path = get_tracing_file("events/ftrace");
363
364 copy_event_system(path, tps);
365
366 put_tracing_file(path);
367}
368
369static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
370{
371 while (tps) {
372 if (!strcmp(sys, tps->system))
373 return true;
374 tps = tps->next;
375 }
376
377 return false;
378}
379
380static void read_event_files(struct tracepoint_path *tps)
381{
382 struct dirent *dent;
383 struct stat st;
384 char *path;
385 char *sys;
386 DIR *dir;
387 int count = 0;
388 int ret;
389
390 path = get_tracing_file("events");
391
392 dir = opendir(path);
393 if (!dir)
394 die("can't read directory '%s'", path);
395
396 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps))
401 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 }
411
412 write_or_die(&count, 4);
413
414 rewinddir(dir);
415 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps))
420 continue;
421 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
422 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st);
424 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) {
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
427 copy_event_system(sys, tps);
428 }
429 }
430 free(sys);
431 }
432
433 put_tracing_file(path);
434}
435
436static void read_proc_kallsyms(void)
437{
438 unsigned int size, check_size;
439 const char *path = "/proc/kallsyms";
440 struct stat st;
441 int ret;
442
443 ret = stat(path, &st);
444 if (ret < 0) {
445 /* not found */
446 size = 0;
447 write_or_die(&size, 4);
448 return;
449 }
450 size = get_size(path);
451 write_or_die(&size, 4);
452 check_size = copy_file(path);
453 if (size != check_size)
454 die("error in size of file '%s'", path);
455
456}
457
458static void read_ftrace_printk(void)
459{
460 unsigned int size, check_size;
461 char *path;
462 struct stat st;
463 int ret;
464
465 path = get_tracing_file("printk_formats");
466 ret = stat(path, &st);
467 if (ret < 0) {
468 /* not found */
469 size = 0;
470 write_or_die(&size, 4);
471 goto out;
472 }
473 size = get_size(path);
474 write_or_die(&size, 4);
475 check_size = copy_file(path);
476 if (size != check_size)
477 die("error in size of file '%s'", path);
478out:
479 put_tracing_file(path);
480}
481
482static struct tracepoint_path *
483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
484{
485 struct tracepoint_path path, *ppath = &path;
486 int i;
487
488 for (i = 0; i < nb_events; i++) {
489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
490 continue;
491 ppath->next = tracepoint_id_to_path(pattrs[i].config);
492 if (!ppath->next)
493 die("%s\n", "No memory to alloc tracepoints list");
494 ppath = ppath->next;
495 }
496
497 return path.next;
498}
499void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
500{
501 char buf[BUFSIZ];
502 struct tracepoint_path *tps;
503
504 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
505 if (output_fd < 0)
506 die("creating file '%s'", output_file);
507
508 buf[0] = 23;
509 buf[1] = 8;
510 buf[2] = 68;
511 memcpy(buf + 3, "tracing", 7);
512
513 write_or_die(buf, 10);
514
515 write_or_die(VERSION, strlen(VERSION) + 1);
516
517 /* save endian */
518 if (bigendian())
519 buf[0] = 1;
520 else
521 buf[0] = 0;
522
523 write_or_die(buf, 1);
524
525 /* save size of long */
526 buf[0] = sizeof(long);
527 write_or_die(buf, 1);
528
529 /* save page_size */
530 page_size = getpagesize();
531 write_or_die(&page_size, 4);
532
533 tps = get_tracepoints_path(pattrs, nb_events);
534
535 read_header_files();
536 read_ftrace_files(tps);
537 read_event_files(tps);
538 read_proc_kallsyms();
539 read_ftrace_printk();
540}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
new file mode 100644
index 000000000000..f6a8437141c8
--- /dev/null
+++ b/tools/perf/util/trace-event-parse.c
@@ -0,0 +1,2967 @@
1/*
2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 *
21 * The parts for function graph printing was taken and modified from the
22 * Linux Kernel that were written by Frederic Weisbecker.
23 */
24#define _GNU_SOURCE
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ctype.h>
29#include <errno.h>
30
31#undef _GNU_SOURCE
32#include "../perf.h"
33#include "util.h"
34#include "trace-event.h"
35
36int header_page_ts_offset;
37int header_page_ts_size;
38int header_page_size_offset;
39int header_page_size_size;
40int header_page_data_offset;
41int header_page_data_size;
42
43static char *input_buf;
44static unsigned long long input_buf_ptr;
45static unsigned long long input_buf_siz;
46
47static int cpus;
48static int long_size;
49
50static void init_input_buf(char *buf, unsigned long long size)
51{
52 input_buf = buf;
53 input_buf_siz = size;
54 input_buf_ptr = 0;
55}
56
57struct cmdline {
58 char *comm;
59 int pid;
60};
61
62static struct cmdline *cmdlines;
63static int cmdline_count;
64
65static int cmdline_cmp(const void *a, const void *b)
66{
67 const struct cmdline *ca = a;
68 const struct cmdline *cb = b;
69
70 if (ca->pid < cb->pid)
71 return -1;
72 if (ca->pid > cb->pid)
73 return 1;
74
75 return 0;
76}
77
78void parse_cmdlines(char *file, int size __unused)
79{
80 struct cmdline_list {
81 struct cmdline_list *next;
82 char *comm;
83 int pid;
84 } *list = NULL, *item;
85 char *line;
86 char *next = NULL;
87 int i;
88
89 line = strtok_r(file, "\n", &next);
90 while (line) {
91 item = malloc_or_die(sizeof(*item));
92 sscanf(line, "%d %as", &item->pid,
93 (float *)(void *)&item->comm); /* workaround gcc warning */
94 item->next = list;
95 list = item;
96 line = strtok_r(NULL, "\n", &next);
97 cmdline_count++;
98 }
99
100 cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
101
102 i = 0;
103 while (list) {
104 cmdlines[i].pid = list->pid;
105 cmdlines[i].comm = list->comm;
106 i++;
107 item = list;
108 list = list->next;
109 free(item);
110 }
111
112 qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
113}
114
115static struct func_map {
116 unsigned long long addr;
117 char *func;
118 char *mod;
119} *func_list;
120static unsigned int func_count;
121
122static int func_cmp(const void *a, const void *b)
123{
124 const struct func_map *fa = a;
125 const struct func_map *fb = b;
126
127 if (fa->addr < fb->addr)
128 return -1;
129 if (fa->addr > fb->addr)
130 return 1;
131
132 return 0;
133}
134
135void parse_proc_kallsyms(char *file, unsigned int size __unused)
136{
137 struct func_list {
138 struct func_list *next;
139 unsigned long long addr;
140 char *func;
141 char *mod;
142 } *list = NULL, *item;
143 char *line;
144 char *next = NULL;
145 char *addr_str;
146 char ch;
147 int ret;
148 int i;
149
150 line = strtok_r(file, "\n", &next);
151 while (line) {
152 item = malloc_or_die(sizeof(*item));
153 item->mod = NULL;
154 ret = sscanf(line, "%as %c %as\t[%as",
155 (float *)(void *)&addr_str, /* workaround gcc warning */
156 &ch,
157 (float *)(void *)&item->func,
158 (float *)(void *)&item->mod);
159 item->addr = strtoull(addr_str, NULL, 16);
160 free(addr_str);
161
162 /* truncate the extra ']' */
163 if (item->mod)
164 item->mod[strlen(item->mod) - 1] = 0;
165
166
167 item->next = list;
168 list = item;
169 line = strtok_r(NULL, "\n", &next);
170 func_count++;
171 }
172
173 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1);
174
175 i = 0;
176 while (list) {
177 func_list[i].func = list->func;
178 func_list[i].addr = list->addr;
179 func_list[i].mod = list->mod;
180 i++;
181 item = list;
182 list = list->next;
183 free(item);
184 }
185
186 qsort(func_list, func_count, sizeof(*func_list), func_cmp);
187
188 /*
189 * Add a special record at the end.
190 */
191 func_list[func_count].func = NULL;
192 func_list[func_count].addr = 0;
193 func_list[func_count].mod = NULL;
194}
195
196/*
197 * We are searching for a record in between, not an exact
198 * match.
199 */
200static int func_bcmp(const void *a, const void *b)
201{
202 const struct func_map *fa = a;
203 const struct func_map *fb = b;
204
205 if ((fa->addr == fb->addr) ||
206
207 (fa->addr > fb->addr &&
208 fa->addr < (fb+1)->addr))
209 return 0;
210
211 if (fa->addr < fb->addr)
212 return -1;
213
214 return 1;
215}
216
217static struct func_map *find_func(unsigned long long addr)
218{
219 struct func_map *func;
220 struct func_map key;
221
222 key.addr = addr;
223
224 func = bsearch(&key, func_list, func_count, sizeof(*func_list),
225 func_bcmp);
226
227 return func;
228}
229
230void print_funcs(void)
231{
232 int i;
233
234 for (i = 0; i < (int)func_count; i++) {
235 printf("%016llx %s",
236 func_list[i].addr,
237 func_list[i].func);
238 if (func_list[i].mod)
239 printf(" [%s]\n", func_list[i].mod);
240 else
241 printf("\n");
242 }
243}
244
245static struct printk_map {
246 unsigned long long addr;
247 char *printk;
248} *printk_list;
249static unsigned int printk_count;
250
251static int printk_cmp(const void *a, const void *b)
252{
253 const struct func_map *fa = a;
254 const struct func_map *fb = b;
255
256 if (fa->addr < fb->addr)
257 return -1;
258 if (fa->addr > fb->addr)
259 return 1;
260
261 return 0;
262}
263
264static struct printk_map *find_printk(unsigned long long addr)
265{
266 struct printk_map *printk;
267 struct printk_map key;
268
269 key.addr = addr;
270
271 printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
272 printk_cmp);
273
274 return printk;
275}
276
277void parse_ftrace_printk(char *file, unsigned int size __unused)
278{
279 struct printk_list {
280 struct printk_list *next;
281 unsigned long long addr;
282 char *printk;
283 } *list = NULL, *item;
284 char *line;
285 char *next = NULL;
286 char *addr_str;
287 int ret;
288 int i;
289
290 line = strtok_r(file, "\n", &next);
291 while (line) {
292 item = malloc_or_die(sizeof(*item));
293 ret = sscanf(line, "%as : %as",
294 (float *)(void *)&addr_str, /* workaround gcc warning */
295 (float *)(void *)&item->printk);
296 item->addr = strtoull(addr_str, NULL, 16);
297 free(addr_str);
298
299 item->next = list;
300 list = item;
301 line = strtok_r(NULL, "\n", &next);
302 printk_count++;
303 }
304
305 printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
306
307 i = 0;
308 while (list) {
309 printk_list[i].printk = list->printk;
310 printk_list[i].addr = list->addr;
311 i++;
312 item = list;
313 list = list->next;
314 free(item);
315 }
316
317 qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
318}
319
320void print_printk(void)
321{
322 int i;
323
324 for (i = 0; i < (int)printk_count; i++) {
325 printf("%016llx %s\n",
326 printk_list[i].addr,
327 printk_list[i].printk);
328 }
329}
330
331static struct event *alloc_event(void)
332{
333 struct event *event;
334
335 event = malloc_or_die(sizeof(*event));
336 memset(event, 0, sizeof(*event));
337
338 return event;
339}
340
341enum event_type {
342 EVENT_ERROR,
343 EVENT_NONE,
344 EVENT_SPACE,
345 EVENT_NEWLINE,
346 EVENT_OP,
347 EVENT_DELIM,
348 EVENT_ITEM,
349 EVENT_DQUOTE,
350 EVENT_SQUOTE,
351};
352
353static struct event *event_list;
354
355static void add_event(struct event *event)
356{
357 event->next = event_list;
358 event_list = event;
359}
360
361static int event_item_type(enum event_type type)
362{
363 switch (type) {
364 case EVENT_ITEM ... EVENT_SQUOTE:
365 return 1;
366 case EVENT_ERROR ... EVENT_DELIM:
367 default:
368 return 0;
369 }
370}
371
372static void free_arg(struct print_arg *arg)
373{
374 if (!arg)
375 return;
376
377 switch (arg->type) {
378 case PRINT_ATOM:
379 if (arg->atom.atom)
380 free(arg->atom.atom);
381 break;
382 case PRINT_NULL:
383 case PRINT_FIELD ... PRINT_OP:
384 default:
385 /* todo */
386 break;
387 }
388
389 free(arg);
390}
391
392static enum event_type get_type(int ch)
393{
394 if (ch == '\n')
395 return EVENT_NEWLINE;
396 if (isspace(ch))
397 return EVENT_SPACE;
398 if (isalnum(ch) || ch == '_')
399 return EVENT_ITEM;
400 if (ch == '\'')
401 return EVENT_SQUOTE;
402 if (ch == '"')
403 return EVENT_DQUOTE;
404 if (!isprint(ch))
405 return EVENT_NONE;
406 if (ch == '(' || ch == ')' || ch == ',')
407 return EVENT_DELIM;
408
409 return EVENT_OP;
410}
411
412static int __read_char(void)
413{
414 if (input_buf_ptr >= input_buf_siz)
415 return -1;
416
417 return input_buf[input_buf_ptr++];
418}
419
420static int __peek_char(void)
421{
422 if (input_buf_ptr >= input_buf_siz)
423 return -1;
424
425 return input_buf[input_buf_ptr];
426}
427
428static enum event_type __read_token(char **tok)
429{
430 char buf[BUFSIZ];
431 int ch, last_ch, quote_ch, next_ch;
432 int i = 0;
433 int tok_size = 0;
434 enum event_type type;
435
436 *tok = NULL;
437
438
439 ch = __read_char();
440 if (ch < 0)
441 return EVENT_NONE;
442
443 type = get_type(ch);
444 if (type == EVENT_NONE)
445 return type;
446
447 buf[i++] = ch;
448
449 switch (type) {
450 case EVENT_NEWLINE:
451 case EVENT_DELIM:
452 *tok = malloc_or_die(2);
453 (*tok)[0] = ch;
454 (*tok)[1] = 0;
455 return type;
456
457 case EVENT_OP:
458 switch (ch) {
459 case '-':
460 next_ch = __peek_char();
461 if (next_ch == '>') {
462 buf[i++] = __read_char();
463 break;
464 }
465 /* fall through */
466 case '+':
467 case '|':
468 case '&':
469 case '>':
470 case '<':
471 last_ch = ch;
472 ch = __peek_char();
473 if (ch != last_ch)
474 goto test_equal;
475 buf[i++] = __read_char();
476 switch (last_ch) {
477 case '>':
478 case '<':
479 goto test_equal;
480 default:
481 break;
482 }
483 break;
484 case '!':
485 case '=':
486 goto test_equal;
487 default: /* what should we do instead? */
488 break;
489 }
490 buf[i] = 0;
491 *tok = strdup(buf);
492 return type;
493
494 test_equal:
495 ch = __peek_char();
496 if (ch == '=')
497 buf[i++] = __read_char();
498 break;
499
500 case EVENT_DQUOTE:
501 case EVENT_SQUOTE:
502 /* don't keep quotes */
503 i--;
504 quote_ch = ch;
505 last_ch = 0;
506 do {
507 if (i == (BUFSIZ - 1)) {
508 buf[i] = 0;
509 if (*tok) {
510 *tok = realloc(*tok, tok_size + BUFSIZ);
511 if (!*tok)
512 return EVENT_NONE;
513 strcat(*tok, buf);
514 } else
515 *tok = strdup(buf);
516
517 if (!*tok)
518 return EVENT_NONE;
519 tok_size += BUFSIZ;
520 i = 0;
521 }
522 last_ch = ch;
523 ch = __read_char();
524 buf[i++] = ch;
525 } while (ch != quote_ch && last_ch != '\\');
526 /* remove the last quote */
527 i--;
528 goto out;
529
530 case EVENT_ERROR ... EVENT_SPACE:
531 case EVENT_ITEM:
532 default:
533 break;
534 }
535
536 while (get_type(__peek_char()) == type) {
537 if (i == (BUFSIZ - 1)) {
538 buf[i] = 0;
539 if (*tok) {
540 *tok = realloc(*tok, tok_size + BUFSIZ);
541 if (!*tok)
542 return EVENT_NONE;
543 strcat(*tok, buf);
544 } else
545 *tok = strdup(buf);
546
547 if (!*tok)
548 return EVENT_NONE;
549 tok_size += BUFSIZ;
550 i = 0;
551 }
552 ch = __read_char();
553 buf[i++] = ch;
554 }
555
556 out:
557 buf[i] = 0;
558 if (*tok) {
559 *tok = realloc(*tok, tok_size + i);
560 if (!*tok)
561 return EVENT_NONE;
562 strcat(*tok, buf);
563 } else
564 *tok = strdup(buf);
565 if (!*tok)
566 return EVENT_NONE;
567
568 return type;
569}
570
571static void free_token(char *tok)
572{
573 if (tok)
574 free(tok);
575}
576
577static enum event_type read_token(char **tok)
578{
579 enum event_type type;
580
581 for (;;) {
582 type = __read_token(tok);
583 if (type != EVENT_SPACE)
584 return type;
585
586 free_token(*tok);
587 }
588
589 /* not reached */
590 return EVENT_NONE;
591}
592
593/* no newline */
594static enum event_type read_token_item(char **tok)
595{
596 enum event_type type;
597
598 for (;;) {
599 type = __read_token(tok);
600 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
601 return type;
602
603 free_token(*tok);
604 }
605
606 /* not reached */
607 return EVENT_NONE;
608}
609
610static int test_type(enum event_type type, enum event_type expect)
611{
612 if (type != expect) {
613 die("Error: expected type %d but read %d",
614 expect, type);
615 return -1;
616 }
617 return 0;
618}
619
620static int test_type_token(enum event_type type, char *token,
621 enum event_type expect, char *expect_tok)
622{
623 if (type != expect) {
624 die("Error: expected type %d but read %d",
625 expect, type);
626 return -1;
627 }
628
629 if (strcmp(token, expect_tok) != 0) {
630 die("Error: expected '%s' but read '%s'",
631 expect_tok, token);
632 return -1;
633 }
634 return 0;
635}
636
637static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
638{
639 enum event_type type;
640
641 if (newline_ok)
642 type = read_token(tok);
643 else
644 type = read_token_item(tok);
645 return test_type(type, expect);
646}
647
648static int read_expect_type(enum event_type expect, char **tok)
649{
650 return __read_expect_type(expect, tok, 1);
651}
652
653static int __read_expected(enum event_type expect, char *str, int newline_ok)
654{
655 enum event_type type;
656 char *token;
657 int ret;
658
659 if (newline_ok)
660 type = read_token(&token);
661 else
662 type = read_token_item(&token);
663
664 ret = test_type_token(type, token, expect, str);
665
666 free_token(token);
667
668 return 0;
669}
670
671static int read_expected(enum event_type expect, char *str)
672{
673 return __read_expected(expect, str, 1);
674}
675
676static int read_expected_item(enum event_type expect, char *str)
677{
678 return __read_expected(expect, str, 0);
679}
680
681static char *event_read_name(void)
682{
683 char *token;
684
685 if (read_expected(EVENT_ITEM, (char *)"name") < 0)
686 return NULL;
687
688 if (read_expected(EVENT_OP, (char *)":") < 0)
689 return NULL;
690
691 if (read_expect_type(EVENT_ITEM, &token) < 0)
692 goto fail;
693
694 return token;
695
696 fail:
697 free_token(token);
698 return NULL;
699}
700
701static int event_read_id(void)
702{
703 char *token;
704 int id;
705
706 if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0)
707 return -1;
708
709 if (read_expected(EVENT_OP, (char *)":") < 0)
710 return -1;
711
712 if (read_expect_type(EVENT_ITEM, &token) < 0)
713 goto fail;
714
715 id = strtoul(token, NULL, 0);
716 free_token(token);
717 return id;
718
719 fail:
720 free_token(token);
721 return -1;
722}
723
724static int event_read_fields(struct event *event, struct format_field **fields)
725{
726 struct format_field *field = NULL;
727 enum event_type type;
728 char *token;
729 char *last_token;
730 int count = 0;
731
732 do {
733 type = read_token(&token);
734 if (type == EVENT_NEWLINE) {
735 free_token(token);
736 return count;
737 }
738
739 count++;
740
741 if (test_type_token(type, token, EVENT_ITEM, (char *)"field"))
742 goto fail;
743 free_token(token);
744
745 type = read_token(&token);
746 /*
747 * The ftrace fields may still use the "special" name.
748 * Just ignore it.
749 */
750 if (event->flags & EVENT_FL_ISFTRACE &&
751 type == EVENT_ITEM && strcmp(token, "special") == 0) {
752 free_token(token);
753 type = read_token(&token);
754 }
755
756 if (test_type_token(type, token, EVENT_OP, (char *)":") < 0)
757 return -1;
758
759 if (read_expect_type(EVENT_ITEM, &token) < 0)
760 goto fail;
761
762 last_token = token;
763
764 field = malloc_or_die(sizeof(*field));
765 memset(field, 0, sizeof(*field));
766
767 /* read the rest of the type */
768 for (;;) {
769 type = read_token(&token);
770 if (type == EVENT_ITEM ||
771 (type == EVENT_OP && strcmp(token, "*") == 0) ||
772 /*
773 * Some of the ftrace fields are broken and have
774 * an illegal "." in them.
775 */
776 (event->flags & EVENT_FL_ISFTRACE &&
777 type == EVENT_OP && strcmp(token, ".") == 0)) {
778
779 if (strcmp(token, "*") == 0)
780 field->flags |= FIELD_IS_POINTER;
781
782 if (field->type) {
783 field->type = realloc(field->type,
784 strlen(field->type) +
785 strlen(last_token) + 2);
786 strcat(field->type, " ");
787 strcat(field->type, last_token);
788 } else
789 field->type = last_token;
790 last_token = token;
791 continue;
792 }
793
794 break;
795 }
796
797 if (!field->type) {
798 die("no type found");
799 goto fail;
800 }
801 field->name = last_token;
802
803 if (test_type(type, EVENT_OP))
804 goto fail;
805
806 if (strcmp(token, "[") == 0) {
807 enum event_type last_type = type;
808 char *brackets = token;
809 int len;
810
811 field->flags |= FIELD_IS_ARRAY;
812
813 type = read_token(&token);
814 while (strcmp(token, "]") != 0) {
815 if (last_type == EVENT_ITEM &&
816 type == EVENT_ITEM)
817 len = 2;
818 else
819 len = 1;
820 last_type = type;
821
822 brackets = realloc(brackets,
823 strlen(brackets) +
824 strlen(token) + len);
825 if (len == 2)
826 strcat(brackets, " ");
827 strcat(brackets, token);
828 free_token(token);
829 type = read_token(&token);
830 if (type == EVENT_NONE) {
831 die("failed to find token");
832 goto fail;
833 }
834 }
835
836 free_token(token);
837
838 brackets = realloc(brackets, strlen(brackets) + 2);
839 strcat(brackets, "]");
840
841 /* add brackets to type */
842
843 type = read_token(&token);
844 /*
845 * If the next token is not an OP, then it is of
846 * the format: type [] item;
847 */
848 if (type == EVENT_ITEM) {
849 field->type = realloc(field->type,
850 strlen(field->type) +
851 strlen(field->name) +
852 strlen(brackets) + 2);
853 strcat(field->type, " ");
854 strcat(field->type, field->name);
855 free_token(field->name);
856 strcat(field->type, brackets);
857 field->name = token;
858 type = read_token(&token);
859 } else {
860 field->type = realloc(field->type,
861 strlen(field->type) +
862 strlen(brackets) + 1);
863 strcat(field->type, brackets);
864 }
865 free(brackets);
866 }
867
868 if (test_type_token(type, token, EVENT_OP, (char *)";"))
869 goto fail;
870 free_token(token);
871
872 if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
873 goto fail_expect;
874
875 if (read_expected(EVENT_OP, (char *)":") < 0)
876 goto fail_expect;
877
878 if (read_expect_type(EVENT_ITEM, &token))
879 goto fail;
880 field->offset = strtoul(token, NULL, 0);
881 free_token(token);
882
883 if (read_expected(EVENT_OP, (char *)";") < 0)
884 goto fail_expect;
885
886 if (read_expected(EVENT_ITEM, (char *)"size") < 0)
887 goto fail_expect;
888
889 if (read_expected(EVENT_OP, (char *)":") < 0)
890 goto fail_expect;
891
892 if (read_expect_type(EVENT_ITEM, &token))
893 goto fail;
894 field->size = strtoul(token, NULL, 0);
895 free_token(token);
896
897 if (read_expected(EVENT_OP, (char *)";") < 0)
898 goto fail_expect;
899
900 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
901 goto fail;
902 free_token(token);
903
904 *fields = field;
905 fields = &field->next;
906
907 } while (1);
908
909 return 0;
910
911fail:
912 free_token(token);
913fail_expect:
914 if (field)
915 free(field);
916 return -1;
917}
918
919static int event_read_format(struct event *event)
920{
921 char *token;
922 int ret;
923
924 if (read_expected_item(EVENT_ITEM, (char *)"format") < 0)
925 return -1;
926
927 if (read_expected(EVENT_OP, (char *)":") < 0)
928 return -1;
929
930 if (read_expect_type(EVENT_NEWLINE, &token))
931 goto fail;
932 free_token(token);
933
934 ret = event_read_fields(event, &event->format.common_fields);
935 if (ret < 0)
936 return ret;
937 event->format.nr_common = ret;
938
939 ret = event_read_fields(event, &event->format.fields);
940 if (ret < 0)
941 return ret;
942 event->format.nr_fields = ret;
943
944 return 0;
945
946 fail:
947 free_token(token);
948 return -1;
949}
950
951enum event_type
952process_arg_token(struct event *event, struct print_arg *arg,
953 char **tok, enum event_type type);
954
955static enum event_type
956process_arg(struct event *event, struct print_arg *arg, char **tok)
957{
958 enum event_type type;
959 char *token;
960
961 type = read_token(&token);
962 *tok = token;
963
964 return process_arg_token(event, arg, tok, type);
965}
966
967static enum event_type
968process_cond(struct event *event, struct print_arg *top, char **tok)
969{
970 struct print_arg *arg, *left, *right;
971 enum event_type type;
972 char *token = NULL;
973
974 arg = malloc_or_die(sizeof(*arg));
975 memset(arg, 0, sizeof(*arg));
976
977 left = malloc_or_die(sizeof(*left));
978
979 right = malloc_or_die(sizeof(*right));
980
981 arg->type = PRINT_OP;
982 arg->op.left = left;
983 arg->op.right = right;
984
985 *tok = NULL;
986 type = process_arg(event, left, &token);
987 if (test_type_token(type, token, EVENT_OP, (char *)":"))
988 goto out_free;
989
990 arg->op.op = token;
991
992 type = process_arg(event, right, &token);
993
994 top->op.right = arg;
995
996 *tok = token;
997 return type;
998
999out_free:
1000 free_token(*tok);
1001 free(right);
1002 free(left);
1003 free_arg(arg);
1004 return EVENT_ERROR;
1005}
1006
1007static int get_op_prio(char *op)
1008{
1009 if (!op[1]) {
1010 switch (op[0]) {
1011 case '*':
1012 case '/':
1013 case '%':
1014 return 6;
1015 case '+':
1016 case '-':
1017 return 7;
1018 /* '>>' and '<<' are 8 */
1019 case '<':
1020 case '>':
1021 return 9;
1022 /* '==' and '!=' are 10 */
1023 case '&':
1024 return 11;
1025 case '^':
1026 return 12;
1027 case '|':
1028 return 13;
1029 case '?':
1030 return 16;
1031 default:
1032 die("unknown op '%c'", op[0]);
1033 return -1;
1034 }
1035 } else {
1036 if (strcmp(op, "++") == 0 ||
1037 strcmp(op, "--") == 0) {
1038 return 3;
1039 } else if (strcmp(op, ">>") == 0 ||
1040 strcmp(op, "<<") == 0) {
1041 return 8;
1042 } else if (strcmp(op, ">=") == 0 ||
1043 strcmp(op, "<=") == 0) {
1044 return 9;
1045 } else if (strcmp(op, "==") == 0 ||
1046 strcmp(op, "!=") == 0) {
1047 return 10;
1048 } else if (strcmp(op, "&&") == 0) {
1049 return 14;
1050 } else if (strcmp(op, "||") == 0) {
1051 return 15;
1052 } else {
1053 die("unknown op '%s'", op);
1054 return -1;
1055 }
1056 }
1057}
1058
1059static void set_op_prio(struct print_arg *arg)
1060{
1061
1062 /* single ops are the greatest */
1063 if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
1064 arg->op.prio = 0;
1065 return;
1066 }
1067
1068 arg->op.prio = get_op_prio(arg->op.op);
1069}
1070
1071static enum event_type
1072process_op(struct event *event, struct print_arg *arg, char **tok)
1073{
1074 struct print_arg *left, *right = NULL;
1075 enum event_type type;
1076 char *token;
1077
1078 /* the op is passed in via tok */
1079 token = *tok;
1080
1081 if (arg->type == PRINT_OP && !arg->op.left) {
1082 /* handle single op */
1083 if (token[1]) {
1084 die("bad op token %s", token);
1085 return EVENT_ERROR;
1086 }
1087 switch (token[0]) {
1088 case '!':
1089 case '+':
1090 case '-':
1091 break;
1092 default:
1093 die("bad op token %s", token);
1094 return EVENT_ERROR;
1095 }
1096
1097 /* make an empty left */
1098 left = malloc_or_die(sizeof(*left));
1099 left->type = PRINT_NULL;
1100 arg->op.left = left;
1101
1102 right = malloc_or_die(sizeof(*right));
1103 arg->op.right = right;
1104
1105 type = process_arg(event, right, tok);
1106
1107 } else if (strcmp(token, "?") == 0) {
1108
1109 left = malloc_or_die(sizeof(*left));
1110 /* copy the top arg to the left */
1111 *left = *arg;
1112
1113 arg->type = PRINT_OP;
1114 arg->op.op = token;
1115 arg->op.left = left;
1116 arg->op.prio = 0;
1117
1118 type = process_cond(event, arg, tok);
1119
1120 } else if (strcmp(token, ">>") == 0 ||
1121 strcmp(token, "<<") == 0 ||
1122 strcmp(token, "&") == 0 ||
1123 strcmp(token, "|") == 0 ||
1124 strcmp(token, "&&") == 0 ||
1125 strcmp(token, "||") == 0 ||
1126 strcmp(token, "-") == 0 ||
1127 strcmp(token, "+") == 0 ||
1128 strcmp(token, "*") == 0 ||
1129 strcmp(token, "^") == 0 ||
1130 strcmp(token, "/") == 0 ||
1131 strcmp(token, "==") == 0 ||
1132 strcmp(token, "!=") == 0) {
1133
1134 left = malloc_or_die(sizeof(*left));
1135
1136 /* copy the top arg to the left */
1137 *left = *arg;
1138
1139 arg->type = PRINT_OP;
1140 arg->op.op = token;
1141 arg->op.left = left;
1142
1143 set_op_prio(arg);
1144
1145 right = malloc_or_die(sizeof(*right));
1146
1147 type = process_arg(event, right, tok);
1148
1149 arg->op.right = right;
1150
1151 } else {
1152 die("unknown op '%s'", token);
1153 /* the arg is now the left side */
1154 return EVENT_NONE;
1155 }
1156
1157
1158 if (type == EVENT_OP) {
1159 int prio;
1160
1161 /* higher prios need to be closer to the root */
1162 prio = get_op_prio(*tok);
1163
1164 if (prio > arg->op.prio)
1165 return process_op(event, arg, tok);
1166
1167 return process_op(event, right, tok);
1168 }
1169
1170 return type;
1171}
1172
1173static enum event_type
1174process_entry(struct event *event __unused, struct print_arg *arg,
1175 char **tok)
1176{
1177 enum event_type type;
1178 char *field;
1179 char *token;
1180
1181 if (read_expected(EVENT_OP, (char *)"->") < 0)
1182 return EVENT_ERROR;
1183
1184 if (read_expect_type(EVENT_ITEM, &token) < 0)
1185 goto fail;
1186 field = token;
1187
1188 arg->type = PRINT_FIELD;
1189 arg->field.name = field;
1190
1191 type = read_token(&token);
1192 *tok = token;
1193
1194 return type;
1195
1196fail:
1197 free_token(token);
1198 return EVENT_ERROR;
1199}
1200
1201static char *arg_eval (struct print_arg *arg);
1202
1203static long long arg_num_eval(struct print_arg *arg)
1204{
1205 long long left, right;
1206 long long val = 0;
1207
1208 switch (arg->type) {
1209 case PRINT_ATOM:
1210 val = strtoll(arg->atom.atom, NULL, 0);
1211 break;
1212 case PRINT_TYPE:
1213 val = arg_num_eval(arg->typecast.item);
1214 break;
1215 case PRINT_OP:
1216 switch (arg->op.op[0]) {
1217 case '|':
1218 left = arg_num_eval(arg->op.left);
1219 right = arg_num_eval(arg->op.right);
1220 if (arg->op.op[1])
1221 val = left || right;
1222 else
1223 val = left | right;
1224 break;
1225 case '&':
1226 left = arg_num_eval(arg->op.left);
1227 right = arg_num_eval(arg->op.right);
1228 if (arg->op.op[1])
1229 val = left && right;
1230 else
1231 val = left & right;
1232 break;
1233 case '<':
1234 left = arg_num_eval(arg->op.left);
1235 right = arg_num_eval(arg->op.right);
1236 switch (arg->op.op[1]) {
1237 case 0:
1238 val = left < right;
1239 break;
1240 case '<':
1241 val = left << right;
1242 break;
1243 case '=':
1244 val = left <= right;
1245 break;
1246 default:
1247 die("unknown op '%s'", arg->op.op);
1248 }
1249 break;
1250 case '>':
1251 left = arg_num_eval(arg->op.left);
1252 right = arg_num_eval(arg->op.right);
1253 switch (arg->op.op[1]) {
1254 case 0:
1255 val = left > right;
1256 break;
1257 case '>':
1258 val = left >> right;
1259 break;
1260 case '=':
1261 val = left >= right;
1262 break;
1263 default:
1264 die("unknown op '%s'", arg->op.op);
1265 }
1266 break;
1267 case '=':
1268 left = arg_num_eval(arg->op.left);
1269 right = arg_num_eval(arg->op.right);
1270
1271 if (arg->op.op[1] != '=')
1272 die("unknown op '%s'", arg->op.op);
1273
1274 val = left == right;
1275 break;
1276 case '!':
1277 left = arg_num_eval(arg->op.left);
1278 right = arg_num_eval(arg->op.right);
1279
1280 switch (arg->op.op[1]) {
1281 case '=':
1282 val = left != right;
1283 break;
1284 default:
1285 die("unknown op '%s'", arg->op.op);
1286 }
1287 break;
1288 default:
1289 die("unknown op '%s'", arg->op.op);
1290 }
1291 break;
1292
1293 case PRINT_NULL:
1294 case PRINT_FIELD ... PRINT_SYMBOL:
1295 case PRINT_STRING:
1296 default:
1297 die("invalid eval type %d", arg->type);
1298
1299 }
1300 return val;
1301}
1302
1303static char *arg_eval (struct print_arg *arg)
1304{
1305 long long val;
1306 static char buf[20];
1307
1308 switch (arg->type) {
1309 case PRINT_ATOM:
1310 return arg->atom.atom;
1311 case PRINT_TYPE:
1312 return arg_eval(arg->typecast.item);
1313 case PRINT_OP:
1314 val = arg_num_eval(arg);
1315 sprintf(buf, "%lld", val);
1316 return buf;
1317
1318 case PRINT_NULL:
1319 case PRINT_FIELD ... PRINT_SYMBOL:
1320 case PRINT_STRING:
1321 default:
1322 die("invalid eval type %d", arg->type);
1323 break;
1324 }
1325
1326 return NULL;
1327}
1328
1329static enum event_type
1330process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1331{
1332 enum event_type type;
1333 struct print_arg *arg = NULL;
1334 struct print_flag_sym *field;
1335 char *token = NULL;
1336 char *value;
1337
1338 do {
1339 free_token(token);
1340 type = read_token_item(&token);
1341 if (test_type_token(type, token, EVENT_OP, (char *)"{"))
1342 break;
1343
1344 arg = malloc_or_die(sizeof(*arg));
1345
1346 free_token(token);
1347 type = process_arg(event, arg, &token);
1348 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1349 goto out_free;
1350
1351 field = malloc_or_die(sizeof(*field));
1352 memset(field, 0, sizeof(field));
1353
1354 value = arg_eval(arg);
1355 field->value = strdup(value);
1356
1357 free_token(token);
1358 type = process_arg(event, arg, &token);
1359 if (test_type_token(type, token, EVENT_OP, (char *)"}"))
1360 goto out_free;
1361
1362 value = arg_eval(arg);
1363 field->str = strdup(value);
1364 free_arg(arg);
1365 arg = NULL;
1366
1367 *list = field;
1368 list = &field->next;
1369
1370 free_token(token);
1371 type = read_token_item(&token);
1372 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
1373
1374 *tok = token;
1375 return type;
1376
1377out_free:
1378 free_arg(arg);
1379 free_token(token);
1380
1381 return EVENT_ERROR;
1382}
1383
1384static enum event_type
1385process_flags(struct event *event, struct print_arg *arg, char **tok)
1386{
1387 struct print_arg *field;
1388 enum event_type type;
1389 char *token;
1390
1391 memset(arg, 0, sizeof(*arg));
1392 arg->type = PRINT_FLAGS;
1393
1394 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
1395 return EVENT_ERROR;
1396
1397 field = malloc_or_die(sizeof(*field));
1398
1399 type = process_arg(event, field, &token);
1400 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1401 goto out_free;
1402
1403 arg->flags.field = field;
1404
1405 type = read_token_item(&token);
1406 if (event_item_type(type)) {
1407 arg->flags.delim = token;
1408 type = read_token_item(&token);
1409 }
1410
1411 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1412 goto out_free;
1413
1414 type = process_fields(event, &arg->flags.flags, &token);
1415 if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
1416 goto out_free;
1417
1418 free_token(token);
1419 type = read_token_item(tok);
1420 return type;
1421
1422out_free:
1423 free_token(token);
1424 return EVENT_ERROR;
1425}
1426
1427static enum event_type
1428process_symbols(struct event *event, struct print_arg *arg, char **tok)
1429{
1430 struct print_arg *field;
1431 enum event_type type;
1432 char *token;
1433
1434 memset(arg, 0, sizeof(*arg));
1435 arg->type = PRINT_SYMBOL;
1436
1437 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
1438 return EVENT_ERROR;
1439
1440 field = malloc_or_die(sizeof(*field));
1441
1442 type = process_arg(event, field, &token);
1443 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1444 goto out_free;
1445
1446 arg->symbol.field = field;
1447
1448 type = process_fields(event, &arg->symbol.symbols, &token);
1449 if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
1450 goto out_free;
1451
1452 free_token(token);
1453 type = read_token_item(tok);
1454 return type;
1455
1456out_free:
1457 free_token(token);
1458 return EVENT_ERROR;
1459}
1460
1461static enum event_type
1462process_paren(struct event *event, struct print_arg *arg, char **tok)
1463{
1464 struct print_arg *item_arg;
1465 enum event_type type;
1466 int ptr_cast = 0;
1467 char *token;
1468
1469 type = process_arg(event, arg, &token);
1470
1471 if (type == EVENT_ERROR)
1472 return EVENT_ERROR;
1473
1474 if (type == EVENT_OP) {
1475 /* handle the ptr casts */
1476 if (!strcmp(token, "*")) {
1477 /*
1478 * FIXME: should we zapp whitespaces before ')' ?
1479 * (may require a peek_token_item())
1480 */
1481 if (__peek_char() == ')') {
1482 ptr_cast = 1;
1483 free_token(token);
1484 type = read_token_item(&token);
1485 }
1486 }
1487 if (!ptr_cast) {
1488 type = process_op(event, arg, &token);
1489
1490 if (type == EVENT_ERROR)
1491 return EVENT_ERROR;
1492 }
1493 }
1494
1495 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) {
1496 free_token(token);
1497 return EVENT_ERROR;
1498 }
1499
1500 free_token(token);
1501 type = read_token_item(&token);
1502
1503 /*
1504 * If the next token is an item or another open paren, then
1505 * this was a typecast.
1506 */
1507 if (event_item_type(type) ||
1508 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
1509
1510 /* make this a typecast and contine */
1511
1512 /* prevous must be an atom */
1513 if (arg->type != PRINT_ATOM)
1514 die("previous needed to be PRINT_ATOM");
1515
1516 item_arg = malloc_or_die(sizeof(*item_arg));
1517
1518 arg->type = PRINT_TYPE;
1519 if (ptr_cast) {
1520 char *old = arg->atom.atom;
1521
1522 arg->atom.atom = malloc_or_die(strlen(old + 3));
1523 sprintf(arg->atom.atom, "%s *", old);
1524 free(old);
1525 }
1526 arg->typecast.type = arg->atom.atom;
1527 arg->typecast.item = item_arg;
1528 type = process_arg_token(event, item_arg, &token, type);
1529
1530 }
1531
1532 *tok = token;
1533 return type;
1534}
1535
1536
1537static enum event_type
1538process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1539{
1540 enum event_type type;
1541 char *token;
1542
1543 if (read_expected(EVENT_DELIM, (char *)"(") < 0)
1544 return EVENT_ERROR;
1545
1546 if (read_expect_type(EVENT_ITEM, &token) < 0)
1547 goto fail;
1548
1549 arg->type = PRINT_STRING;
1550 arg->string.string = token;
1551 arg->string.offset = -1;
1552
1553 if (read_expected(EVENT_DELIM, (char *)")") < 0)
1554 return EVENT_ERROR;
1555
1556 type = read_token(&token);
1557 *tok = token;
1558
1559 return type;
1560fail:
1561 free_token(token);
1562 return EVENT_ERROR;
1563}
1564
1565enum event_type
1566process_arg_token(struct event *event, struct print_arg *arg,
1567 char **tok, enum event_type type)
1568{
1569 char *token;
1570 char *atom;
1571
1572 token = *tok;
1573
1574 switch (type) {
1575 case EVENT_ITEM:
1576 if (strcmp(token, "REC") == 0) {
1577 free_token(token);
1578 type = process_entry(event, arg, &token);
1579 } else if (strcmp(token, "__print_flags") == 0) {
1580 free_token(token);
1581 type = process_flags(event, arg, &token);
1582 } else if (strcmp(token, "__print_symbolic") == 0) {
1583 free_token(token);
1584 type = process_symbols(event, arg, &token);
1585 } else if (strcmp(token, "__get_str") == 0) {
1586 free_token(token);
1587 type = process_str(event, arg, &token);
1588 } else {
1589 atom = token;
1590 /* test the next token */
1591 type = read_token_item(&token);
1592
1593 /* atoms can be more than one token long */
1594 while (type == EVENT_ITEM) {
1595 atom = realloc(atom, strlen(atom) + strlen(token) + 2);
1596 strcat(atom, " ");
1597 strcat(atom, token);
1598 free_token(token);
1599 type = read_token_item(&token);
1600 }
1601
1602 /* todo, test for function */
1603
1604 arg->type = PRINT_ATOM;
1605 arg->atom.atom = atom;
1606 }
1607 break;
1608 case EVENT_DQUOTE:
1609 case EVENT_SQUOTE:
1610 arg->type = PRINT_ATOM;
1611 arg->atom.atom = token;
1612 type = read_token_item(&token);
1613 break;
1614 case EVENT_DELIM:
1615 if (strcmp(token, "(") == 0) {
1616 free_token(token);
1617 type = process_paren(event, arg, &token);
1618 break;
1619 }
1620 case EVENT_OP:
1621 /* handle single ops */
1622 arg->type = PRINT_OP;
1623 arg->op.op = token;
1624 arg->op.left = NULL;
1625 type = process_op(event, arg, &token);
1626
1627 break;
1628
1629 case EVENT_ERROR ... EVENT_NEWLINE:
1630 default:
1631 die("unexpected type %d", type);
1632 }
1633 *tok = token;
1634
1635 return type;
1636}
1637
1638static int event_read_print_args(struct event *event, struct print_arg **list)
1639{
1640 enum event_type type;
1641 struct print_arg *arg;
1642 char *token;
1643 int args = 0;
1644
1645 do {
1646 arg = malloc_or_die(sizeof(*arg));
1647 memset(arg, 0, sizeof(*arg));
1648
1649 type = process_arg(event, arg, &token);
1650
1651 if (type == EVENT_ERROR) {
1652 free_arg(arg);
1653 return -1;
1654 }
1655
1656 *list = arg;
1657 args++;
1658
1659 if (type == EVENT_OP) {
1660 type = process_op(event, arg, &token);
1661 list = &arg->next;
1662 continue;
1663 }
1664
1665 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
1666 free_token(token);
1667 *list = arg;
1668 list = &arg->next;
1669 continue;
1670 }
1671 break;
1672 } while (type != EVENT_NONE);
1673
1674 if (type != EVENT_NONE)
1675 free_token(token);
1676
1677 return args;
1678}
1679
1680static int event_read_print(struct event *event)
1681{
1682 enum event_type type;
1683 char *token;
1684 int ret;
1685
1686 if (read_expected_item(EVENT_ITEM, (char *)"print") < 0)
1687 return -1;
1688
1689 if (read_expected(EVENT_ITEM, (char *)"fmt") < 0)
1690 return -1;
1691
1692 if (read_expected(EVENT_OP, (char *)":") < 0)
1693 return -1;
1694
1695 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1696 goto fail;
1697
1698 event->print_fmt.format = token;
1699 event->print_fmt.args = NULL;
1700
1701 /* ok to have no arg */
1702 type = read_token_item(&token);
1703
1704 if (type == EVENT_NONE)
1705 return 0;
1706
1707 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1708 goto fail;
1709
1710 free_token(token);
1711
1712 ret = event_read_print_args(event, &event->print_fmt.args);
1713 if (ret < 0)
1714 return -1;
1715
1716 return 0;
1717
1718 fail:
1719 free_token(token);
1720 return -1;
1721}
1722
1723static struct format_field *
1724find_common_field(struct event *event, const char *name)
1725{
1726 struct format_field *format;
1727
1728 for (format = event->format.common_fields;
1729 format; format = format->next) {
1730 if (strcmp(format->name, name) == 0)
1731 break;
1732 }
1733
1734 return format;
1735}
1736
1737static struct format_field *
1738find_field(struct event *event, const char *name)
1739{
1740 struct format_field *format;
1741
1742 for (format = event->format.fields;
1743 format; format = format->next) {
1744 if (strcmp(format->name, name) == 0)
1745 break;
1746 }
1747
1748 return format;
1749}
1750
1751static struct format_field *
1752find_any_field(struct event *event, const char *name)
1753{
1754 struct format_field *format;
1755
1756 format = find_common_field(event, name);
1757 if (format)
1758 return format;
1759 return find_field(event, name);
1760}
1761
1762static unsigned long long read_size(void *ptr, int size)
1763{
1764 switch (size) {
1765 case 1:
1766 return *(unsigned char *)ptr;
1767 case 2:
1768 return data2host2(ptr);
1769 case 4:
1770 return data2host4(ptr);
1771 case 8:
1772 return data2host8(ptr);
1773 default:
1774 /* BUG! */
1775 return 0;
1776 }
1777}
1778
1779unsigned long long
1780raw_field_value(struct event *event, const char *name, void *data)
1781{
1782 struct format_field *field;
1783
1784 field = find_any_field(event, name);
1785 if (!field)
1786 return 0ULL;
1787
1788 return read_size(data + field->offset, field->size);
1789}
1790
1791void *raw_field_ptr(struct event *event, const char *name, void *data)
1792{
1793 struct format_field *field;
1794
1795 field = find_any_field(event, name);
1796 if (!field)
1797 return NULL;
1798
1799 return data + field->offset;
1800}
1801
1802static int get_common_info(const char *type, int *offset, int *size)
1803{
1804 struct event *event;
1805 struct format_field *field;
1806
1807 /*
1808 * All events should have the same common elements.
1809 * Pick any event to find where the type is;
1810 */
1811 if (!event_list)
1812 die("no event_list!");
1813
1814 event = event_list;
1815 field = find_common_field(event, type);
1816 if (!field)
1817 die("field '%s' not found", type);
1818
1819 *offset = field->offset;
1820 *size = field->size;
1821
1822 return 0;
1823}
1824
1825int trace_parse_common_type(void *data)
1826{
1827 static int type_offset;
1828 static int type_size;
1829 int ret;
1830
1831 if (!type_size) {
1832 ret = get_common_info("common_type",
1833 &type_offset,
1834 &type_size);
1835 if (ret < 0)
1836 return ret;
1837 }
1838 return read_size(data + type_offset, type_size);
1839}
1840
1841static int parse_common_pid(void *data)
1842{
1843 static int pid_offset;
1844 static int pid_size;
1845 int ret;
1846
1847 if (!pid_size) {
1848 ret = get_common_info("common_pid",
1849 &pid_offset,
1850 &pid_size);
1851 if (ret < 0)
1852 return ret;
1853 }
1854
1855 return read_size(data + pid_offset, pid_size);
1856}
1857
1858struct event *trace_find_event(int id)
1859{
1860 struct event *event;
1861
1862 for (event = event_list; event; event = event->next) {
1863 if (event->id == id)
1864 break;
1865 }
1866 return event;
1867}
1868
1869static unsigned long long eval_num_arg(void *data, int size,
1870 struct event *event, struct print_arg *arg)
1871{
1872 unsigned long long val = 0;
1873 unsigned long long left, right;
1874
1875 switch (arg->type) {
1876 case PRINT_NULL:
1877 /* ?? */
1878 return 0;
1879 case PRINT_ATOM:
1880 return strtoull(arg->atom.atom, NULL, 0);
1881 case PRINT_FIELD:
1882 if (!arg->field.field) {
1883 arg->field.field = find_any_field(event, arg->field.name);
1884 if (!arg->field.field)
1885 die("field %s not found", arg->field.name);
1886 }
1887 /* must be a number */
1888 val = read_size(data + arg->field.field->offset,
1889 arg->field.field->size);
1890 break;
1891 case PRINT_FLAGS:
1892 case PRINT_SYMBOL:
1893 break;
1894 case PRINT_TYPE:
1895 return eval_num_arg(data, size, event, arg->typecast.item);
1896 case PRINT_STRING:
1897 return 0;
1898 break;
1899 case PRINT_OP:
1900 left = eval_num_arg(data, size, event, arg->op.left);
1901 right = eval_num_arg(data, size, event, arg->op.right);
1902 switch (arg->op.op[0]) {
1903 case '|':
1904 if (arg->op.op[1])
1905 val = left || right;
1906 else
1907 val = left | right;
1908 break;
1909 case '&':
1910 if (arg->op.op[1])
1911 val = left && right;
1912 else
1913 val = left & right;
1914 break;
1915 case '<':
1916 switch (arg->op.op[1]) {
1917 case 0:
1918 val = left < right;
1919 break;
1920 case '<':
1921 val = left << right;
1922 break;
1923 case '=':
1924 val = left <= right;
1925 break;
1926 default:
1927 die("unknown op '%s'", arg->op.op);
1928 }
1929 break;
1930 case '>':
1931 switch (arg->op.op[1]) {
1932 case 0:
1933 val = left > right;
1934 break;
1935 case '>':
1936 val = left >> right;
1937 break;
1938 case '=':
1939 val = left >= right;
1940 break;
1941 default:
1942 die("unknown op '%s'", arg->op.op);
1943 }
1944 break;
1945 case '=':
1946 if (arg->op.op[1] != '=')
1947 die("unknown op '%s'", arg->op.op);
1948 val = left == right;
1949 break;
1950 default:
1951 die("unknown op '%s'", arg->op.op);
1952 }
1953 break;
1954 default: /* not sure what to do there */
1955 return 0;
1956 }
1957 return val;
1958}
1959
1960struct flag {
1961 const char *name;
1962 unsigned long long value;
1963};
1964
1965static const struct flag flags[] = {
1966 { "HI_SOFTIRQ", 0 },
1967 { "TIMER_SOFTIRQ", 1 },
1968 { "NET_TX_SOFTIRQ", 2 },
1969 { "NET_RX_SOFTIRQ", 3 },
1970 { "BLOCK_SOFTIRQ", 4 },
1971 { "TASKLET_SOFTIRQ", 5 },
1972 { "SCHED_SOFTIRQ", 6 },
1973 { "HRTIMER_SOFTIRQ", 7 },
1974 { "RCU_SOFTIRQ", 8 },
1975
1976 { "HRTIMER_NORESTART", 0 },
1977 { "HRTIMER_RESTART", 1 },
1978};
1979
1980static unsigned long long eval_flag(const char *flag)
1981{
1982 int i;
1983
1984 /*
1985 * Some flags in the format files do not get converted.
1986 * If the flag is not numeric, see if it is something that
1987 * we already know about.
1988 */
1989 if (isdigit(flag[0]))
1990 return strtoull(flag, NULL, 0);
1991
1992 for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
1993 if (strcmp(flags[i].name, flag) == 0)
1994 return flags[i].value;
1995
1996 return 0;
1997}
1998
1999static void print_str_arg(void *data, int size,
2000 struct event *event, struct print_arg *arg)
2001{
2002 struct print_flag_sym *flag;
2003 unsigned long long val, fval;
2004 char *str;
2005 int print;
2006
2007 switch (arg->type) {
2008 case PRINT_NULL:
2009 /* ?? */
2010 return;
2011 case PRINT_ATOM:
2012 printf("%s", arg->atom.atom);
2013 return;
2014 case PRINT_FIELD:
2015 if (!arg->field.field) {
2016 arg->field.field = find_any_field(event, arg->field.name);
2017 if (!arg->field.field)
2018 die("field %s not found", arg->field.name);
2019 }
2020 str = malloc_or_die(arg->field.field->size + 1);
2021 memcpy(str, data + arg->field.field->offset,
2022 arg->field.field->size);
2023 str[arg->field.field->size] = 0;
2024 printf("%s", str);
2025 free(str);
2026 break;
2027 case PRINT_FLAGS:
2028 val = eval_num_arg(data, size, event, arg->flags.field);
2029 print = 0;
2030 for (flag = arg->flags.flags; flag; flag = flag->next) {
2031 fval = eval_flag(flag->value);
2032 if (!val && !fval) {
2033 printf("%s", flag->str);
2034 break;
2035 }
2036 if (fval && (val & fval) == fval) {
2037 if (print && arg->flags.delim)
2038 printf("%s", arg->flags.delim);
2039 printf("%s", flag->str);
2040 print = 1;
2041 val &= ~fval;
2042 }
2043 }
2044 break;
2045 case PRINT_SYMBOL:
2046 val = eval_num_arg(data, size, event, arg->symbol.field);
2047 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
2048 fval = eval_flag(flag->value);
2049 if (val == fval) {
2050 printf("%s", flag->str);
2051 break;
2052 }
2053 }
2054 break;
2055
2056 case PRINT_TYPE:
2057 break;
2058 case PRINT_STRING: {
2059 int str_offset;
2060
2061 if (arg->string.offset == -1) {
2062 struct format_field *f;
2063
2064 f = find_any_field(event, arg->string.string);
2065 arg->string.offset = f->offset;
2066 }
2067 str_offset = *(int *)(data + arg->string.offset);
2068 str_offset &= 0xffff;
2069 printf("%s", ((char *)data) + str_offset);
2070 break;
2071 }
2072 case PRINT_OP:
2073 /*
2074 * The only op for string should be ? :
2075 */
2076 if (arg->op.op[0] != '?')
2077 return;
2078 val = eval_num_arg(data, size, event, arg->op.left);
2079 if (val)
2080 print_str_arg(data, size, event, arg->op.right->op.left);
2081 else
2082 print_str_arg(data, size, event, arg->op.right->op.right);
2083 break;
2084 default:
2085 /* well... */
2086 break;
2087 }
2088}
2089
2090static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
2091{
2092 static struct format_field *field, *ip_field;
2093 struct print_arg *args, *arg, **next;
2094 unsigned long long ip, val;
2095 char *ptr;
2096 void *bptr;
2097
2098 if (!field) {
2099 field = find_field(event, "buf");
2100 if (!field)
2101 die("can't find buffer field for binary printk");
2102 ip_field = find_field(event, "ip");
2103 if (!ip_field)
2104 die("can't find ip field for binary printk");
2105 }
2106
2107 ip = read_size(data + ip_field->offset, ip_field->size);
2108
2109 /*
2110 * The first arg is the IP pointer.
2111 */
2112 args = malloc_or_die(sizeof(*args));
2113 arg = args;
2114 arg->next = NULL;
2115 next = &arg->next;
2116
2117 arg->type = PRINT_ATOM;
2118 arg->atom.atom = malloc_or_die(32);
2119 sprintf(arg->atom.atom, "%lld", ip);
2120
2121 /* skip the first "%pf : " */
2122 for (ptr = fmt + 6, bptr = data + field->offset;
2123 bptr < data + size && *ptr; ptr++) {
2124 int ls = 0;
2125
2126 if (*ptr == '%') {
2127 process_again:
2128 ptr++;
2129 switch (*ptr) {
2130 case '%':
2131 break;
2132 case 'l':
2133 ls++;
2134 goto process_again;
2135 case 'L':
2136 ls = 2;
2137 goto process_again;
2138 case '0' ... '9':
2139 goto process_again;
2140 case 'p':
2141 ls = 1;
2142 /* fall through */
2143 case 'd':
2144 case 'u':
2145 case 'x':
2146 case 'i':
2147 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) &
2148 ~(long_size - 1));
2149 switch (ls) {
2150 case 0:
2151 case 1:
2152 ls = long_size;
2153 break;
2154 case 2:
2155 ls = 8;
2156 default:
2157 break;
2158 }
2159 val = read_size(bptr, ls);
2160 bptr += ls;
2161 arg = malloc_or_die(sizeof(*arg));
2162 arg->next = NULL;
2163 arg->type = PRINT_ATOM;
2164 arg->atom.atom = malloc_or_die(32);
2165 sprintf(arg->atom.atom, "%lld", val);
2166 *next = arg;
2167 next = &arg->next;
2168 break;
2169 case 's':
2170 arg = malloc_or_die(sizeof(*arg));
2171 arg->next = NULL;
2172 arg->type = PRINT_STRING;
2173 arg->string.string = strdup(bptr);
2174 bptr += strlen(bptr) + 1;
2175 *next = arg;
2176 next = &arg->next;
2177 default:
2178 break;
2179 }
2180 }
2181 }
2182
2183 return args;
2184}
2185
2186static void free_args(struct print_arg *args)
2187{
2188 struct print_arg *next;
2189
2190 while (args) {
2191 next = args->next;
2192
2193 if (args->type == PRINT_ATOM)
2194 free(args->atom.atom);
2195 else
2196 free(args->string.string);
2197 free(args);
2198 args = next;
2199 }
2200}
2201
2202static char *get_bprint_format(void *data, int size __unused, struct event *event)
2203{
2204 unsigned long long addr;
2205 static struct format_field *field;
2206 struct printk_map *printk;
2207 char *format;
2208 char *p;
2209
2210 if (!field) {
2211 field = find_field(event, "fmt");
2212 if (!field)
2213 die("can't find format field for binary printk");
2214 printf("field->offset = %d size=%d\n", field->offset, field->size);
2215 }
2216
2217 addr = read_size(data + field->offset, field->size);
2218
2219 printk = find_printk(addr);
2220 if (!printk) {
2221 format = malloc_or_die(45);
2222 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
2223 addr);
2224 return format;
2225 }
2226
2227 p = printk->printk;
2228 /* Remove any quotes. */
2229 if (*p == '"')
2230 p++;
2231 format = malloc_or_die(strlen(p) + 10);
2232 sprintf(format, "%s : %s", "%pf", p);
2233 /* remove ending quotes and new line since we will add one too */
2234 p = format + strlen(format) - 1;
2235 if (*p == '"')
2236 *p = 0;
2237
2238 p -= 2;
2239 if (strcmp(p, "\\n") == 0)
2240 *p = 0;
2241
2242 return format;
2243}
2244
2245static void pretty_print(void *data, int size, struct event *event)
2246{
2247 struct print_fmt *print_fmt = &event->print_fmt;
2248 struct print_arg *arg = print_fmt->args;
2249 struct print_arg *args = NULL;
2250 const char *ptr = print_fmt->format;
2251 unsigned long long val;
2252 struct func_map *func;
2253 const char *saveptr;
2254 char *bprint_fmt = NULL;
2255 char format[32];
2256 int show_func;
2257 int len;
2258 int ls;
2259
2260 if (event->flags & EVENT_FL_ISFUNC)
2261 ptr = " %pF <-- %pF";
2262
2263 if (event->flags & EVENT_FL_ISBPRINT) {
2264 bprint_fmt = get_bprint_format(data, size, event);
2265 args = make_bprint_args(bprint_fmt, data, size, event);
2266 arg = args;
2267 ptr = bprint_fmt;
2268 }
2269
2270 for (; *ptr; ptr++) {
2271 ls = 0;
2272 if (*ptr == '%') {
2273 saveptr = ptr;
2274 show_func = 0;
2275 cont_process:
2276 ptr++;
2277 switch (*ptr) {
2278 case '%':
2279 printf("%%");
2280 break;
2281 case 'l':
2282 ls++;
2283 goto cont_process;
2284 case 'L':
2285 ls = 2;
2286 goto cont_process;
2287 case 'z':
2288 case 'Z':
2289 case '0' ... '9':
2290 goto cont_process;
2291 case 'p':
2292 if (long_size == 4)
2293 ls = 1;
2294 else
2295 ls = 2;
2296
2297 if (*(ptr+1) == 'F' ||
2298 *(ptr+1) == 'f') {
2299 ptr++;
2300 show_func = *ptr;
2301 }
2302
2303 /* fall through */
2304 case 'd':
2305 case 'i':
2306 case 'x':
2307 case 'X':
2308 case 'u':
2309 if (!arg)
2310 die("no argument match");
2311
2312 len = ((unsigned long)ptr + 1) -
2313 (unsigned long)saveptr;
2314
2315 /* should never happen */
2316 if (len > 32)
2317 die("bad format!");
2318
2319 memcpy(format, saveptr, len);
2320 format[len] = 0;
2321
2322 val = eval_num_arg(data, size, event, arg);
2323 arg = arg->next;
2324
2325 if (show_func) {
2326 func = find_func(val);
2327 if (func) {
2328 printf("%s", func->func);
2329 if (show_func == 'F')
2330 printf("+0x%llx",
2331 val - func->addr);
2332 break;
2333 }
2334 }
2335 switch (ls) {
2336 case 0:
2337 printf(format, (int)val);
2338 break;
2339 case 1:
2340 printf(format, (long)val);
2341 break;
2342 case 2:
2343 printf(format, (long long)val);
2344 break;
2345 default:
2346 die("bad count (%d)", ls);
2347 }
2348 break;
2349 case 's':
2350 if (!arg)
2351 die("no matching argument");
2352
2353 print_str_arg(data, size, event, arg);
2354 arg = arg->next;
2355 break;
2356 default:
2357 printf(">%c<", *ptr);
2358
2359 }
2360 } else
2361 printf("%c", *ptr);
2362 }
2363
2364 if (args) {
2365 free_args(args);
2366 free(bprint_fmt);
2367 }
2368}
2369
2370static inline int log10_cpu(int nb)
2371{
2372 if (nb / 100)
2373 return 3;
2374 if (nb / 10)
2375 return 2;
2376 return 1;
2377}
2378
2379/* taken from Linux, written by Frederic Weisbecker */
2380static void print_graph_cpu(int cpu)
2381{
2382 int i;
2383 int log10_this = log10_cpu(cpu);
2384 int log10_all = log10_cpu(cpus);
2385
2386
2387 /*
2388 * Start with a space character - to make it stand out
2389 * to the right a bit when trace output is pasted into
2390 * email:
2391 */
2392 printf(" ");
2393
2394 /*
2395 * Tricky - we space the CPU field according to the max
2396 * number of online CPUs. On a 2-cpu system it would take
2397 * a maximum of 1 digit - on a 128 cpu system it would
2398 * take up to 3 digits:
2399 */
2400 for (i = 0; i < log10_all - log10_this; i++)
2401 printf(" ");
2402
2403 printf("%d) ", cpu);
2404}
2405
2406#define TRACE_GRAPH_PROCINFO_LENGTH 14
2407#define TRACE_GRAPH_INDENT 2
2408
2409static void print_graph_proc(int pid, const char *comm)
2410{
2411 /* sign + log10(MAX_INT) + '\0' */
2412 char pid_str[11];
2413 int spaces = 0;
2414 int len;
2415 int i;
2416
2417 sprintf(pid_str, "%d", pid);
2418
2419 /* 1 stands for the "-" character */
2420 len = strlen(comm) + strlen(pid_str) + 1;
2421
2422 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
2423 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
2424
2425 /* First spaces to align center */
2426 for (i = 0; i < spaces / 2; i++)
2427 printf(" ");
2428
2429 printf("%s-%s", comm, pid_str);
2430
2431 /* Last spaces to align center */
2432 for (i = 0; i < spaces - (spaces / 2); i++)
2433 printf(" ");
2434}
2435
2436static struct record *
2437get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2438 struct record *next)
2439{
2440 struct format_field *field;
2441 struct event *event;
2442 unsigned long val;
2443 int type;
2444 int pid;
2445
2446 type = trace_parse_common_type(next->data);
2447 event = trace_find_event(type);
2448 if (!event)
2449 return NULL;
2450
2451 if (!(event->flags & EVENT_FL_ISFUNCRET))
2452 return NULL;
2453
2454 pid = parse_common_pid(next->data);
2455 field = find_field(event, "func");
2456 if (!field)
2457 die("function return does not have field func");
2458
2459 val = read_size(next->data + field->offset, field->size);
2460
2461 if (cur_pid != pid || cur_func != val)
2462 return NULL;
2463
2464 /* this is a leaf, now advance the iterator */
2465 return trace_read_data(cpu);
2466}
2467
2468/* Signal a overhead of time execution to the output */
2469static void print_graph_overhead(unsigned long long duration)
2470{
2471 /* Non nested entry or return */
2472 if (duration == ~0ULL)
2473 return (void)printf(" ");
2474
2475 /* Duration exceeded 100 msecs */
2476 if (duration > 100000ULL)
2477 return (void)printf("! ");
2478
2479 /* Duration exceeded 10 msecs */
2480 if (duration > 10000ULL)
2481 return (void)printf("+ ");
2482
2483 printf(" ");
2484}
2485
2486static void print_graph_duration(unsigned long long duration)
2487{
2488 unsigned long usecs = duration / 1000;
2489 unsigned long nsecs_rem = duration % 1000;
2490 /* log10(ULONG_MAX) + '\0' */
2491 char msecs_str[21];
2492 char nsecs_str[5];
2493 int len;
2494 int i;
2495
2496 sprintf(msecs_str, "%lu", usecs);
2497
2498 /* Print msecs */
2499 len = printf("%lu", usecs);
2500
2501 /* Print nsecs (we don't want to exceed 7 numbers) */
2502 if (len < 7) {
2503 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2504 len += printf(".%s", nsecs_str);
2505 }
2506
2507 printf(" us ");
2508
2509 /* Print remaining spaces to fit the row's width */
2510 for (i = len; i < 7; i++)
2511 printf(" ");
2512
2513 printf("| ");
2514}
2515
2516static void
2517print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2518{
2519 unsigned long long rettime, calltime;
2520 unsigned long long duration, depth;
2521 unsigned long long val;
2522 struct format_field *field;
2523 struct func_map *func;
2524 struct event *ret_event;
2525 int type;
2526 int i;
2527
2528 type = trace_parse_common_type(ret_rec->data);
2529 ret_event = trace_find_event(type);
2530
2531 field = find_field(ret_event, "rettime");
2532 if (!field)
2533 die("can't find rettime in return graph");
2534 rettime = read_size(ret_rec->data + field->offset, field->size);
2535
2536 field = find_field(ret_event, "calltime");
2537 if (!field)
2538 die("can't find rettime in return graph");
2539 calltime = read_size(ret_rec->data + field->offset, field->size);
2540
2541 duration = rettime - calltime;
2542
2543 /* Overhead */
2544 print_graph_overhead(duration);
2545
2546 /* Duration */
2547 print_graph_duration(duration);
2548
2549 field = find_field(event, "depth");
2550 if (!field)
2551 die("can't find depth in entry graph");
2552 depth = read_size(data + field->offset, field->size);
2553
2554 /* Function */
2555 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2556 printf(" ");
2557
2558 field = find_field(event, "func");
2559 if (!field)
2560 die("can't find func in entry graph");
2561 val = read_size(data + field->offset, field->size);
2562 func = find_func(val);
2563
2564 if (func)
2565 printf("%s();", func->func);
2566 else
2567 printf("%llx();", val);
2568}
2569
2570static void print_graph_nested(struct event *event, void *data)
2571{
2572 struct format_field *field;
2573 unsigned long long depth;
2574 unsigned long long val;
2575 struct func_map *func;
2576 int i;
2577
2578 /* No overhead */
2579 print_graph_overhead(-1);
2580
2581 /* No time */
2582 printf(" | ");
2583
2584 field = find_field(event, "depth");
2585 if (!field)
2586 die("can't find depth in entry graph");
2587 depth = read_size(data + field->offset, field->size);
2588
2589 /* Function */
2590 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2591 printf(" ");
2592
2593 field = find_field(event, "func");
2594 if (!field)
2595 die("can't find func in entry graph");
2596 val = read_size(data + field->offset, field->size);
2597 func = find_func(val);
2598
2599 if (func)
2600 printf("%s() {", func->func);
2601 else
2602 printf("%llx() {", val);
2603}
2604
2605static void
2606pretty_print_func_ent(void *data, int size, struct event *event,
2607 int cpu, int pid, const char *comm,
2608 unsigned long secs, unsigned long usecs)
2609{
2610 struct format_field *field;
2611 struct record *rec;
2612 void *copy_data;
2613 unsigned long val;
2614
2615 printf("%5lu.%06lu | ", secs, usecs);
2616
2617 print_graph_cpu(cpu);
2618 print_graph_proc(pid, comm);
2619
2620 printf(" | ");
2621
2622 field = find_field(event, "func");
2623 if (!field)
2624 die("function entry does not have func field");
2625
2626 val = read_size(data + field->offset, field->size);
2627
2628 /*
2629 * peek_data may unmap the data pointer. Copy it first.
2630 */
2631 copy_data = malloc_or_die(size);
2632 memcpy(copy_data, data, size);
2633 data = copy_data;
2634
2635 rec = trace_peek_data(cpu);
2636 if (rec) {
2637 rec = get_return_for_leaf(cpu, pid, val, rec);
2638 if (rec) {
2639 print_graph_entry_leaf(event, data, rec);
2640 goto out_free;
2641 }
2642 }
2643 print_graph_nested(event, data);
2644out_free:
2645 free(data);
2646}
2647
2648static void
2649pretty_print_func_ret(void *data, int size __unused, struct event *event,
2650 int cpu, int pid, const char *comm,
2651 unsigned long secs, unsigned long usecs)
2652{
2653 unsigned long long rettime, calltime;
2654 unsigned long long duration, depth;
2655 struct format_field *field;
2656 int i;
2657
2658 printf("%5lu.%06lu | ", secs, usecs);
2659
2660 print_graph_cpu(cpu);
2661 print_graph_proc(pid, comm);
2662
2663 printf(" | ");
2664
2665 field = find_field(event, "rettime");
2666 if (!field)
2667 die("can't find rettime in return graph");
2668 rettime = read_size(data + field->offset, field->size);
2669
2670 field = find_field(event, "calltime");
2671 if (!field)
2672 die("can't find calltime in return graph");
2673 calltime = read_size(data + field->offset, field->size);
2674
2675 duration = rettime - calltime;
2676
2677 /* Overhead */
2678 print_graph_overhead(duration);
2679
2680 /* Duration */
2681 print_graph_duration(duration);
2682
2683 field = find_field(event, "depth");
2684 if (!field)
2685 die("can't find depth in entry graph");
2686 depth = read_size(data + field->offset, field->size);
2687
2688 /* Function */
2689 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2690 printf(" ");
2691
2692 printf("}");
2693}
2694
2695static void
2696pretty_print_func_graph(void *data, int size, struct event *event,
2697 int cpu, int pid, const char *comm,
2698 unsigned long secs, unsigned long usecs)
2699{
2700 if (event->flags & EVENT_FL_ISFUNCENT)
2701 pretty_print_func_ent(data, size, event,
2702 cpu, pid, comm, secs, usecs);
2703 else if (event->flags & EVENT_FL_ISFUNCRET)
2704 pretty_print_func_ret(data, size, event,
2705 cpu, pid, comm, secs, usecs);
2706 printf("\n");
2707}
2708
2709void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2710 char *comm)
2711{
2712 struct event *event;
2713 unsigned long secs;
2714 unsigned long usecs;
2715 int type;
2716 int pid;
2717
2718 secs = nsecs / NSECS_PER_SEC;
2719 nsecs -= secs * NSECS_PER_SEC;
2720 usecs = nsecs / NSECS_PER_USEC;
2721
2722 type = trace_parse_common_type(data);
2723
2724 event = trace_find_event(type);
2725 if (!event) {
2726 printf("ug! no event found for type %d\n", type);
2727 return;
2728 }
2729
2730 pid = parse_common_pid(data);
2731
2732 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2733 return pretty_print_func_graph(data, size, event, cpu,
2734 pid, comm, secs, usecs);
2735
2736 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ",
2737 comm, pid, cpu,
2738 secs, nsecs, event->name);
2739
2740 pretty_print(data, size, event);
2741 printf("\n");
2742}
2743
2744static void print_fields(struct print_flag_sym *field)
2745{
2746 printf("{ %s, %s }", field->value, field->str);
2747 if (field->next) {
2748 printf(", ");
2749 print_fields(field->next);
2750 }
2751}
2752
2753static void print_args(struct print_arg *args)
2754{
2755 int print_paren = 1;
2756
2757 switch (args->type) {
2758 case PRINT_NULL:
2759 printf("null");
2760 break;
2761 case PRINT_ATOM:
2762 printf("%s", args->atom.atom);
2763 break;
2764 case PRINT_FIELD:
2765 printf("REC->%s", args->field.name);
2766 break;
2767 case PRINT_FLAGS:
2768 printf("__print_flags(");
2769 print_args(args->flags.field);
2770 printf(", %s, ", args->flags.delim);
2771 print_fields(args->flags.flags);
2772 printf(")");
2773 break;
2774 case PRINT_SYMBOL:
2775 printf("__print_symbolic(");
2776 print_args(args->symbol.field);
2777 printf(", ");
2778 print_fields(args->symbol.symbols);
2779 printf(")");
2780 break;
2781 case PRINT_STRING:
2782 printf("__get_str(%s)", args->string.string);
2783 break;
2784 case PRINT_TYPE:
2785 printf("(%s)", args->typecast.type);
2786 print_args(args->typecast.item);
2787 break;
2788 case PRINT_OP:
2789 if (strcmp(args->op.op, ":") == 0)
2790 print_paren = 0;
2791 if (print_paren)
2792 printf("(");
2793 print_args(args->op.left);
2794 printf(" %s ", args->op.op);
2795 print_args(args->op.right);
2796 if (print_paren)
2797 printf(")");
2798 break;
2799 default:
2800 /* we should warn... */
2801 return;
2802 }
2803 if (args->next) {
2804 printf("\n");
2805 print_args(args->next);
2806 }
2807}
2808
2809static void parse_header_field(char *type,
2810 int *offset, int *size)
2811{
2812 char *token;
2813
2814 if (read_expected(EVENT_ITEM, (char *)"field") < 0)
2815 return;
2816 if (read_expected(EVENT_OP, (char *)":") < 0)
2817 return;
2818 /* type */
2819 if (read_expect_type(EVENT_ITEM, &token) < 0)
2820 return;
2821 free_token(token);
2822
2823 if (read_expected(EVENT_ITEM, type) < 0)
2824 return;
2825 if (read_expected(EVENT_OP, (char *)";") < 0)
2826 return;
2827 if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
2828 return;
2829 if (read_expected(EVENT_OP, (char *)":") < 0)
2830 return;
2831 if (read_expect_type(EVENT_ITEM, &token) < 0)
2832 return;
2833 *offset = atoi(token);
2834 free_token(token);
2835 if (read_expected(EVENT_OP, (char *)";") < 0)
2836 return;
2837 if (read_expected(EVENT_ITEM, (char *)"size") < 0)
2838 return;
2839 if (read_expected(EVENT_OP, (char *)":") < 0)
2840 return;
2841 if (read_expect_type(EVENT_ITEM, &token) < 0)
2842 return;
2843 *size = atoi(token);
2844 free_token(token);
2845 if (read_expected(EVENT_OP, (char *)";") < 0)
2846 return;
2847 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2848 return;
2849 free_token(token);
2850}
2851
2852int parse_header_page(char *buf, unsigned long size)
2853{
2854 init_input_buf(buf, size);
2855
2856 parse_header_field((char *)"timestamp", &header_page_ts_offset,
2857 &header_page_ts_size);
2858 parse_header_field((char *)"commit", &header_page_size_offset,
2859 &header_page_size_size);
2860 parse_header_field((char *)"data", &header_page_data_offset,
2861 &header_page_data_size);
2862
2863 return 0;
2864}
2865
2866int parse_ftrace_file(char *buf, unsigned long size)
2867{
2868 struct format_field *field;
2869 struct print_arg *arg, **list;
2870 struct event *event;
2871 int ret;
2872
2873 init_input_buf(buf, size);
2874
2875 event = alloc_event();
2876 if (!event)
2877 return -ENOMEM;
2878
2879 event->flags |= EVENT_FL_ISFTRACE;
2880
2881 event->name = event_read_name();
2882 if (!event->name)
2883 die("failed to read ftrace event name");
2884
2885 if (strcmp(event->name, "function") == 0)
2886 event->flags |= EVENT_FL_ISFUNC;
2887
2888 else if (strcmp(event->name, "funcgraph_entry") == 0)
2889 event->flags |= EVENT_FL_ISFUNCENT;
2890
2891 else if (strcmp(event->name, "funcgraph_exit") == 0)
2892 event->flags |= EVENT_FL_ISFUNCRET;
2893
2894 else if (strcmp(event->name, "bprint") == 0)
2895 event->flags |= EVENT_FL_ISBPRINT;
2896
2897 event->id = event_read_id();
2898 if (event->id < 0)
2899 die("failed to read ftrace event id");
2900
2901 add_event(event);
2902
2903 ret = event_read_format(event);
2904 if (ret < 0)
2905 die("failed to read ftrace event format");
2906
2907 ret = event_read_print(event);
2908 if (ret < 0)
2909 die("failed to read ftrace event print fmt");
2910
2911 /*
2912 * The arguments for ftrace files are parsed by the fields.
2913 * Set up the fields as their arguments.
2914 */
2915 list = &event->print_fmt.args;
2916 for (field = event->format.fields; field; field = field->next) {
2917 arg = malloc_or_die(sizeof(*arg));
2918 memset(arg, 0, sizeof(*arg));
2919 *list = arg;
2920 list = &arg->next;
2921 arg->type = PRINT_FIELD;
2922 arg->field.name = field->name;
2923 arg->field.field = field;
2924 }
2925 return 0;
2926}
2927
2928int parse_event_file(char *buf, unsigned long size, char *system__unused __unused)
2929{
2930 struct event *event;
2931 int ret;
2932
2933 init_input_buf(buf, size);
2934
2935 event = alloc_event();
2936 if (!event)
2937 return -ENOMEM;
2938
2939 event->name = event_read_name();
2940 if (!event->name)
2941 die("failed to read event name");
2942
2943 event->id = event_read_id();
2944 if (event->id < 0)
2945 die("failed to read event id");
2946
2947 ret = event_read_format(event);
2948 if (ret < 0)
2949 die("failed to read event format");
2950
2951 ret = event_read_print(event);
2952 if (ret < 0)
2953 die("failed to read event print fmt");
2954
2955#define PRINT_ARGS 0
2956 if (PRINT_ARGS && event->print_fmt.args)
2957 print_args(event->print_fmt.args);
2958
2959 add_event(event);
2960 return 0;
2961}
2962
2963void parse_set_info(int nr_cpus, int long_sz)
2964{
2965 cpus = nr_cpus;
2966 long_size = long_sz;
2967}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
new file mode 100644
index 000000000000..1b5c847d2c22
--- /dev/null
+++ b/tools/perf/util/trace-event-read.c
@@ -0,0 +1,514 @@
1/*
2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _LARGEFILE64_SOURCE
22
23#include <dirent.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <getopt.h>
28#include <stdarg.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/wait.h>
32#include <sys/mman.h>
33#include <pthread.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <ctype.h>
37#include <errno.h>
38
39#include "../perf.h"
40#include "util.h"
41#include "trace-event.h"
42
43static int input_fd;
44
45static int read_page;
46
47int file_bigendian;
48int host_bigendian;
49static int long_size;
50
51static unsigned long page_size;
52
53static int read_or_die(void *data, int size)
54{
55 int r;
56
57 r = read(input_fd, data, size);
58 if (r != size)
59 die("reading input file (size expected=%d received=%d)",
60 size, r);
61 return r;
62}
63
64static unsigned int read4(void)
65{
66 unsigned int data;
67
68 read_or_die(&data, 4);
69 return __data2host4(data);
70}
71
72static unsigned long long read8(void)
73{
74 unsigned long long data;
75
76 read_or_die(&data, 8);
77 return __data2host8(data);
78}
79
80static char *read_string(void)
81{
82 char buf[BUFSIZ];
83 char *str = NULL;
84 int size = 0;
85 int i;
86 int r;
87
88 for (;;) {
89 r = read(input_fd, buf, BUFSIZ);
90 if (r < 0)
91 die("reading input file");
92
93 if (!r)
94 die("no data");
95
96 for (i = 0; i < r; i++) {
97 if (!buf[i])
98 break;
99 }
100 if (i < r)
101 break;
102
103 if (str) {
104 size += BUFSIZ;
105 str = realloc(str, size);
106 if (!str)
107 die("malloc of size %d", size);
108 memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
109 } else {
110 size = BUFSIZ;
111 str = malloc_or_die(size);
112 memcpy(str, buf, size);
113 }
114 }
115
116 /* trailing \0: */
117 i++;
118
119 /* move the file descriptor to the end of the string */
120 r = lseek(input_fd, -(r - i), SEEK_CUR);
121 if (r < 0)
122 die("lseek");
123
124 if (str) {
125 size += i;
126 str = realloc(str, size);
127 if (!str)
128 die("malloc of size %d", size);
129 memcpy(str + (size - i), buf, i);
130 } else {
131 size = i;
132 str = malloc_or_die(i);
133 memcpy(str, buf, i);
134 }
135
136 return str;
137}
138
139static void read_proc_kallsyms(void)
140{
141 unsigned int size;
142 char *buf;
143
144 size = read4();
145 if (!size)
146 return;
147
148 buf = malloc_or_die(size);
149 read_or_die(buf, size);
150
151 parse_proc_kallsyms(buf, size);
152
153 free(buf);
154}
155
156static void read_ftrace_printk(void)
157{
158 unsigned int size;
159 char *buf;
160
161 size = read4();
162 if (!size)
163 return;
164
165 buf = malloc_or_die(size);
166 read_or_die(buf, size);
167
168 parse_ftrace_printk(buf, size);
169
170 free(buf);
171}
172
173static void read_header_files(void)
174{
175 unsigned long long size;
176 char *header_page;
177 char *header_event;
178 char buf[BUFSIZ];
179
180 read_or_die(buf, 12);
181
182 if (memcmp(buf, "header_page", 12) != 0)
183 die("did not read header page");
184
185 size = read8();
186 header_page = malloc_or_die(size);
187 read_or_die(header_page, size);
188 parse_header_page(header_page, size);
189 free(header_page);
190
191 /*
192 * The size field in the page is of type long,
193 * use that instead, since it represents the kernel.
194 */
195 long_size = header_page_size_size;
196
197 read_or_die(buf, 13);
198 if (memcmp(buf, "header_event", 13) != 0)
199 die("did not read header event");
200
201 size = read8();
202 header_event = malloc_or_die(size);
203 read_or_die(header_event, size);
204 free(header_event);
205}
206
207static void read_ftrace_file(unsigned long long size)
208{
209 char *buf;
210
211 buf = malloc_or_die(size);
212 read_or_die(buf, size);
213 parse_ftrace_file(buf, size);
214 free(buf);
215}
216
217static void read_event_file(char *sys, unsigned long long size)
218{
219 char *buf;
220
221 buf = malloc_or_die(size);
222 read_or_die(buf, size);
223 parse_event_file(buf, size, sys);
224 free(buf);
225}
226
227static void read_ftrace_files(void)
228{
229 unsigned long long size;
230 int count;
231 int i;
232
233 count = read4();
234
235 for (i = 0; i < count; i++) {
236 size = read8();
237 read_ftrace_file(size);
238 }
239}
240
241static void read_event_files(void)
242{
243 unsigned long long size;
244 char *sys;
245 int systems;
246 int count;
247 int i,x;
248
249 systems = read4();
250
251 for (i = 0; i < systems; i++) {
252 sys = read_string();
253
254 count = read4();
255 for (x=0; x < count; x++) {
256 size = read8();
257 read_event_file(sys, size);
258 }
259 }
260}
261
262struct cpu_data {
263 unsigned long long offset;
264 unsigned long long size;
265 unsigned long long timestamp;
266 struct record *next;
267 char *page;
268 int cpu;
269 int index;
270 int page_size;
271};
272
273static struct cpu_data *cpu_data;
274
275static void update_cpu_data_index(int cpu)
276{
277 cpu_data[cpu].offset += page_size;
278 cpu_data[cpu].size -= page_size;
279 cpu_data[cpu].index = 0;
280}
281
282static void get_next_page(int cpu)
283{
284 off64_t save_seek;
285 off64_t ret;
286
287 if (!cpu_data[cpu].page)
288 return;
289
290 if (read_page) {
291 if (cpu_data[cpu].size <= page_size) {
292 free(cpu_data[cpu].page);
293 cpu_data[cpu].page = NULL;
294 return;
295 }
296
297 update_cpu_data_index(cpu);
298
299 /* other parts of the code may expect the pointer to not move */
300 save_seek = lseek64(input_fd, 0, SEEK_CUR);
301
302 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET);
303 if (ret < 0)
304 die("failed to lseek");
305 ret = read(input_fd, cpu_data[cpu].page, page_size);
306 if (ret < 0)
307 die("failed to read page");
308
309 /* reset the file pointer back */
310 lseek64(input_fd, save_seek, SEEK_SET);
311
312 return;
313 }
314
315 munmap(cpu_data[cpu].page, page_size);
316 cpu_data[cpu].page = NULL;
317
318 if (cpu_data[cpu].size <= page_size)
319 return;
320
321 update_cpu_data_index(cpu);
322
323 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
324 input_fd, cpu_data[cpu].offset);
325 if (cpu_data[cpu].page == MAP_FAILED)
326 die("failed to mmap cpu %d at offset 0x%llx",
327 cpu, cpu_data[cpu].offset);
328}
329
330static unsigned int type_len4host(unsigned int type_len_ts)
331{
332 if (file_bigendian)
333 return (type_len_ts >> 27) & ((1 << 5) - 1);
334 else
335 return type_len_ts & ((1 << 5) - 1);
336}
337
338static unsigned int ts4host(unsigned int type_len_ts)
339{
340 if (file_bigendian)
341 return type_len_ts & ((1 << 27) - 1);
342 else
343 return type_len_ts >> 5;
344}
345
346static int calc_index(void *ptr, int cpu)
347{
348 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
349}
350
351struct record *trace_peek_data(int cpu)
352{
353 struct record *data;
354 void *page = cpu_data[cpu].page;
355 int idx = cpu_data[cpu].index;
356 void *ptr = page + idx;
357 unsigned long long extend;
358 unsigned int type_len_ts;
359 unsigned int type_len;
360 unsigned int delta;
361 unsigned int length = 0;
362
363 if (cpu_data[cpu].next)
364 return cpu_data[cpu].next;
365
366 if (!page)
367 return NULL;
368
369 if (!idx) {
370 /* FIXME: handle header page */
371 if (header_page_ts_size != 8)
372 die("expected a long long type for timestamp");
373 cpu_data[cpu].timestamp = data2host8(ptr);
374 ptr += 8;
375 switch (header_page_size_size) {
376 case 4:
377 cpu_data[cpu].page_size = data2host4(ptr);
378 ptr += 4;
379 break;
380 case 8:
381 cpu_data[cpu].page_size = data2host8(ptr);
382 ptr += 8;
383 break;
384 default:
385 die("bad long size");
386 }
387 ptr = cpu_data[cpu].page + header_page_data_offset;
388 }
389
390read_again:
391 idx = calc_index(ptr, cpu);
392
393 if (idx >= cpu_data[cpu].page_size) {
394 get_next_page(cpu);
395 return trace_peek_data(cpu);
396 }
397
398 type_len_ts = data2host4(ptr);
399 ptr += 4;
400
401 type_len = type_len4host(type_len_ts);
402 delta = ts4host(type_len_ts);
403
404 switch (type_len) {
405 case RINGBUF_TYPE_PADDING:
406 if (!delta)
407 die("error, hit unexpected end of page");
408 length = data2host4(ptr);
409 ptr += 4;
410 length *= 4;
411 ptr += length;
412 goto read_again;
413
414 case RINGBUF_TYPE_TIME_EXTEND:
415 extend = data2host4(ptr);
416 ptr += 4;
417 extend <<= TS_SHIFT;
418 extend += delta;
419 cpu_data[cpu].timestamp += extend;
420 goto read_again;
421
422 case RINGBUF_TYPE_TIME_STAMP:
423 ptr += 12;
424 break;
425 case 0:
426 length = data2host4(ptr);
427 ptr += 4;
428 die("here! length=%d", length);
429 break;
430 default:
431 length = type_len * 4;
432 break;
433 }
434
435 cpu_data[cpu].timestamp += delta;
436
437 data = malloc_or_die(sizeof(*data));
438 memset(data, 0, sizeof(*data));
439
440 data->ts = cpu_data[cpu].timestamp;
441 data->size = length;
442 data->data = ptr;
443 ptr += length;
444
445 cpu_data[cpu].index = calc_index(ptr, cpu);
446 cpu_data[cpu].next = data;
447
448 return data;
449}
450
451struct record *trace_read_data(int cpu)
452{
453 struct record *data;
454
455 data = trace_peek_data(cpu);
456 cpu_data[cpu].next = NULL;
457
458 return data;
459}
460
461void trace_report(void)
462{
463 const char *input_file = "trace.info";
464 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 };
466 char *version;
467 int show_version = 0;
468 int show_funcs = 0;
469 int show_printk = 0;
470
471 input_fd = open(input_file, O_RDONLY);
472 if (input_fd < 0)
473 die("opening '%s'\n", input_file);
474
475 read_or_die(buf, 3);
476 if (memcmp(buf, test, 3) != 0)
477 die("not an trace data file");
478
479 read_or_die(buf, 7);
480 if (memcmp(buf, "tracing", 7) != 0)
481 die("not a trace file (missing tracing)");
482
483 version = read_string();
484 if (show_version)
485 printf("version = %s\n", version);
486 free(version);
487
488 read_or_die(buf, 1);
489 file_bigendian = buf[0];
490 host_bigendian = bigendian();
491
492 read_or_die(buf, 1);
493 long_size = buf[0];
494
495 page_size = read4();
496
497 read_header_files();
498
499 read_ftrace_files();
500 read_event_files();
501 read_proc_kallsyms();
502 read_ftrace_printk();
503
504 if (show_funcs) {
505 print_funcs();
506 return;
507 }
508 if (show_printk) {
509 print_printk();
510 return;
511 }
512
513 return;
514}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
new file mode 100644
index 000000000000..693f815c9429
--- /dev/null
+++ b/tools/perf/util/trace-event.h
@@ -0,0 +1,245 @@
1#ifndef _TRACE_EVENTS_H
2#define _TRACE_EVENTS_H
3
4#include "parse-events.h"
5
6#define __unused __attribute__((unused))
7
8
9#ifndef PAGE_MASK
10#define PAGE_MASK (page_size - 1)
11#endif
12
13enum {
14 RINGBUF_TYPE_PADDING = 29,
15 RINGBUF_TYPE_TIME_EXTEND = 30,
16 RINGBUF_TYPE_TIME_STAMP = 31,
17};
18
19#ifndef TS_SHIFT
20#define TS_SHIFT 27
21#endif
22
23#define NSECS_PER_SEC 1000000000ULL
24#define NSECS_PER_USEC 1000ULL
25
26enum format_flags {
27 FIELD_IS_ARRAY = 1,
28 FIELD_IS_POINTER = 2,
29};
30
31struct format_field {
32 struct format_field *next;
33 char *type;
34 char *name;
35 int offset;
36 int size;
37 unsigned long flags;
38};
39
40struct format {
41 int nr_common;
42 int nr_fields;
43 struct format_field *common_fields;
44 struct format_field *fields;
45};
46
47struct print_arg_atom {
48 char *atom;
49};
50
51struct print_arg_string {
52 char *string;
53 int offset;
54};
55
56struct print_arg_field {
57 char *name;
58 struct format_field *field;
59};
60
61struct print_flag_sym {
62 struct print_flag_sym *next;
63 char *value;
64 char *str;
65};
66
67struct print_arg_typecast {
68 char *type;
69 struct print_arg *item;
70};
71
72struct print_arg_flags {
73 struct print_arg *field;
74 char *delim;
75 struct print_flag_sym *flags;
76};
77
78struct print_arg_symbol {
79 struct print_arg *field;
80 struct print_flag_sym *symbols;
81};
82
83struct print_arg;
84
85struct print_arg_op {
86 char *op;
87 int prio;
88 struct print_arg *left;
89 struct print_arg *right;
90};
91
92struct print_arg_func {
93 char *name;
94 struct print_arg *args;
95};
96
97enum print_arg_type {
98 PRINT_NULL,
99 PRINT_ATOM,
100 PRINT_FIELD,
101 PRINT_FLAGS,
102 PRINT_SYMBOL,
103 PRINT_TYPE,
104 PRINT_STRING,
105 PRINT_OP,
106};
107
108struct print_arg {
109 struct print_arg *next;
110 enum print_arg_type type;
111 union {
112 struct print_arg_atom atom;
113 struct print_arg_field field;
114 struct print_arg_typecast typecast;
115 struct print_arg_flags flags;
116 struct print_arg_symbol symbol;
117 struct print_arg_func func;
118 struct print_arg_string string;
119 struct print_arg_op op;
120 };
121};
122
123struct print_fmt {
124 char *format;
125 struct print_arg *args;
126};
127
128struct event {
129 struct event *next;
130 char *name;
131 int id;
132 int flags;
133 struct format format;
134 struct print_fmt print_fmt;
135};
136
137enum {
138 EVENT_FL_ISFTRACE = 1,
139 EVENT_FL_ISPRINT = 2,
140 EVENT_FL_ISBPRINT = 4,
141 EVENT_FL_ISFUNC = 8,
142 EVENT_FL_ISFUNCENT = 16,
143 EVENT_FL_ISFUNCRET = 32,
144};
145
146struct record {
147 unsigned long long ts;
148 int size;
149 void *data;
150};
151
152struct record *trace_peek_data(int cpu);
153struct record *trace_read_data(int cpu);
154
155void parse_set_info(int nr_cpus, int long_sz);
156
157void trace_report(void);
158
159void *malloc_or_die(unsigned int size);
160
161void parse_cmdlines(char *file, int size);
162void parse_proc_kallsyms(char *file, unsigned int size);
163void parse_ftrace_printk(char *file, unsigned int size);
164
165void print_funcs(void);
166void print_printk(void);
167
168int parse_ftrace_file(char *buf, unsigned long size);
169int parse_event_file(char *buf, unsigned long size, char *system);
170void print_event(int cpu, void *data, int size, unsigned long long nsecs,
171 char *comm);
172
173extern int file_bigendian;
174extern int host_bigendian;
175
176int bigendian(void);
177
178static inline unsigned short __data2host2(unsigned short data)
179{
180 unsigned short swap;
181
182 if (host_bigendian == file_bigendian)
183 return data;
184
185 swap = ((data & 0xffULL) << 8) |
186 ((data & (0xffULL << 8)) >> 8);
187
188 return swap;
189}
190
191static inline unsigned int __data2host4(unsigned int data)
192{
193 unsigned int swap;
194
195 if (host_bigendian == file_bigendian)
196 return data;
197
198 swap = ((data & 0xffULL) << 24) |
199 ((data & (0xffULL << 8)) << 8) |
200 ((data & (0xffULL << 16)) >> 8) |
201 ((data & (0xffULL << 24)) >> 24);
202
203 return swap;
204}
205
206static inline unsigned long long __data2host8(unsigned long long data)
207{
208 unsigned long long swap;
209
210 if (host_bigendian == file_bigendian)
211 return data;
212
213 swap = ((data & 0xffULL) << 56) |
214 ((data & (0xffULL << 8)) << 40) |
215 ((data & (0xffULL << 16)) << 24) |
216 ((data & (0xffULL << 24)) << 8) |
217 ((data & (0xffULL << 32)) >> 8) |
218 ((data & (0xffULL << 40)) >> 24) |
219 ((data & (0xffULL << 48)) >> 40) |
220 ((data & (0xffULL << 56)) >> 56);
221
222 return swap;
223}
224
225#define data2host2(ptr) __data2host2(*(unsigned short *)ptr)
226#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
227#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr)
228
229extern int header_page_ts_offset;
230extern int header_page_ts_size;
231extern int header_page_size_offset;
232extern int header_page_size_size;
233extern int header_page_data_offset;
234extern int header_page_data_size;
235
236int parse_header_page(char *buf, unsigned long size);
237int trace_parse_common_type(void *data);
238struct event *trace_find_event(int id);
239unsigned long long
240raw_field_value(struct event *event, const char *name, void *data);
241void *raw_field_ptr(struct event *event, const char *name, void *data);
242
243void read_tracing_data(struct perf_event_attr *pattrs, int nb_events);
244
245#endif /* _TRACE_EVENTS_H */
diff --git a/tools/perf/types.h b/tools/perf/util/types.h
index 5e75f9005940..5e75f9005940 100644
--- a/tools/perf/types.h
+++ b/tools/perf/util/types.h
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b8cfed776d81..9de2329dd44d 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -39,10 +39,6 @@
39/* Approximation of the length of the decimal representation of this type. */ 39/* Approximation of the length of the decimal representation of this type. */
40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) 40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
41 41
42#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX)
43#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
44#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
45#endif
46#define _ALL_SOURCE 1 42#define _ALL_SOURCE 1
47#define _GNU_SOURCE 1 43#define _GNU_SOURCE 1
48#define _BSD_SOURCE 1 44#define _BSD_SOURCE 1
@@ -50,6 +46,7 @@
50#include <unistd.h> 46#include <unistd.h>
51#include <stdio.h> 47#include <stdio.h>
52#include <sys/stat.h> 48#include <sys/stat.h>
49#include <sys/statfs.h>
53#include <fcntl.h> 50#include <fcntl.h>
54#include <stddef.h> 51#include <stddef.h>
55#include <stdlib.h> 52#include <stdlib.h>
@@ -67,7 +64,6 @@
67#include <assert.h> 64#include <assert.h>
68#include <regex.h> 65#include <regex.h>
69#include <utime.h> 66#include <utime.h>
70#ifndef __MINGW32__
71#include <sys/wait.h> 67#include <sys/wait.h>
72#include <sys/poll.h> 68#include <sys/poll.h>
73#include <sys/socket.h> 69#include <sys/socket.h>
@@ -81,20 +77,8 @@
81#include <netdb.h> 77#include <netdb.h>
82#include <pwd.h> 78#include <pwd.h>
83#include <inttypes.h> 79#include <inttypes.h>
84#if defined(__CYGWIN__) 80#include "../../../include/linux/magic.h"
85#undef _XOPEN_SOURCE 81
86#include <grp.h>
87#define _XOPEN_SOURCE 600
88#include "compat/cygwin.h"
89#else
90#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
91#include <grp.h>
92#define _ALL_SOURCE 1
93#endif
94#else /* __MINGW32__ */
95/* pull in Windows compatibility stuff */
96#include "compat/mingw.h"
97#endif /* __MINGW32__ */
98 82
99#ifndef NO_ICONV 83#ifndef NO_ICONV
100#include <iconv.h> 84#include <iconv.h>
@@ -323,6 +307,7 @@ static inline int has_extension(const char *filename, const char *ext)
323#undef isspace 307#undef isspace
324#undef isdigit 308#undef isdigit
325#undef isalpha 309#undef isalpha
310#undef isprint
326#undef isalnum 311#undef isalnum
327#undef tolower 312#undef tolower
328#undef toupper 313#undef toupper
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
new file mode 100644
index 000000000000..1c15e39f99e3
--- /dev/null
+++ b/tools/perf/util/values.c
@@ -0,0 +1,230 @@
1#include <stdlib.h>
2
3#include "util.h"
4#include "values.h"
5
6void perf_read_values_init(struct perf_read_values *values)
7{
8 values->threads_max = 16;
9 values->pid = malloc(values->threads_max * sizeof(*values->pid));
10 values->tid = malloc(values->threads_max * sizeof(*values->tid));
11 values->value = malloc(values->threads_max * sizeof(*values->value));
12 if (!values->pid || !values->tid || !values->value)
13 die("failed to allocate read_values threads arrays");
14 values->threads = 0;
15
16 values->counters_max = 16;
17 values->counterrawid = malloc(values->counters_max
18 * sizeof(*values->counterrawid));
19 values->countername = malloc(values->counters_max
20 * sizeof(*values->countername));
21 if (!values->counterrawid || !values->countername)
22 die("failed to allocate read_values counters arrays");
23 values->counters = 0;
24}
25
26void perf_read_values_destroy(struct perf_read_values *values)
27{
28 int i;
29
30 if (!values->threads_max || !values->counters_max)
31 return;
32
33 for (i = 0; i < values->threads; i++)
34 free(values->value[i]);
35 free(values->pid);
36 free(values->tid);
37 free(values->counterrawid);
38 for (i = 0; i < values->counters; i++)
39 free(values->countername[i]);
40 free(values->countername);
41}
42
43static void perf_read_values__enlarge_threads(struct perf_read_values *values)
44{
45 values->threads_max *= 2;
46 values->pid = realloc(values->pid,
47 values->threads_max * sizeof(*values->pid));
48 values->tid = realloc(values->tid,
49 values->threads_max * sizeof(*values->tid));
50 values->value = realloc(values->value,
51 values->threads_max * sizeof(*values->value));
52 if (!values->pid || !values->tid || !values->value)
53 die("failed to enlarge read_values threads arrays");
54}
55
56static int perf_read_values__findnew_thread(struct perf_read_values *values,
57 u32 pid, u32 tid)
58{
59 int i;
60
61 for (i = 0; i < values->threads; i++)
62 if (values->pid[i] == pid && values->tid[i] == tid)
63 return i;
64
65 if (values->threads == values->threads_max)
66 perf_read_values__enlarge_threads(values);
67
68 i = values->threads++;
69 values->pid[i] = pid;
70 values->tid[i] = tid;
71 values->value[i] = malloc(values->counters_max * sizeof(**values->value));
72 if (!values->value[i])
73 die("failed to allocate read_values counters array");
74
75 return i;
76}
77
78static void perf_read_values__enlarge_counters(struct perf_read_values *values)
79{
80 int i;
81
82 values->counters_max *= 2;
83 values->counterrawid = realloc(values->counterrawid,
84 values->counters_max * sizeof(*values->counterrawid));
85 values->countername = realloc(values->countername,
86 values->counters_max * sizeof(*values->countername));
87 if (!values->counterrawid || !values->countername)
88 die("failed to enlarge read_values counters arrays");
89
90 for (i = 0; i < values->threads; i++) {
91 values->value[i] = realloc(values->value[i],
92 values->counters_max * sizeof(**values->value));
93 if (!values->value[i])
94 die("failed to enlarge read_values counters arrays");
95 }
96}
97
98static int perf_read_values__findnew_counter(struct perf_read_values *values,
99 u64 rawid, const char *name)
100{
101 int i;
102
103 for (i = 0; i < values->counters; i++)
104 if (values->counterrawid[i] == rawid)
105 return i;
106
107 if (values->counters == values->counters_max)
108 perf_read_values__enlarge_counters(values);
109
110 i = values->counters++;
111 values->counterrawid[i] = rawid;
112 values->countername[i] = strdup(name);
113
114 return i;
115}
116
117void perf_read_values_add_value(struct perf_read_values *values,
118 u32 pid, u32 tid,
119 u64 rawid, const char *name, u64 value)
120{
121 int tindex, cindex;
122
123 tindex = perf_read_values__findnew_thread(values, pid, tid);
124 cindex = perf_read_values__findnew_counter(values, rawid, name);
125
126 values->value[tindex][cindex] = value;
127}
128
129static void perf_read_values__display_pretty(FILE *fp,
130 struct perf_read_values *values)
131{
132 int i, j;
133 int pidwidth, tidwidth;
134 int *counterwidth;
135
136 counterwidth = malloc(values->counters * sizeof(*counterwidth));
137 if (!counterwidth)
138 die("failed to allocate counterwidth array");
139 tidwidth = 3;
140 pidwidth = 3;
141 for (j = 0; j < values->counters; j++)
142 counterwidth[j] = strlen(values->countername[j]);
143 for (i = 0; i < values->threads; i++) {
144 int width;
145
146 width = snprintf(NULL, 0, "%d", values->pid[i]);
147 if (width > pidwidth)
148 pidwidth = width;
149 width = snprintf(NULL, 0, "%d", values->tid[i]);
150 if (width > tidwidth)
151 tidwidth = width;
152 for (j = 0; j < values->counters; j++) {
153 width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
154 if (width > counterwidth[j])
155 counterwidth[j] = width;
156 }
157 }
158
159 fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID");
160 for (j = 0; j < values->counters; j++)
161 fprintf(fp, " %*s", counterwidth[j], values->countername[j]);
162 fprintf(fp, "\n");
163
164 for (i = 0; i < values->threads; i++) {
165 fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
166 tidwidth, values->tid[i]);
167 for (j = 0; j < values->counters; j++)
168 fprintf(fp, " %*Lu",
169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n");
171 }
172}
173
174static void perf_read_values__display_raw(FILE *fp,
175 struct perf_read_values *values)
176{
177 int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth;
178 int i, j;
179
180 tidwidth = 3; /* TID */
181 pidwidth = 3; /* PID */
182 namewidth = 4; /* "Name" */
183 rawwidth = 3; /* "Raw" */
184 countwidth = 5; /* "Count" */
185
186 for (i = 0; i < values->threads; i++) {
187 width = snprintf(NULL, 0, "%d", values->pid[i]);
188 if (width > pidwidth)
189 pidwidth = width;
190 width = snprintf(NULL, 0, "%d", values->tid[i]);
191 if (width > tidwidth)
192 tidwidth = width;
193 }
194 for (j = 0; j < values->counters; j++) {
195 width = strlen(values->countername[j]);
196 if (width > namewidth)
197 namewidth = width;
198 width = snprintf(NULL, 0, "%llx", values->counterrawid[j]);
199 if (width > rawwidth)
200 rawwidth = width;
201 }
202 for (i = 0; i < values->threads; i++) {
203 for (j = 0; j < values->counters; j++) {
204 width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
205 if (width > countwidth)
206 countwidth = width;
207 }
208 }
209
210 fprintf(fp, "# %*s %*s %*s %*s %*s\n",
211 pidwidth, "PID", tidwidth, "TID",
212 namewidth, "Name", rawwidth, "Raw",
213 countwidth, "Count");
214 for (i = 0; i < values->threads; i++)
215 for (j = 0; j < values->counters; j++)
216 fprintf(fp, " %*d %*d %*s %*llx %*Lu\n",
217 pidwidth, values->pid[i],
218 tidwidth, values->tid[i],
219 namewidth, values->countername[j],
220 rawwidth, values->counterrawid[j],
221 countwidth, values->value[i][j]);
222}
223
224void perf_read_values_display(FILE *fp, struct perf_read_values *values, int raw)
225{
226 if (raw)
227 perf_read_values__display_raw(fp, values);
228 else
229 perf_read_values__display_pretty(fp, values);
230}
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
new file mode 100644
index 000000000000..cadf8cf2a590
--- /dev/null
+++ b/tools/perf/util/values.h
@@ -0,0 +1,27 @@
1#ifndef _PERF_VALUES_H
2#define _PERF_VALUES_H
3
4#include "types.h"
5
6struct perf_read_values {
7 int threads;
8 int threads_max;
9 u32 *pid, *tid;
10 int counters;
11 int counters_max;
12 u64 *counterrawid;
13 char **countername;
14 u64 **value;
15};
16
17void perf_read_values_init(struct perf_read_values *values);
18void perf_read_values_destroy(struct perf_read_values *values);
19
20void perf_read_values_add_value(struct perf_read_values *values,
21 u32 pid, u32 tid,
22 u64 rawid, const char *name, u64 value);
23
24void perf_read_values_display(FILE *fp, struct perf_read_values *values,
25 int raw);
26
27#endif /* _PERF_VALUES_H */
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 6350d65f6d9e..4574ac28396f 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -7,7 +7,7 @@
7 * There's no pack memory to release - but stay close to the Git 7 * There's no pack memory to release - but stay close to the Git
8 * version so wrap this away: 8 * version so wrap this away:
9 */ 9 */
10static inline void release_pack_memory(size_t size, int flag) 10static inline void release_pack_memory(size_t size __used, int flag __used)
11{ 11{
12} 12}
13 13
@@ -59,7 +59,8 @@ void *xmemdupz(const void *data, size_t len)
59char *xstrndup(const char *str, size_t len) 59char *xstrndup(const char *str, size_t len)
60{ 60{
61 char *p = memchr(str, '\0', len); 61 char *p = memchr(str, '\0', len);
62 return xmemdupz(str, p ? p - str : len); 62
63 return xmemdupz(str, p ? (size_t)(p - str) : len);
63} 64}
64 65
65void *xrealloc(void *ptr, size_t size) 66void *xrealloc(void *ptr, size_t size)