aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-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-stat.txt6
-rw-r--r--tools/perf/Documentation/perf-top.txt112
-rw-r--r--tools/perf/Makefile103
-rw-r--r--tools/perf/builtin-annotate.c565
-rw-r--r--tools/perf/builtin-help.c7
-rw-r--r--tools/perf/builtin-list.c5
-rw-r--r--tools/perf/builtin-record.c272
-rw-r--r--tools/perf/builtin-report.c1411
-rw-r--r--tools/perf/builtin-stat.c426
-rw-r--r--tools/perf/builtin-top.c684
-rw-r--r--tools/perf/builtin-trace.c297
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/perf.c83
-rw-r--r--tools/perf/perf.h35
-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.h96
-rw-r--r--tools/perf/util/exec_cmd.c6
-rw-r--r--tools/perf/util/header.c280
-rw-r--r--tools/perf/util/header.h41
-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.c509
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/pager.c5
-rw-r--r--tools/perf/util/parse-events.c639
-rw-r--r--tools/perf/util/parse-events.h21
-rw-r--r--tools/perf/util/parse-options.c27
-rw-r--r--tools/perf/util/parse-options.h27
-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/symbol.c596
-rw-r--r--tools/perf/util/symbol.h55
-rw-r--r--tools/perf/util/thread.c175
-rw-r--r--tools/perf/util/thread.h21
-rw-r--r--tools/perf/util/trace-event-info.c539
-rw-r--r--tools/perf/util/trace-event-parse.c2942
-rw-r--r--tools/perf/util/trace-event-read.c512
-rw-r--r--tools/perf/util/trace-event.h240
-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
76 files changed, 10654 insertions, 3208 deletions
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-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-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/Makefile b/tools/perf/Makefile
index 36d7eef49913..9f8d207a91bf 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
@@ -289,10 +319,11 @@ export PERL_PATH
289LIB_FILE=libperf.a 319LIB_FILE=libperf.a
290 320
291LIB_H += ../../include/linux/perf_counter.h 321LIB_H += ../../include/linux/perf_counter.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,12 +356,23 @@ 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
331 376
332BUILTIN_OBJS += builtin-annotate.o 377BUILTIN_OBJS += builtin-annotate.o
333BUILTIN_OBJS += builtin-help.o 378BUILTIN_OBJS += builtin-help.o
@@ -336,9 +381,9 @@ BUILTIN_OBJS += builtin-record.o
336BUILTIN_OBJS += builtin-report.o 381BUILTIN_OBJS += builtin-report.o
337BUILTIN_OBJS += builtin-stat.o 382BUILTIN_OBJS += builtin-stat.o
338BUILTIN_OBJS += builtin-top.o 383BUILTIN_OBJS += builtin-top.o
384BUILTIN_OBJS += builtin-trace.o
339 385
340PERFLIBS = $(LIB_FILE) 386PERFLIBS = $(LIB_FILE)
341EXTLIBS =
342 387
343# 388#
344# Platform specific tweaks 389# Platform specific tweaks
@@ -367,6 +412,39 @@ ifeq ($(uname_S),Darwin)
367 PTHREAD_LIBS = 412 PTHREAD_LIBS =
368endif 413endif
369 414
415ifneq ($(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)
416 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
417endif
418
419ifdef NO_DEMANGLE
420 BASIC_CFLAGS += -DNO_DEMANGLE
421else
422 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")
423
424 ifeq ($(has_bfd),y)
425 EXTLIBS += -lbfd
426 else
427 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")
428 ifeq ($(has_bfd_iberty),y)
429 EXTLIBS += -lbfd -liberty
430 else
431 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")
432 ifeq ($(has_bfd_iberty_z),y)
433 EXTLIBS += -lbfd -liberty -lz
434 else
435 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")
436 ifeq ($(has_cplus_demangle),y)
437 EXTLIBS += -liberty
438 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
439 else
440 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling)
441 BASIC_CFLAGS += -DNO_DEMANGLE
442 endif
443 endif
444 endif
445 endif
446endif
447
370ifndef CC_LD_DYNPATH 448ifndef CC_LD_DYNPATH
371 ifdef NO_R_TO_GCC_LINKER 449 ifdef NO_R_TO_GCC_LINKER
372 # Some gcc does not accept and pass -R to the linker to specify 450 # Some gcc does not accept and pass -R to the linker to specify
@@ -377,12 +455,6 @@ ifndef CC_LD_DYNPATH
377 endif 455 endif
378endif 456endif
379 457
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 458ifdef NEEDS_SOCKET
387 EXTLIBS += -lsocket 459 EXTLIBS += -lsocket
388endif 460endif
@@ -693,6 +765,9 @@ builtin-init-db.o: builtin-init-db.c PERF-CFLAGS
693util/config.o: util/config.c PERF-CFLAGS 765util/config.o: util/config.c PERF-CFLAGS
694 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 766 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
695 767
768util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
769 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
770
696perf-%$X: %.o $(PERFLIBS) 771perf-%$X: %.o $(PERFLIBS)
697 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 772 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
698 773
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 7e58e3ad1508..043d85b7e254 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",
@@ -885,7 +511,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
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_EVENT_MISC_USER) {
891 517
@@ -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_EVENT_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_EVENT_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_EVENT_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_EVENT_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_EVENT_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_EVENT_FORK, skipping event.\n");
993 return -1; 631 return -1;
994 } 632 }
995 total_fork++; 633 total_fork++;
@@ -998,25 +636,12 @@ 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) {
642 case PERF_EVENT_SAMPLE:
643 return process_sample_event(event, offset, head);
644
1020 case PERF_EVENT_MMAP: 645 case PERF_EVENT_MMAP:
1021 return process_mmap_event(event, offset, head); 646 return process_mmap_event(event, offset, head);
1022 647
@@ -1025,9 +650,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1025 650
1026 case PERF_EVENT_FORK: 651 case PERF_EVENT_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 */
@@ -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..99a12fe86e9f 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,17 @@ 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;
42 51
43static long samples; 52static long samples;
44static struct timeval last_read; 53static struct timeval last_read;
@@ -52,25 +61,8 @@ static int nr_poll;
52static int nr_cpu; 61static int nr_cpu;
53 62
54static int file_new = 1; 63static 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 64
65struct perf_header *header;
74 66
75struct mmap_data { 67struct mmap_data {
76 int counter; 68 int counter;
@@ -197,46 +189,48 @@ static void sig_atexit(void)
197 kill(getpid(), signr); 189 kill(getpid(), signr);
198} 190}
199 191
200static void pid_synthesize_comm_event(pid_t pid, int full) 192static pid_t pid_synthesize_comm_event(pid_t pid, int full)
201{ 193{
202 struct comm_event comm_ev; 194 struct comm_event comm_ev;
203 char filename[PATH_MAX]; 195 char filename[PATH_MAX];
204 char bf[BUFSIZ]; 196 char bf[BUFSIZ];
205 int fd; 197 FILE *fp;
206 size_t size; 198 size_t size = 0;
207 char *field, *sep;
208 DIR *tasks; 199 DIR *tasks;
209 struct dirent dirent, *next; 200 struct dirent dirent, *next;
201 pid_t tgid = 0;
210 202
211 snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); 203 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
212 204
213 fd = open(filename, O_RDONLY); 205 fp = fopen(filename, "r");
214 if (fd < 0) { 206 if (fp == NULL) {
215 /* 207 /*
216 * We raced with a task exiting - just return: 208 * We raced with a task exiting - just return:
217 */ 209 */
218 if (verbose) 210 if (verbose)
219 fprintf(stderr, "couldn't open %s\n", filename); 211 fprintf(stderr, "couldn't open %s\n", filename);
220 return; 212 return 0;
221 }
222 if (read(fd, bf, sizeof(bf)) < 0) {
223 fprintf(stderr, "couldn't read %s\n", filename);
224 exit(EXIT_FAILURE);
225 } 213 }
226 close(fd);
227 214
228 /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */
229 memset(&comm_ev, 0, sizeof(comm_ev)); 215 memset(&comm_ev, 0, sizeof(comm_ev));
230 field = strchr(bf, '('); 216 while (!comm_ev.comm[0] || !comm_ev.pid) {
231 if (field == NULL) 217 if (fgets(bf, sizeof(bf), fp) == NULL)
232 goto out_failure; 218 goto out_failure;
233 sep = strchr(++field, ')'); 219
234 if (sep == NULL) 220 if (memcmp(bf, "Name:", 5) == 0) {
235 goto out_failure; 221 char *name = bf + 5;
236 size = sep - field; 222 while (*name && isspace(*name))
237 memcpy(comm_ev.comm, field, size++); 223 ++name;
238 224 size = strlen(name) - 1;
239 comm_ev.pid = pid; 225 memcpy(comm_ev.comm, name, size++);
226 } else if (memcmp(bf, "Tgid:", 5) == 0) {
227 char *tgids = bf + 5;
228 while (*tgids && isspace(*tgids))
229 ++tgids;
230 tgid = comm_ev.pid = atoi(tgids);
231 }
232 }
233
240 comm_ev.header.type = PERF_EVENT_COMM; 234 comm_ev.header.type = PERF_EVENT_COMM;
241 size = ALIGN(size, sizeof(u64)); 235 size = ALIGN(size, sizeof(u64));
242 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); 236 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
@@ -245,7 +239,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
245 comm_ev.tid = pid; 239 comm_ev.tid = pid;
246 240
247 write_output(&comm_ev, comm_ev.header.size); 241 write_output(&comm_ev, comm_ev.header.size);
248 return; 242 goto out_fclose;
249 } 243 }
250 244
251 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 245 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
@@ -262,7 +256,10 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
262 write_output(&comm_ev, comm_ev.header.size); 256 write_output(&comm_ev, comm_ev.header.size);
263 } 257 }
264 closedir(tasks); 258 closedir(tasks);
265 return; 259
260out_fclose:
261 fclose(fp);
262 return tgid;
266 263
267out_failure: 264out_failure:
268 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", 265 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
@@ -270,7 +267,7 @@ out_failure:
270 exit(EXIT_FAILURE); 267 exit(EXIT_FAILURE);
271} 268}
272 269
273static void pid_synthesize_mmap_samples(pid_t pid) 270static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
274{ 271{
275 char filename[PATH_MAX]; 272 char filename[PATH_MAX];
276 FILE *fp; 273 FILE *fp;
@@ -289,7 +286,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
289 while (1) { 286 while (1) {
290 char bf[BUFSIZ], *pbf = bf; 287 char bf[BUFSIZ], *pbf = bf;
291 struct mmap_event mmap_ev = { 288 struct mmap_event mmap_ev = {
292 .header.type = PERF_EVENT_MMAP, 289 .header = { .type = PERF_EVENT_MMAP },
293 }; 290 };
294 int n; 291 int n;
295 size_t size; 292 size_t size;
@@ -306,12 +303,15 @@ static void pid_synthesize_mmap_samples(pid_t pid)
306 continue; 303 continue;
307 pbf += n + 3; 304 pbf += n + 3;
308 if (*pbf == 'x') { /* vm_exec */ 305 if (*pbf == 'x') { /* vm_exec */
309 char *execname = strrchr(bf, ' '); 306 char *execname = strchr(bf, '/');
307
308 /* Catch VDSO */
309 if (execname == NULL)
310 execname = strstr(bf, "[vdso]");
310 311
311 if (execname == NULL || execname[1] != '/') 312 if (execname == NULL)
312 continue; 313 continue;
313 314
314 execname += 1;
315 size = strlen(execname); 315 size = strlen(execname);
316 execname[size - 1] = '\0'; /* Remove \n */ 316 execname[size - 1] = '\0'; /* Remove \n */
317 memcpy(mmap_ev.filename, execname, size); 317 memcpy(mmap_ev.filename, execname, size);
@@ -319,7 +319,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
319 mmap_ev.len -= mmap_ev.start; 319 mmap_ev.len -= mmap_ev.start;
320 mmap_ev.header.size = (sizeof(mmap_ev) - 320 mmap_ev.header.size = (sizeof(mmap_ev) -
321 (sizeof(mmap_ev.filename) - size)); 321 (sizeof(mmap_ev.filename) - size));
322 mmap_ev.pid = pid; 322 mmap_ev.pid = tgid;
323 mmap_ev.tid = pid; 323 mmap_ev.tid = pid;
324 324
325 write_output(&mmap_ev, mmap_ev.header.size); 325 write_output(&mmap_ev, mmap_ev.header.size);
@@ -329,7 +329,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
329 fclose(fp); 329 fclose(fp);
330} 330}
331 331
332static void synthesize_samples(void) 332static void synthesize_all(void)
333{ 333{
334 DIR *proc; 334 DIR *proc;
335 struct dirent dirent, *next; 335 struct dirent dirent, *next;
@@ -338,14 +338,14 @@ static void synthesize_samples(void)
338 338
339 while (!readdir_r(proc, &dirent, &next) && next) { 339 while (!readdir_r(proc, &dirent, &next) && next) {
340 char *end; 340 char *end;
341 pid_t pid; 341 pid_t pid, tgid;
342 342
343 pid = strtol(dirent.d_name, &end, 10); 343 pid = strtol(dirent.d_name, &end, 10);
344 if (*end) /* only interested in proper numerical dirents */ 344 if (*end) /* only interested in proper numerical dirents */
345 continue; 345 continue;
346 346
347 pid_synthesize_comm_event(pid, 1); 347 tgid = pid_synthesize_comm_event(pid, 1);
348 pid_synthesize_mmap_samples(pid); 348 pid_synthesize_mmap_samples(pid, tgid);
349 } 349 }
350 350
351 closedir(proc); 351 closedir(proc);
@@ -353,12 +353,37 @@ static void synthesize_samples(void)
353 353
354static int group_fd; 354static int group_fd;
355 355
356static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr)
357{
358 struct perf_header_attr *h_attr;
359
360 if (nr < header->attrs) {
361 h_attr = header->attr[nr];
362 } else {
363 h_attr = perf_header_attr__new(a);
364 perf_header__add_attr(header, h_attr);
365 }
366
367 return h_attr;
368}
369
356static void create_counter(int counter, int cpu, pid_t pid) 370static void create_counter(int counter, int cpu, pid_t pid)
357{ 371{
358 struct perf_counter_attr *attr = attrs + counter; 372 struct perf_counter_attr *attr = attrs + counter;
359 int track = 1; 373 struct perf_header_attr *h_attr;
374 int track = !counter; /* only the first counter needs these */
375 struct {
376 u64 count;
377 u64 time_enabled;
378 u64 time_running;
379 u64 id;
380 } read_data;
381
382 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
383 PERF_FORMAT_TOTAL_TIME_RUNNING |
384 PERF_FORMAT_ID;
360 385
361 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 386 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
362 387
363 if (freq) { 388 if (freq) {
364 attr->sample_type |= PERF_SAMPLE_PERIOD; 389 attr->sample_type |= PERF_SAMPLE_PERIOD;
@@ -366,16 +391,22 @@ static void create_counter(int counter, int cpu, pid_t pid)
366 attr->sample_freq = freq; 391 attr->sample_freq = freq;
367 } 392 }
368 393
394 if (no_samples)
395 attr->sample_freq = 0;
396
397 if (inherit_stat)
398 attr->inherit_stat = 1;
399
400 if (sample_address)
401 attr->sample_type |= PERF_SAMPLE_ADDR;
402
369 if (call_graph) 403 if (call_graph)
370 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 404 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
371 405
372 if (file_new) { 406 if (raw_samples) {
373 file_header.sample_type = attr->sample_type; 407 attr->sample_type |= PERF_SAMPLE_TIME;
374 } else { 408 attr->sample_type |= PERF_SAMPLE_RAW;
375 if (file_header.sample_type != attr->sample_type) { 409 attr->sample_type |= PERF_SAMPLE_CPU;
376 fprintf(stderr, "incompatible append\n");
377 exit(-1);
378 }
379 } 410 }
380 411
381 attr->mmap = track; 412 attr->mmap = track;
@@ -383,8 +414,6 @@ static void create_counter(int counter, int cpu, pid_t pid)
383 attr->inherit = (cpu < 0) && inherit; 414 attr->inherit = (cpu < 0) && inherit;
384 attr->disabled = 1; 415 attr->disabled = 1;
385 416
386 track = 0; /* only the first counter needs these */
387
388try_again: 417try_again:
389 fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); 418 fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
390 419
@@ -393,6 +422,8 @@ try_again:
393 422
394 if (err == EPERM) 423 if (err == EPERM)
395 die("Permission error - are you root?\n"); 424 die("Permission error - are you root?\n");
425 else if (err == ENODEV && profile_cpu != -1)
426 die("No such device - did you specify an out-of-range profile CPU?\n");
396 427
397 /* 428 /*
398 * If it's cycles then fall back to hrtimer 429 * If it's cycles then fall back to hrtimer
@@ -415,6 +446,22 @@ try_again:
415 exit(-1); 446 exit(-1);
416 } 447 }
417 448
449 h_attr = get_header_attr(attr, counter);
450
451 if (!file_new) {
452 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
453 fprintf(stderr, "incompatible append\n");
454 exit(-1);
455 }
456 }
457
458 if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) {
459 perror("Unable to read perf file descriptor\n");
460 exit(-1);
461 }
462
463 perf_header_attr__add_id(h_attr, read_data.id);
464
418 assert(fd[nr_cpu][counter] >= 0); 465 assert(fd[nr_cpu][counter] >= 0);
419 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 466 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
420 467
@@ -445,11 +492,6 @@ static void open_counters(int cpu, pid_t pid)
445{ 492{
446 int counter; 493 int counter;
447 494
448 if (pid > 0) {
449 pid_synthesize_comm_event(pid, 0);
450 pid_synthesize_mmap_samples(pid);
451 }
452
453 group_fd = -1; 495 group_fd = -1;
454 for (counter = 0; counter < nr_counters; counter++) 496 for (counter = 0; counter < nr_counters; counter++)
455 create_counter(counter, cpu, pid); 497 create_counter(counter, cpu, pid);
@@ -459,17 +501,16 @@ static void open_counters(int cpu, pid_t pid)
459 501
460static void atexit_header(void) 502static void atexit_header(void)
461{ 503{
462 file_header.data_size += bytes_written; 504 header->data_size += bytes_written;
463 505
464 if (pwrite(output, &file_header, sizeof(file_header), 0) == -1) 506 perf_header__write(header, output);
465 perror("failed to write on file headers");
466} 507}
467 508
468static int __cmd_record(int argc, const char **argv) 509static int __cmd_record(int argc, const char **argv)
469{ 510{
470 int i, counter; 511 int i, counter;
471 struct stat st; 512 struct stat st;
472 pid_t pid; 513 pid_t pid = 0;
473 int flags; 514 int flags;
474 int ret; 515 int ret;
475 516
@@ -482,10 +523,14 @@ static int __cmd_record(int argc, const char **argv)
482 signal(SIGCHLD, sig_handler); 523 signal(SIGCHLD, sig_handler);
483 signal(SIGINT, sig_handler); 524 signal(SIGINT, sig_handler);
484 525
485 if (!stat(output_name, &st) && !force && !append_file) { 526 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", 527 if (!force && !append_file) {
487 output_name); 528 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
488 exit(-1); 529 output_name);
530 exit(-1);
531 }
532 } else {
533 append_file = 0;
489 } 534 }
490 535
491 flags = O_CREAT|O_RDWR; 536 flags = O_CREAT|O_RDWR;
@@ -500,21 +545,47 @@ static int __cmd_record(int argc, const char **argv)
500 exit(-1); 545 exit(-1);
501 } 546 }
502 547
503 if (!file_new) { 548 if (!file_new)
504 if (read(output, &file_header, sizeof(file_header)) == -1) { 549 header = perf_header__read(output);
505 perror("failed to read file headers"); 550 else
506 exit(-1); 551 header = perf_header__new();
552
553
554 if (raw_samples) {
555 read_tracing_data(attrs, nr_counters);
556 } else {
557 for (i = 0; i < nr_counters; i++) {
558 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
559 read_tracing_data(attrs, nr_counters);
560 break;
561 }
507 } 562 }
563 }
564 atexit(atexit_header);
565
566 if (!system_wide) {
567 pid = target_pid;
568 if (pid == -1)
569 pid = getpid();
508 570
509 lseek(output, file_header.data_size, SEEK_CUR); 571 open_counters(profile_cpu, pid);
572 } else {
573 if (profile_cpu != -1) {
574 open_counters(profile_cpu, target_pid);
575 } else {
576 for (i = 0; i < nr_cpus; i++)
577 open_counters(i, target_pid);
578 }
510 } 579 }
511 580
512 atexit(atexit_header); 581 if (file_new)
582 perf_header__write(header, output);
513 583
514 if (!system_wide) { 584 if (!system_wide) {
515 open_counters(-1, target_pid != -1 ? target_pid : getpid()); 585 pid_t tgid = pid_synthesize_comm_event(pid, 0);
516 } else for (i = 0; i < nr_cpus; i++) 586 pid_synthesize_mmap_samples(pid, tgid);
517 open_counters(i, target_pid); 587 } else
588 synthesize_all();
518 589
519 if (target_pid == -1 && argc) { 590 if (target_pid == -1 && argc) {
520 pid = fork(); 591 pid = fork();
@@ -539,10 +610,7 @@ static int __cmd_record(int argc, const char **argv)
539 } 610 }
540 } 611 }
541 612
542 if (system_wide) 613 for (;;) {
543 synthesize_samples();
544
545 while (!done) {
546 int hits = samples; 614 int hits = samples;
547 615
548 for (i = 0; i < nr_cpu; i++) { 616 for (i = 0; i < nr_cpu; i++) {
@@ -550,8 +618,11 @@ static int __cmd_record(int argc, const char **argv)
550 mmap_read(&mmap_array[i][counter]); 618 mmap_read(&mmap_array[i][counter]);
551 } 619 }
552 620
553 if (hits == samples) 621 if (hits == samples) {
622 if (done)
623 break;
554 ret = poll(event_array, nr_poll, 100); 624 ret = poll(event_array, nr_poll, 100);
625 }
555 } 626 }
556 627
557 /* 628 /*
@@ -580,10 +651,14 @@ static const struct option options[] = {
580 "record events on existing pid"), 651 "record events on existing pid"),
581 OPT_INTEGER('r', "realtime", &realtime_prio, 652 OPT_INTEGER('r', "realtime", &realtime_prio,
582 "collect data with this RT SCHED_FIFO priority"), 653 "collect data with this RT SCHED_FIFO priority"),
654 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
655 "collect raw sample records from all opened counters"),
583 OPT_BOOLEAN('a', "all-cpus", &system_wide, 656 OPT_BOOLEAN('a', "all-cpus", &system_wide,
584 "system-wide collection from all CPUs"), 657 "system-wide collection from all CPUs"),
585 OPT_BOOLEAN('A', "append", &append_file, 658 OPT_BOOLEAN('A', "append", &append_file,
586 "append to the output file to do incremental profiling"), 659 "append to the output file to do incremental profiling"),
660 OPT_INTEGER('C', "profile_cpu", &profile_cpu,
661 "CPU to profile on"),
587 OPT_BOOLEAN('f', "force", &force, 662 OPT_BOOLEAN('f', "force", &force,
588 "overwrite existing data file"), 663 "overwrite existing data file"),
589 OPT_LONG('c', "count", &default_interval, 664 OPT_LONG('c', "count", &default_interval,
@@ -600,14 +675,21 @@ static const struct option options[] = {
600 "do call-graph (stack chain/backtrace) recording"), 675 "do call-graph (stack chain/backtrace) recording"),
601 OPT_BOOLEAN('v', "verbose", &verbose, 676 OPT_BOOLEAN('v', "verbose", &verbose,
602 "be more verbose (show counter open errors, etc)"), 677 "be more verbose (show counter open errors, etc)"),
678 OPT_BOOLEAN('s', "stat", &inherit_stat,
679 "per thread counts"),
680 OPT_BOOLEAN('d', "data", &sample_address,
681 "Sample addresses"),
682 OPT_BOOLEAN('n', "no-samples", &no_samples,
683 "don't sample"),
603 OPT_END() 684 OPT_END()
604}; 685};
605 686
606int cmd_record(int argc, const char **argv, const char *prefix) 687int cmd_record(int argc, const char **argv, const char *prefix __used)
607{ 688{
608 int counter; 689 int counter;
609 690
610 argc = parse_options(argc, argv, options, record_usage, 0); 691 argc = parse_options(argc, argv, options, record_usage,
692 PARSE_OPT_STOP_AT_NON_OPTION);
611 if (!argc && target_pid == -1 && !system_wide) 693 if (!argc && target_pid == -1 && !system_wide)
612 usage_with_options(record_usage, options); 694 usage_with_options(record_usage, options);
613 695
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 5eb5566f0c95..cdf9a8d27bb9 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_EVENT_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_EVENT_MISC_CPUMODE_MASK;
1162
1163 if (cpumode == PERF_EVENT_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_EVENT_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_EVENT_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_EVENT_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_EVENT_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_EVENT_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_EVENT_%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_EVENT_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_EVENT_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_EVENT_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_EVENT_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_counter_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_EVENT_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,10 +1336,10 @@ 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) {
1340 case PERF_EVENT_SAMPLE:
1341 return process_sample_event(event, offset, head);
1342
1339 case PERF_EVENT_MMAP: 1343 case PERF_EVENT_MMAP:
1340 return process_mmap_event(event, offset, head); 1344 return process_mmap_event(event, offset, head);
1341 1345
@@ -1343,14 +1347,15 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
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_EVENT_FORK:
1346 return process_fork_event(event, offset, head); 1350 case PERF_EVENT_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_EVENT_LOST:
1352 return process_lost_event(event, offset, head); 1354 return process_lost_event(event, offset, head);
1353 1355
1356 case PERF_EVENT_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 */
@@ -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-stat.c b/tools/perf/builtin-stat.c
index 6d3eeac1ea25..61b828236c11 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_counter_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,56 +63,76 @@ 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
72static int scale = 1;
73 78
74static const unsigned int default_count[] = { 79struct stats
75 1000000, 80{
76 1000000, 81 double n, mean, M2;
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_counter_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_counter_attr *attr = attrs + counter;
115 138
@@ -118,21 +141,23 @@ static void create_perf_stat_counter(int counter)
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 ++) { 145
146 for (cpu = 0; cpu < nr_cpus; cpu++) {
123 fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0); 147 fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
124 if (fd[cpu][counter] < 0 && verbose) { 148 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)); 149 fprintf(stderr, ERR_PERF_OPEN, counter,
126 } 150 fd[cpu][counter], strerror(errno));
127 } 151 }
128 } else { 152 } else {
129 attr->inherit = inherit; 153 attr->inherit = inherit;
130 attr->disabled = 1; 154 attr->disabled = 1;
131 155 attr->enable_on_exec = 1;
132 fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0); 156
133 if (fd[0][counter] < 0 && verbose) { 157 fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0);
134 printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[0][counter], strerror(errno)); 158 if (fd[0][counter] < 0 && verbose)
135 } 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,38 @@ 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 fprintf(stderr, " %14.0f %-24s", avg, event_name(counter));
280
281 if (runtime_cycles_avg &&
282 attrs[counter].type == PERF_TYPE_HARDWARE &&
283 attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) {
284 342
343 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
285 fprintf(stderr, " # %10.3f IPC ", 344 fprintf(stderr, " # %10.3f IPC ",
286 (double)count[0] / (double)runtime_cycles_avg); 345 avg / avg_stats(&runtime_cycles_stats));
287 } else { 346 } else {
288 if (runtime_nsecs_avg) { 347 fprintf(stderr, " # %10.3f M/sec",
289 fprintf(stderr, " # %10.3f M/sec", 348 1000.0 * avg / avg_stats(&runtime_nsecs_stats));
290 (double)count[0]/runtime_nsecs_avg*1000.0);
291 }
292 } 349 }
293 print_noise(count, noise);
294} 350}
295 351
296/* 352/*
@@ -298,121 +354,39 @@ static void abs_printout(int counter, u64 *count, u64 *noise)
298 */ 354 */
299static void print_counter(int counter) 355static void print_counter(int counter)
300{ 356{
301 u64 *count, *noise; 357 double avg = avg_stats(&event_res_stats[counter][0]);
302 int scaled; 358 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 359
308 if (scaled == -1) { 360 if (scaled == -1) {
309 fprintf(stderr, " %14s %-20s\n", 361 fprintf(stderr, " %14s %-24s\n",
310 "<not counted>", event_name(counter)); 362 "<not counted>", event_name(counter));
311 return; 363 return;
312 } 364 }
313 365
314 if (nsec_counter(counter)) 366 if (nsec_counter(counter))
315 nsec_printout(counter, count, noise); 367 nsec_printout(counter, avg);
316 else 368 else
317 abs_printout(counter, count, noise); 369 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 370
326/* 371 print_noise(counter, avg);
327 * normalize_noise noise values down to stddev:
328 */
329static void normalize_noise(u64 *val)
330{
331 double res;
332 372
333 res = (double)*val / (run_count * sqrt((double)run_count)); 373 if (scaled) {
374 double avg_enabled, avg_running;
334 375
335 *val = (u64)res; 376 avg_enabled = avg_stats(&event_res_stats[counter][1]);
336} 377 avg_running = avg_stats(&event_res_stats[counter][2]);
337 378
338static void update_avg(const char *name, int idx, u64 *avg, u64 *val) 379 fprintf(stderr, " (scaled from %.2f%%)",
339{ 380 100 * avg_running / avg_enabled);
340 *avg += *val;
341
342 if (verbose > 1)
343 fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val);
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
381 for (i = 0; i < run_count; i++) {
382 runtime_nsecs_noise +=
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 } 381 }
398 382
399 normalize_noise(&runtime_nsecs_noise); 383 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} 384}
409 385
410static void print_stat(int argc, const char **argv) 386static void print_stat(int argc, const char **argv)
411{ 387{
412 int i, counter; 388 int i, counter;
413 389
414 calc_avg();
415
416 fflush(stdout); 390 fflush(stdout);
417 391
418 fprintf(stderr, "\n"); 392 fprintf(stderr, "\n");
@@ -429,11 +403,15 @@ static void print_stat(int argc, const char **argv)
429 for (counter = 0; counter < nr_counters; counter++) 403 for (counter = 0; counter < nr_counters; counter++)
430 print_counter(counter); 404 print_counter(counter);
431 405
432
433 fprintf(stderr, "\n");
434 fprintf(stderr, " %14.9f seconds time elapsed.\n",
435 (double)walltime_nsecs_avg/1e9);
436 fprintf(stderr, "\n"); 406 fprintf(stderr, "\n");
407 fprintf(stderr, " %14.9f seconds time elapsed",
408 avg_stats(&walltime_nsecs_stats)/1e9);
409 if (run_count > 1) {
410 fprintf(stderr, " ( +- %7.3f%% )",
411 100*stddev_stats(&walltime_nsecs_stats) /
412 avg_stats(&walltime_nsecs_stats));
413 }
414 fprintf(stderr, "\n\n");
437} 415}
438 416
439static volatile int signr = -1; 417static volatile int signr = -1;
@@ -466,36 +444,38 @@ static const struct option options[] = {
466 OPT_INTEGER('p', "pid", &target_pid, 444 OPT_INTEGER('p', "pid", &target_pid,
467 "stat events on existing pid"), 445 "stat events on existing pid"),
468 OPT_BOOLEAN('a', "all-cpus", &system_wide, 446 OPT_BOOLEAN('a', "all-cpus", &system_wide,
469 "system-wide collection from all CPUs"), 447 "system-wide collection from all CPUs"),
470 OPT_BOOLEAN('S', "scale", &scale, 448 OPT_BOOLEAN('c', "scale", &scale,
471 "scale/normalize counters"), 449 "scale/normalize counters"),
472 OPT_BOOLEAN('v', "verbose", &verbose, 450 OPT_BOOLEAN('v', "verbose", &verbose,
473 "be more verbose (show counter open errors, etc)"), 451 "be more verbose (show counter open errors, etc)"),
474 OPT_INTEGER('r', "repeat", &run_count, 452 OPT_INTEGER('r', "repeat", &run_count,
475 "repeat command and print average + stddev (max: 100)"), 453 "repeat command and print average + stddev (max: 100)"),
454 OPT_BOOLEAN('n', "null", &null_run,
455 "null run - dont start any counters"),
476 OPT_END() 456 OPT_END()
477}; 457};
478 458
479int cmd_stat(int argc, const char **argv, const char *prefix) 459int cmd_stat(int argc, const char **argv, const char *prefix __used)
480{ 460{
481 int status; 461 int status;
482 462
483 page_size = sysconf(_SC_PAGE_SIZE); 463 argc = parse_options(argc, argv, options, stat_usage,
484 464 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) 465 if (!argc)
489 usage_with_options(stat_usage, options); 466 usage_with_options(stat_usage, options);
490 if (run_count <= 0 || run_count > MAX_RUN) 467 if (run_count <= 0)
491 usage_with_options(stat_usage, options); 468 usage_with_options(stat_usage, options);
492 469
493 if (!nr_counters) 470 /* Set attrs and nr_counters if no event is selected and !null_run */
494 nr_counters = 8; 471 if (!null_run && !nr_counters) {
472 memcpy(attrs, default_attrs, sizeof(default_attrs));
473 nr_counters = ARRAY_SIZE(default_attrs);
474 }
495 475
496 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 476 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
497 assert(nr_cpus <= MAX_NR_CPUS); 477 assert(nr_cpus <= MAX_NR_CPUS);
498 assert(nr_cpus >= 0); 478 assert((int)nr_cpus >= 0);
499 479
500 /* 480 /*
501 * We dont want to block the signals - that would cause 481 * We dont want to block the signals - that would cause
@@ -511,7 +491,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
511 status = 0; 491 status = 0;
512 for (run_idx = 0; run_idx < run_count; run_idx++) { 492 for (run_idx = 0; run_idx < run_count; run_idx++) {
513 if (run_count != 1 && verbose) 493 if (run_count != 1 && verbose)
514 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx+1); 494 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
515 status = run_perf_stat(argc, argv); 495 status = run_perf_stat(argc, argv);
516 } 496 }
517 497
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5352b5e352ed..4002ccb36750 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,7 +895,7 @@ 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
@@ -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_EVENT_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_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER;
983 process_event(event->ip.ip, md->counter, user);
515 } 984 }
516 } 985 }
517 986
@@ -537,7 +1006,7 @@ int group_fd;
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_counter_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,6 +1016,7 @@ 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_counter_open(attr, target_pid, cpu, group_fd, 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..914ab366e369
--- /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_EVENT_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_EVENT_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_EVENT_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_EVENT_MISC_CPUMODE_MASK;
102
103 if (cpumode == PERF_EVENT_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_EVENT_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_EVENT_MMAP ... PERF_EVENT_LOST:
150 return 0;
151
152 case PERF_EVENT_COMM:
153 return process_comm_event(event, offset, head);
154
155 case PERF_EVENT_EXIT ... PERF_EVENT_READ:
156 return 0;
157
158 case PERF_EVENT_SAMPLE:
159 return process_sample_event(event, offset, head);
160
161 case PERF_EVENT_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..3a63e41fb44e 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -22,5 +22,6 @@ extern int cmd_stat(int argc, const char **argv, const char *prefix);
22extern int cmd_top(int argc, const char **argv, const char *prefix); 22extern int cmd_top(int argc, const char **argv, const char *prefix);
23extern int cmd_version(int argc, const char **argv, const char *prefix); 23extern int cmd_version(int argc, const char **argv, const char *prefix);
24extern int cmd_list(int argc, const char **argv, const char *prefix); 24extern int cmd_list(int argc, const char **argv, const char *prefix);
25extern int cmd_trace(int argc, const char **argv, const char *prefix);
25 26
26#endif 27#endif
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 4eb725933703..fe4589dde950 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)
@@ -265,8 +292,9 @@ static void handle_internal_command(int argc, const char **argv)
265 { "top", cmd_top, 0 }, 292 { "top", cmd_top, 0 },
266 { "annotate", cmd_annotate, 0 }, 293 { "annotate", cmd_annotate, 0 },
267 { "version", cmd_version, 0 }, 294 { "version", cmd_version, 0 },
295 { "trace", cmd_trace, 0 },
268 }; 296 };
269 int i; 297 unsigned int i;
270 static const char ext[] = STRIP_EXTENSION; 298 static const char ext[] = STRIP_EXTENSION;
271 299
272 if (sizeof(ext) > 1) { 300 if (sizeof(ext) > 1) {
@@ -349,6 +377,49 @@ static int run_argv(int *argcp, const char ***argv)
349 return done_alias; 377 return done_alias;
350} 378}
351 379
380/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
381static void get_debugfs_mntpt(void)
382{
383 FILE *file;
384 char fs_type[100];
385 char debugfs[MAXPATHLEN];
386
387 /*
388 * try the standard location
389 */
390 if (valid_debugfs_mount("/sys/kernel/debug/") == 0) {
391 strcpy(debugfs_mntpt, "/sys/kernel/debug/");
392 return;
393 }
394
395 /*
396 * try the sane location
397 */
398 if (valid_debugfs_mount("/debug/") == 0) {
399 strcpy(debugfs_mntpt, "/debug/");
400 return;
401 }
402
403 /*
404 * give up and parse /proc/mounts
405 */
406 file = fopen("/proc/mounts", "r");
407 if (file == NULL)
408 return;
409
410 while (fscanf(file, "%*s %"
411 STR(MAXPATHLEN)
412 "s %99s %*s %*d %*d\n",
413 debugfs, fs_type) == 2) {
414 if (strcmp(fs_type, "debugfs") == 0)
415 break;
416 }
417 fclose(file);
418 if (strcmp(fs_type, "debugfs") == 0) {
419 strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
420 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
421 }
422}
352 423
353int main(int argc, const char **argv) 424int main(int argc, const char **argv)
354{ 425{
@@ -357,7 +428,8 @@ int main(int argc, const char **argv)
357 cmd = perf_extract_argv0_path(argv[0]); 428 cmd = perf_extract_argv0_path(argv[0]);
358 if (!cmd) 429 if (!cmd)
359 cmd = "perf-help"; 430 cmd = "perf-help";
360 431 /* get debugfs mount point from /proc/mounts */
432 get_debugfs_mntpt();
361 /* 433 /*
362 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 434 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
363 * 435 *
@@ -380,6 +452,7 @@ int main(int argc, const char **argv)
380 argc--; 452 argc--;
381 handle_options(&argv, &argc, NULL); 453 handle_options(&argv, &argc, NULL);
382 commit_pager_choice(); 454 commit_pager_choice();
455 set_debugfs_path();
383 if (argc > 0) { 456 if (argc > 0) {
384 if (!prefixcmp(argv[0], "--")) 457 if (!prefixcmp(argv[0], "--"))
385 argv[0] += 2; 458 argv[0] += 2;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index ceb68aa51f7f..e5148e2b6134 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,13 +25,29 @@
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
22#include <time.h> 44#include <time.h>
23#include <unistd.h> 45#include <unistd.h>
24#include <sys/types.h> 46#include <sys/types.h>
25#include <sys/syscall.h> 47#include <sys/syscall.h>
26 48
27#include "../../include/linux/perf_counter.h" 49#include "../../include/linux/perf_counter.h"
28#include "types.h" 50#include "util/types.h"
29 51
30/* 52/*
31 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all 53 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
@@ -52,6 +74,8 @@ static inline unsigned long long rdclock(void)
52#define __user 74#define __user
53#define asmlinkage 75#define asmlinkage
54 76
77#define __used __attribute__((__unused__))
78
55#define unlikely(x) __builtin_expect(!!(x), 0) 79#define unlikely(x) __builtin_expect(!!(x), 0)
56#define min(x, y) ({ \ 80#define min(x, y) ({ \
57 typeof(x) _min1 = (x); \ 81 typeof(x) _min1 = (x); \
@@ -72,10 +96,9 @@ sys_perf_counter_open(struct perf_counter_attr *attr,
72#define MAX_COUNTERS 256 96#define MAX_COUNTERS 256
73#define MAX_NR_CPUS 256 97#define MAX_NR_CPUS 256
74 98
75struct perf_file_header { 99struct ip_callchain {
76 u64 version; 100 u64 nr;
77 u64 sample_type; 101 u64 ips[0];
78 u64 data_size;
79}; 102};
80 103
81#endif 104#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..fa2d4e91d329
--- /dev/null
+++ b/tools/perf/util/event.h
@@ -0,0 +1,96 @@
1#ifndef __PERF_EVENT_H
2#define __PERF_EVENT_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};
43
44struct lost_event {
45 struct perf_event_header header;
46 u64 id;
47 u64 lost;
48};
49
50/*
51 * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
52 */
53struct read_event {
54 struct perf_event_header header;
55 u32 pid,tid;
56 u64 value;
57 u64 time_enabled;
58 u64 time_running;
59 u64 id;
60};
61
62typedef union event_union {
63 struct perf_event_header header;
64 struct ip_event ip;
65 struct mmap_event mmap;
66 struct comm_event comm;
67 struct fork_event fork;
68 struct lost_event lost;
69 struct read_event read;
70} event_t;
71
72struct map {
73 struct list_head node;
74 u64 start;
75 u64 end;
76 u64 pgoff;
77 u64 (*map_ip)(struct map *, u64);
78 struct dso *dso;
79};
80
81static inline u64 map__map_ip(struct map *map, u64 ip)
82{
83 return ip - map->start + map->pgoff;
84}
85
86static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
87{
88 return ip;
89}
90
91struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
92struct map *map__clone(struct map *self);
93int map__overlap(struct map *l, struct map *r);
94size_t map__fprintf(struct map *self, FILE *fp);
95
96#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..ec4d4c2f9522
--- /dev/null
+++ b/tools/perf/util/header.c
@@ -0,0 +1,280 @@
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 *
11 */
12
13struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr)
14{
15 struct perf_header_attr *self = malloc(sizeof(*self));
16
17 if (!self)
18 die("nomem");
19
20 self->attr = *attr;
21 self->ids = 0;
22 self->size = 1;
23 self->id = malloc(sizeof(u64));
24
25 if (!self->id)
26 die("nomem");
27
28 return self;
29}
30
31void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
32{
33 int pos = self->ids;
34
35 self->ids++;
36 if (self->ids > self->size) {
37 self->size *= 2;
38 self->id = realloc(self->id, self->size * sizeof(u64));
39 if (!self->id)
40 die("nomem");
41 }
42 self->id[pos] = id;
43}
44
45/*
46 *
47 */
48
49struct perf_header *perf_header__new(void)
50{
51 struct perf_header *self = malloc(sizeof(*self));
52
53 if (!self)
54 die("nomem");
55
56 self->frozen = 0;
57
58 self->attrs = 0;
59 self->size = 1;
60 self->attr = malloc(sizeof(void *));
61
62 if (!self->attr)
63 die("nomem");
64
65 self->data_offset = 0;
66 self->data_size = 0;
67
68 return self;
69}
70
71void perf_header__add_attr(struct perf_header *self,
72 struct perf_header_attr *attr)
73{
74 int pos = self->attrs;
75
76 if (self->frozen)
77 die("frozen");
78
79 self->attrs++;
80 if (self->attrs > self->size) {
81 self->size *= 2;
82 self->attr = realloc(self->attr, self->size * sizeof(void *));
83 if (!self->attr)
84 die("nomem");
85 }
86 self->attr[pos] = attr;
87}
88
89static const char *__perf_magic = "PERFFILE";
90
91#define PERF_MAGIC (*(u64 *)__perf_magic)
92
93struct perf_file_section {
94 u64 offset;
95 u64 size;
96};
97
98struct perf_file_attr {
99 struct perf_counter_attr attr;
100 struct perf_file_section ids;
101};
102
103struct perf_file_header {
104 u64 magic;
105 u64 size;
106 u64 attr_size;
107 struct perf_file_section attrs;
108 struct perf_file_section data;
109};
110
111static void do_write(int fd, void *buf, size_t size)
112{
113 while (size) {
114 int ret = write(fd, buf, size);
115
116 if (ret < 0)
117 die("failed to write");
118
119 size -= ret;
120 buf += ret;
121 }
122}
123
124void perf_header__write(struct perf_header *self, int fd)
125{
126 struct perf_file_header f_header;
127 struct perf_file_attr f_attr;
128 struct perf_header_attr *attr;
129 int i;
130
131 lseek(fd, sizeof(f_header), SEEK_SET);
132
133
134 for (i = 0; i < self->attrs; i++) {
135 attr = self->attr[i];
136
137 attr->id_offset = lseek(fd, 0, SEEK_CUR);
138 do_write(fd, attr->id, attr->ids * sizeof(u64));
139 }
140
141
142 self->attr_offset = lseek(fd, 0, SEEK_CUR);
143
144 for (i = 0; i < self->attrs; i++) {
145 attr = self->attr[i];
146
147 f_attr = (struct perf_file_attr){
148 .attr = attr->attr,
149 .ids = {
150 .offset = attr->id_offset,
151 .size = attr->ids * sizeof(u64),
152 }
153 };
154 do_write(fd, &f_attr, sizeof(f_attr));
155 }
156
157
158 self->data_offset = lseek(fd, 0, SEEK_CUR);
159
160 f_header = (struct perf_file_header){
161 .magic = PERF_MAGIC,
162 .size = sizeof(f_header),
163 .attr_size = sizeof(f_attr),
164 .attrs = {
165 .offset = self->attr_offset,
166 .size = self->attrs * sizeof(f_attr),
167 },
168 .data = {
169 .offset = self->data_offset,
170 .size = self->data_size,
171 },
172 };
173
174 lseek(fd, 0, SEEK_SET);
175 do_write(fd, &f_header, sizeof(f_header));
176 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
177
178 self->frozen = 1;
179}
180
181static void do_read(int fd, void *buf, size_t size)
182{
183 while (size) {
184 int ret = read(fd, buf, size);
185
186 if (ret < 0)
187 die("failed to read");
188 if (ret == 0)
189 die("failed to read: missing data");
190
191 size -= ret;
192 buf += ret;
193 }
194}
195
196struct perf_header *perf_header__read(int fd)
197{
198 struct perf_header *self = perf_header__new();
199 struct perf_file_header f_header;
200 struct perf_file_attr f_attr;
201 u64 f_id;
202
203 int nr_attrs, nr_ids, i, j;
204
205 lseek(fd, 0, SEEK_SET);
206 do_read(fd, &f_header, sizeof(f_header));
207
208 if (f_header.magic != PERF_MAGIC ||
209 f_header.size != sizeof(f_header) ||
210 f_header.attr_size != sizeof(f_attr))
211 die("incompatible file format");
212
213 nr_attrs = f_header.attrs.size / sizeof(f_attr);
214 lseek(fd, f_header.attrs.offset, SEEK_SET);
215
216 for (i = 0; i < nr_attrs; i++) {
217 struct perf_header_attr *attr;
218 off_t tmp;
219
220 do_read(fd, &f_attr, sizeof(f_attr));
221 tmp = lseek(fd, 0, SEEK_CUR);
222
223 attr = perf_header_attr__new(&f_attr.attr);
224
225 nr_ids = f_attr.ids.size / sizeof(u64);
226 lseek(fd, f_attr.ids.offset, SEEK_SET);
227
228 for (j = 0; j < nr_ids; j++) {
229 do_read(fd, &f_id, sizeof(f_id));
230
231 perf_header_attr__add_id(attr, f_id);
232 }
233 perf_header__add_attr(self, attr);
234 lseek(fd, tmp, SEEK_SET);
235 }
236
237 self->data_offset = f_header.data.offset;
238 self->data_size = f_header.data.size;
239
240 lseek(fd, self->data_offset, SEEK_SET);
241
242 self->frozen = 1;
243
244 return self;
245}
246
247u64 perf_header__sample_type(struct perf_header *header)
248{
249 u64 type = 0;
250 int i;
251
252 for (i = 0; i < header->attrs; i++) {
253 struct perf_header_attr *attr = header->attr[i];
254
255 if (!type)
256 type = attr->attr.sample_type;
257 else if (type != attr->attr.sample_type)
258 die("non matching sample_type");
259 }
260
261 return type;
262}
263
264struct perf_counter_attr *
265perf_header__find_attr(u64 id, struct perf_header *header)
266{
267 int i;
268
269 for (i = 0; i < header->attrs; i++) {
270 struct perf_header_attr *attr = header->attr[i];
271 int j;
272
273 for (j = 0; j < attr->ids; j++) {
274 if (attr->id[j] == id)
275 return &attr->attr;
276 }
277 }
278
279 return NULL;
280}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
new file mode 100644
index 000000000000..5d0a72ecc919
--- /dev/null
+++ b/tools/perf/util/header.h
@@ -0,0 +1,41 @@
1#ifndef _PERF_HEADER_H
2#define _PERF_HEADER_H
3
4#include "../../../include/linux/perf_counter.h"
5#include <sys/types.h>
6#include "types.h"
7
8struct perf_header_attr {
9 struct perf_counter_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};
23
24struct perf_header *perf_header__read(int fd);
25void perf_header__write(struct perf_header *self, int fd);
26
27void perf_header__add_attr(struct perf_header *self,
28 struct perf_header_attr *attr);
29
30struct perf_header_attr *
31perf_header_attr__new(struct perf_counter_attr *attr);
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
33
34u64 perf_header__sample_type(struct perf_header *header);
35struct perf_counter_attr *
36perf_header__find_attr(u64 id, struct perf_header *header);
37
38
39struct perf_header *perf_header__new(void);
40
41#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..3d567fe59c79
--- /dev/null
+++ b/tools/perf/util/module.c
@@ -0,0 +1,509 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <gelf.h>
8#include <elf.h>
9#include <dirent.h>
10#include <sys/utsname.h>
11
12static unsigned int crc32(const char *p, unsigned int len)
13{
14 int i;
15 unsigned int crc = 0;
16
17 while (len--) {
18 crc ^= *p++;
19 for (i = 0; i < 8; i++)
20 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
21 }
22 return crc;
23}
24
25/* module section methods */
26
27struct sec_dso *sec_dso__new_dso(const char *name)
28{
29 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
30
31 if (self != NULL) {
32 strcpy(self->name, name);
33 self->secs = RB_ROOT;
34 self->find_section = sec_dso__find_section;
35 }
36
37 return self;
38}
39
40static void sec_dso__delete_section(struct section *self)
41{
42 free(((void *)self));
43}
44
45void sec_dso__delete_sections(struct sec_dso *self)
46{
47 struct section *pos;
48 struct rb_node *next = rb_first(&self->secs);
49
50 while (next) {
51 pos = rb_entry(next, struct section, rb_node);
52 next = rb_next(&pos->rb_node);
53 rb_erase(&pos->rb_node, &self->secs);
54 sec_dso__delete_section(pos);
55 }
56}
57
58void sec_dso__delete_self(struct sec_dso *self)
59{
60 sec_dso__delete_sections(self);
61 free(self);
62}
63
64static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
65{
66 struct rb_node **p = &self->secs.rb_node;
67 struct rb_node *parent = NULL;
68 const u64 hash = sec->hash;
69 struct section *s;
70
71 while (*p != NULL) {
72 parent = *p;
73 s = rb_entry(parent, struct section, rb_node);
74 if (hash < s->hash)
75 p = &(*p)->rb_left;
76 else
77 p = &(*p)->rb_right;
78 }
79 rb_link_node(&sec->rb_node, parent, p);
80 rb_insert_color(&sec->rb_node, &self->secs);
81}
82
83struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
84{
85 struct rb_node *n;
86 u64 hash;
87 int len;
88
89 if (self == NULL)
90 return NULL;
91
92 len = strlen(name);
93 hash = crc32(name, len);
94
95 n = self->secs.rb_node;
96
97 while (n) {
98 struct section *s = rb_entry(n, struct section, rb_node);
99
100 if (hash < s->hash)
101 n = n->rb_left;
102 else if (hash > s->hash)
103 n = n->rb_right;
104 else {
105 if (!strcmp(name, s->name))
106 return s;
107 else
108 n = rb_next(&s->rb_node);
109 }
110 }
111
112 return NULL;
113}
114
115static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
116{
117 return fprintf(fp, "name:%s vma:%llx path:%s\n",
118 self->name, self->vma, self->path);
119}
120
121size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
122{
123 size_t ret = fprintf(fp, "dso: %s\n", self->name);
124
125 struct rb_node *nd;
126 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
127 struct section *pos = rb_entry(nd, struct section, rb_node);
128 ret += sec_dso__fprintf_section(pos, fp);
129 }
130
131 return ret;
132}
133
134static struct section *section__new(const char *name, const char *path)
135{
136 struct section *self = calloc(1, sizeof(*self));
137
138 if (!self)
139 goto out_failure;
140
141 self->name = calloc(1, strlen(name) + 1);
142 if (!self->name)
143 goto out_failure;
144
145 self->path = calloc(1, strlen(path) + 1);
146 if (!self->path)
147 goto out_failure;
148
149 strcpy(self->name, name);
150 strcpy(self->path, path);
151 self->hash = crc32(self->name, strlen(name));
152
153 return self;
154
155out_failure:
156 if (self) {
157 if (self->name)
158 free(self->name);
159 if (self->path)
160 free(self->path);
161 free(self);
162 }
163
164 return NULL;
165}
166
167/* module methods */
168
169struct mod_dso *mod_dso__new_dso(const char *name)
170{
171 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
172
173 if (self != NULL) {
174 strcpy(self->name, name);
175 self->mods = RB_ROOT;
176 self->find_module = mod_dso__find_module;
177 }
178
179 return self;
180}
181
182static void mod_dso__delete_module(struct module *self)
183{
184 free(((void *)self));
185}
186
187void mod_dso__delete_modules(struct mod_dso *self)
188{
189 struct module *pos;
190 struct rb_node *next = rb_first(&self->mods);
191
192 while (next) {
193 pos = rb_entry(next, struct module, rb_node);
194 next = rb_next(&pos->rb_node);
195 rb_erase(&pos->rb_node, &self->mods);
196 mod_dso__delete_module(pos);
197 }
198}
199
200void mod_dso__delete_self(struct mod_dso *self)
201{
202 mod_dso__delete_modules(self);
203 free(self);
204}
205
206static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
207{
208 struct rb_node **p = &self->mods.rb_node;
209 struct rb_node *parent = NULL;
210 const u64 hash = mod->hash;
211 struct module *m;
212
213 while (*p != NULL) {
214 parent = *p;
215 m = rb_entry(parent, struct module, rb_node);
216 if (hash < m->hash)
217 p = &(*p)->rb_left;
218 else
219 p = &(*p)->rb_right;
220 }
221 rb_link_node(&mod->rb_node, parent, p);
222 rb_insert_color(&mod->rb_node, &self->mods);
223}
224
225struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
226{
227 struct rb_node *n;
228 u64 hash;
229 int len;
230
231 if (self == NULL)
232 return NULL;
233
234 len = strlen(name);
235 hash = crc32(name, len);
236
237 n = self->mods.rb_node;
238
239 while (n) {
240 struct module *m = rb_entry(n, struct module, rb_node);
241
242 if (hash < m->hash)
243 n = n->rb_left;
244 else if (hash > m->hash)
245 n = n->rb_right;
246 else {
247 if (!strcmp(name, m->name))
248 return m;
249 else
250 n = rb_next(&m->rb_node);
251 }
252 }
253
254 return NULL;
255}
256
257static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
258{
259 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
260}
261
262size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
263{
264 struct rb_node *nd;
265 size_t ret;
266
267 ret = fprintf(fp, "dso: %s\n", self->name);
268
269 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
270 struct module *pos = rb_entry(nd, struct module, rb_node);
271
272 ret += mod_dso__fprintf_module(pos, fp);
273 }
274
275 return ret;
276}
277
278static struct module *module__new(const char *name, const char *path)
279{
280 struct module *self = calloc(1, sizeof(*self));
281
282 if (!self)
283 goto out_failure;
284
285 self->name = calloc(1, strlen(name) + 1);
286 if (!self->name)
287 goto out_failure;
288
289 self->path = calloc(1, strlen(path) + 1);
290 if (!self->path)
291 goto out_failure;
292
293 strcpy(self->name, name);
294 strcpy(self->path, path);
295 self->hash = crc32(self->name, strlen(name));
296
297 return self;
298
299out_failure:
300 if (self) {
301 if (self->name)
302 free(self->name);
303 if (self->path)
304 free(self->path);
305 free(self);
306 }
307
308 return NULL;
309}
310
311static int mod_dso__load_sections(struct module *mod)
312{
313 int count = 0, path_len;
314 struct dirent *entry;
315 char *line = NULL;
316 char *dir_path;
317 DIR *dir;
318 size_t n;
319
320 path_len = strlen("/sys/module/");
321 path_len += strlen(mod->name);
322 path_len += strlen("/sections/");
323
324 dir_path = calloc(1, path_len + 1);
325 if (dir_path == NULL)
326 goto out_failure;
327
328 strcat(dir_path, "/sys/module/");
329 strcat(dir_path, mod->name);
330 strcat(dir_path, "/sections/");
331
332 dir = opendir(dir_path);
333 if (dir == NULL)
334 goto out_free;
335
336 while ((entry = readdir(dir))) {
337 struct section *section;
338 char *path, *vma;
339 int line_len;
340 FILE *file;
341
342 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
343 continue;
344
345 path = calloc(1, path_len + strlen(entry->d_name) + 1);
346 if (path == NULL)
347 break;
348 strcat(path, dir_path);
349 strcat(path, entry->d_name);
350
351 file = fopen(path, "r");
352 if (file == NULL) {
353 free(path);
354 break;
355 }
356
357 line_len = getline(&line, &n, file);
358 if (line_len < 0) {
359 free(path);
360 fclose(file);
361 break;
362 }
363
364 if (!line) {
365 free(path);
366 fclose(file);
367 break;
368 }
369
370 line[--line_len] = '\0'; /* \n */
371
372 vma = strstr(line, "0x");
373 if (!vma) {
374 free(path);
375 fclose(file);
376 break;
377 }
378 vma += 2;
379
380 section = section__new(entry->d_name, path);
381 if (!section) {
382 fprintf(stderr, "load_sections: allocation error\n");
383 free(path);
384 fclose(file);
385 break;
386 }
387
388 hex2u64(vma, &section->vma);
389 sec_dso__insert_section(mod->sections, section);
390
391 free(path);
392 fclose(file);
393 count++;
394 }
395
396 closedir(dir);
397 free(line);
398 free(dir_path);
399
400 return count;
401
402out_free:
403 free(dir_path);
404
405out_failure:
406 return count;
407}
408
409static int mod_dso__load_module_paths(struct mod_dso *self)
410{
411 struct utsname uts;
412 int count = 0, len;
413 char *line = NULL;
414 FILE *file;
415 char *path;
416 size_t n;
417
418 if (uname(&uts) < 0)
419 goto out_failure;
420
421 len = strlen("/lib/modules/");
422 len += strlen(uts.release);
423 len += strlen("/modules.dep");
424
425 path = calloc(1, len);
426 if (path == NULL)
427 goto out_failure;
428
429 strcat(path, "/lib/modules/");
430 strcat(path, uts.release);
431 strcat(path, "/modules.dep");
432
433 file = fopen(path, "r");
434 free(path);
435 if (file == NULL)
436 goto out_failure;
437
438 while (!feof(file)) {
439 char *name, *tmp;
440 struct module *module;
441 int line_len;
442
443 line_len = getline(&line, &n, file);
444 if (line_len < 0)
445 break;
446
447 if (!line)
448 goto out_failure;
449
450 line[--line_len] = '\0'; /* \n */
451
452 path = strtok(line, ":");
453 if (!path)
454 goto out_failure;
455
456 name = strdup(path);
457 name = strtok(name, "/");
458
459 tmp = name;
460
461 while (tmp) {
462 tmp = strtok(NULL, "/");
463 if (tmp)
464 name = tmp;
465 }
466 name = strsep(&name, ".");
467
468 /* Quirk: replace '-' with '_' in sound modules */
469 for (len = strlen(name); len; len--) {
470 if (*(name+len) == '-')
471 *(name+len) = '_';
472 }
473
474 module = module__new(name, path);
475 if (!module) {
476 fprintf(stderr, "load_module_paths: allocation error\n");
477 goto out_failure;
478 }
479 mod_dso__insert_module(self, module);
480
481 module->sections = sec_dso__new_dso("sections");
482 if (!module->sections) {
483 fprintf(stderr, "load_module_paths: allocation error\n");
484 goto out_failure;
485 }
486
487 module->active = mod_dso__load_sections(module);
488
489 if (module->active > 0)
490 count++;
491 }
492
493 free(line);
494 fclose(file);
495
496 return count;
497
498out_failure:
499 return -1;
500}
501
502int mod_dso__load_modules(struct mod_dso *dso)
503{
504 int err;
505
506 err = mod_dso__load_module_paths(dso);
507
508 return err;
509}
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..a587d41ae3c9 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,47 +1,44 @@
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);
10 9
11int nr_counters; 10int nr_counters;
12 11
13struct perf_counter_attr attrs[MAX_COUNTERS]; 12struct perf_counter_attr attrs[MAX_COUNTERS];
14 13
15struct event_symbol { 14struct event_symbol {
16 u8 type; 15 u8 type;
17 u64 config; 16 u64 config;
18 char *symbol; 17 const char *symbol;
18 const char *alias;
19}; 19};
20 20
21#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y 21char debugfs_path[MAXPATHLEN];
22#define CR(x, y) .type = PERF_TYPE_##x, .config = y 22
23#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
24#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
23 25
24static struct event_symbol event_symbols[] = { 26static struct event_symbol event_symbols[] = {
25 { C(HARDWARE, HW_CPU_CYCLES), "cpu-cycles", }, 27 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
26 { C(HARDWARE, HW_CPU_CYCLES), "cycles", }, 28 { CHW(INSTRUCTIONS), "instructions", "" },
27 { C(HARDWARE, HW_INSTRUCTIONS), "instructions", }, 29 { CHW(CACHE_REFERENCES), "cache-references", "" },
28 { C(HARDWARE, HW_CACHE_REFERENCES), "cache-references", }, 30 { CHW(CACHE_MISSES), "cache-misses", "" },
29 { C(HARDWARE, HW_CACHE_MISSES), "cache-misses", }, 31 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
30 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", }, 32 { CHW(BRANCH_MISSES), "branch-misses", "" },
31 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches", }, 33 { CHW(BUS_CYCLES), "bus-cycles", "" },
32 { C(HARDWARE, HW_BRANCH_MISSES), "branch-misses", }, 34
33 { C(HARDWARE, HW_BUS_CYCLES), "bus-cycles", }, 35 { CSW(CPU_CLOCK), "cpu-clock", "" },
34 36 { CSW(TASK_CLOCK), "task-clock", "" },
35 { C(SOFTWARE, SW_CPU_CLOCK), "cpu-clock", }, 37 { CSW(PAGE_FAULTS), "page-faults", "faults" },
36 { C(SOFTWARE, SW_TASK_CLOCK), "task-clock", }, 38 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
37 { C(SOFTWARE, SW_PAGE_FAULTS), "page-faults", }, 39 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
38 { C(SOFTWARE, SW_PAGE_FAULTS), "faults", }, 40 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
39 { C(SOFTWARE, SW_PAGE_FAULTS_MIN), "minor-faults", }, 41 { 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}; 42};
46 43
47#define __PERF_COUNTER_FIELD(config, name) \ 44#define __PERF_COUNTER_FIELD(config, name) \
@@ -52,7 +49,7 @@ static struct event_symbol event_symbols[] = {
52#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) 49#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
53#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) 50#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
54 51
55static char *hw_event_names[] = { 52static const char *hw_event_names[] = {
56 "cycles", 53 "cycles",
57 "instructions", 54 "instructions",
58 "cache-references", 55 "cache-references",
@@ -62,7 +59,7 @@ static char *hw_event_names[] = {
62 "bus-cycles", 59 "bus-cycles",
63}; 60};
64 61
65static char *sw_event_names[] = { 62static const char *sw_event_names[] = {
66 "cpu-clock-msecs", 63 "cpu-clock-msecs",
67 "task-clock-msecs", 64 "task-clock-msecs",
68 "page-faults", 65 "page-faults",
@@ -74,33 +71,213 @@ static char *sw_event_names[] = {
74 71
75#define MAX_ALIASES 8 72#define MAX_ALIASES 8
76 73
77static char *hw_cache [][MAX_ALIASES] = { 74static const char *hw_cache[][MAX_ALIASES] = {
78 { "L1-data" , "l1-d", "l1d" }, 75 { "L1-dcache", "l1-d", "l1d", "L1-data", },
79 { "L1-instruction" , "l1-i", "l1i" }, 76 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
80 { "L2" , "l2" }, 77 { "LLC", "L2" },
81 { "Data-TLB" , "dtlb", "d-tlb" }, 78 { "dTLB", "d-tlb", "Data-TLB", },
82 { "Instruction-TLB" , "itlb", "i-tlb" }, 79 { "iTLB", "i-tlb", "Instruction-TLB", },
83 { "Branch" , "bpu" , "btb", "bpc" }, 80 { "branch", "branches", "bpu", "btb", "bpc", },
84}; 81};
85 82
86static char *hw_cache_op [][MAX_ALIASES] = { 83static const char *hw_cache_op[][MAX_ALIASES] = {
87 { "Load" , "read" }, 84 { "load", "loads", "read", },
88 { "Store" , "write" }, 85 { "store", "stores", "write", },
89 { "Prefetch" , "speculative-read", "speculative-load" }, 86 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
90}; 87};
91 88
92static char *hw_cache_result [][MAX_ALIASES] = { 89static const char *hw_cache_result[][MAX_ALIASES] = {
93 { "Reference" , "ops", "access" }, 90 { "refs", "Reference", "ops", "access", },
94 { "Miss" }, 91 { "misses", "miss", },
92};
93
94#define C(x) PERF_COUNT_HW_CACHE_##x
95#define CACHE_READ (1 << C(OP_READ))
96#define CACHE_WRITE (1 << C(OP_WRITE))
97#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
98#define COP(x) (1 << x)
99
100/*
101 * cache operartion stat
102 * L1I : Read and prefetch only
103 * ITLB and BPU : Read-only
104 */
105static unsigned long hw_cache_stat[C(MAX)] = {
106 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
107 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
108 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
109 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
110 [C(ITLB)] = (CACHE_READ),
111 [C(BPU)] = (CACHE_READ),
95}; 112};
96 113
97char *event_name(int counter) 114#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
115 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
116 if (sys_dirent.d_type == DT_DIR && \
117 (strcmp(sys_dirent.d_name, ".")) && \
118 (strcmp(sys_dirent.d_name, "..")))
119
120static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
121{
122 char evt_path[MAXPATHLEN];
123 int fd;
124
125 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
126 sys_dir->d_name, evt_dir->d_name);
127 fd = open(evt_path, O_RDONLY);
128 if (fd < 0)
129 return -EINVAL;
130 close(fd);
131
132 return 0;
133}
134
135#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \
136 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
137 if (evt_dirent.d_type == DT_DIR && \
138 (strcmp(evt_dirent.d_name, ".")) && \
139 (strcmp(evt_dirent.d_name, "..")) && \
140 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
141
142#define MAX_EVENT_LENGTH 30
143
144int valid_debugfs_mount(const char *debugfs)
145{
146 struct statfs st_fs;
147
148 if (statfs(debugfs, &st_fs) < 0)
149 return -ENOENT;
150 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
151 return -ENOENT;
152 return 0;
153}
154
155struct tracepoint_path *tracepoint_id_to_path(u64 config)
156{
157 struct tracepoint_path *path = NULL;
158 DIR *sys_dir, *evt_dir;
159 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
160 char id_buf[4];
161 int sys_dir_fd, fd;
162 u64 id;
163 char evt_path[MAXPATHLEN];
164
165 if (valid_debugfs_mount(debugfs_path))
166 return NULL;
167
168 sys_dir = opendir(debugfs_path);
169 if (!sys_dir)
170 goto cleanup;
171 sys_dir_fd = dirfd(sys_dir);
172
173 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
174 int dfd = openat(sys_dir_fd, sys_dirent.d_name,
175 O_RDONLY|O_DIRECTORY), evt_dir_fd;
176 if (dfd == -1)
177 continue;
178 evt_dir = fdopendir(dfd);
179 if (!evt_dir) {
180 close(dfd);
181 continue;
182 }
183 evt_dir_fd = dirfd(evt_dir);
184 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
185 snprintf(evt_path, MAXPATHLEN, "%s/id",
186 evt_dirent.d_name);
187 fd = openat(evt_dir_fd, evt_path, O_RDONLY);
188 if (fd < 0)
189 continue;
190 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
191 close(fd);
192 continue;
193 }
194 close(fd);
195 id = atoll(id_buf);
196 if (id == config) {
197 closedir(evt_dir);
198 closedir(sys_dir);
199 path = calloc(1, sizeof(path));
200 path->system = malloc(MAX_EVENT_LENGTH);
201 if (!path->system) {
202 free(path);
203 return NULL;
204 }
205 path->name = malloc(MAX_EVENT_LENGTH);
206 if (!path->name) {
207 free(path->system);
208 free(path);
209 return NULL;
210 }
211 strncpy(path->system, sys_dirent.d_name,
212 MAX_EVENT_LENGTH);
213 strncpy(path->name, evt_dirent.d_name,
214 MAX_EVENT_LENGTH);
215 return path;
216 }
217 }
218 closedir(evt_dir);
219 }
220
221cleanup:
222 closedir(sys_dir);
223 return NULL;
224}
225
226#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
227static const char *tracepoint_id_to_name(u64 config)
228{
229 static char buf[TP_PATH_LEN];
230 struct tracepoint_path *path;
231
232 path = tracepoint_id_to_path(config);
233 if (path) {
234 snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
235 free(path->name);
236 free(path->system);
237 free(path);
238 } else
239 snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
240
241 return buf;
242}
243
244static int is_cache_op_valid(u8 cache_type, u8 cache_op)
245{
246 if (hw_cache_stat[cache_type] & COP(cache_op))
247 return 1; /* valid */
248 else
249 return 0; /* invalid */
250}
251
252static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
253{
254 static char name[50];
255
256 if (cache_result) {
257 sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
258 hw_cache_op[cache_op][0],
259 hw_cache_result[cache_result][0]);
260 } else {
261 sprintf(name, "%s-%s", hw_cache[cache_type][0],
262 hw_cache_op[cache_op][1]);
263 }
264
265 return name;
266}
267
268const char *event_name(int counter)
98{ 269{
99 u64 config = attrs[counter].config; 270 u64 config = attrs[counter].config;
100 int type = attrs[counter].type; 271 int type = attrs[counter].type;
272
273 return __event_name(type, config);
274}
275
276const char *__event_name(int type, u64 config)
277{
101 static char buf[32]; 278 static char buf[32];
102 279
103 if (attrs[counter].type == PERF_TYPE_RAW) { 280 if (type == PERF_TYPE_RAW) {
104 sprintf(buf, "raw 0x%llx", config); 281 sprintf(buf, "raw 0x%llx", config);
105 return buf; 282 return buf;
106 } 283 }
@@ -113,7 +290,6 @@ char *event_name(int counter)
113 290
114 case PERF_TYPE_HW_CACHE: { 291 case PERF_TYPE_HW_CACHE: {
115 u8 cache_type, cache_op, cache_result; 292 u8 cache_type, cache_op, cache_result;
116 static char name[100];
117 293
118 cache_type = (config >> 0) & 0xff; 294 cache_type = (config >> 0) & 0xff;
119 if (cache_type > PERF_COUNT_HW_CACHE_MAX) 295 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
@@ -127,12 +303,10 @@ char *event_name(int counter)
127 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX) 303 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
128 return "unknown-ext-hardware-cache-result"; 304 return "unknown-ext-hardware-cache-result";
129 305
130 sprintf(name, "%s-Cache-%s-%ses", 306 if (!is_cache_op_valid(cache_type, cache_op))
131 hw_cache[cache_type][0], 307 return "invalid-cache";
132 hw_cache_op[cache_op][0],
133 hw_cache_result[cache_result][0]);
134 308
135 return name; 309 return event_cache_name(cache_type, cache_op, cache_result);
136 } 310 }
137 311
138 case PERF_TYPE_SOFTWARE: 312 case PERF_TYPE_SOFTWARE:
@@ -140,6 +314,9 @@ char *event_name(int counter)
140 return sw_event_names[config]; 314 return sw_event_names[config];
141 return "unknown-software"; 315 return "unknown-software";
142 316
317 case PERF_TYPE_TRACEPOINT:
318 return tracepoint_id_to_name(config);
319
143 default: 320 default:
144 break; 321 break;
145 } 322 }
@@ -147,43 +324,74 @@ char *event_name(int counter)
147 return "unknown"; 324 return "unknown";
148} 325}
149 326
150static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) 327static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
151{ 328{
152 int i, j; 329 int i, j;
330 int n, longest = -1;
153 331
154 for (i = 0; i < size; i++) { 332 for (i = 0; i < size; i++) {
155 for (j = 0; j < MAX_ALIASES; j++) { 333 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
156 if (!names[i][j]) 334 n = strlen(names[i][j]);
157 break; 335 if (n > longest && !strncasecmp(*str, names[i][j], n))
158 if (strcasestr(str, names[i][j])) 336 longest = n;
159 return i; 337 }
338 if (longest > 0) {
339 *str += longest;
340 return i;
160 } 341 }
161 } 342 }
162 343
163 return -1; 344 return -1;
164} 345}
165 346
166static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) 347static int
348parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
167{ 349{
168 int cache_type = -1, cache_op = 0, cache_result = 0; 350 const char *s = *str;
351 int cache_type = -1, cache_op = -1, cache_result = -1;
169 352
170 cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); 353 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
171 /* 354 /*
172 * No fallback - if we cannot get a clear cache type 355 * No fallback - if we cannot get a clear cache type
173 * then bail out: 356 * then bail out:
174 */ 357 */
175 if (cache_type == -1) 358 if (cache_type == -1)
176 return -EINVAL; 359 return 0;
360
361 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
362 ++s;
363
364 if (cache_op == -1) {
365 cache_op = parse_aliases(&s, hw_cache_op,
366 PERF_COUNT_HW_CACHE_OP_MAX);
367 if (cache_op >= 0) {
368 if (!is_cache_op_valid(cache_type, cache_op))
369 return 0;
370 continue;
371 }
372 }
373
374 if (cache_result == -1) {
375 cache_result = parse_aliases(&s, hw_cache_result,
376 PERF_COUNT_HW_CACHE_RESULT_MAX);
377 if (cache_result >= 0)
378 continue;
379 }
380
381 /*
382 * Can't parse this as a cache op or result, so back up
383 * to the '-'.
384 */
385 --s;
386 break;
387 }
177 388
178 cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
179 /* 389 /*
180 * Fall back to reads: 390 * Fall back to reads:
181 */ 391 */
182 if (cache_op == -1) 392 if (cache_op == -1)
183 cache_op = PERF_COUNT_HW_CACHE_OP_READ; 393 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
184 394
185 cache_result = parse_aliases(str, hw_cache_result,
186 PERF_COUNT_HW_CACHE_RESULT_MAX);
187 /* 395 /*
188 * Fall back to accesses: 396 * Fall back to accesses:
189 */ 397 */
@@ -193,82 +401,212 @@ 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); 401 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
194 attr->type = PERF_TYPE_HW_CACHE; 402 attr->type = PERF_TYPE_HW_CACHE;
195 403
196 return 0; 404 *str = s;
405 return 1;
197} 406}
198 407
199/* 408static int parse_tracepoint_event(const char **strp,
200 * Each event can have multiple symbolic names. 409 struct perf_counter_attr *attr)
201 * Symbolic names are (almost) exactly matched.
202 */
203static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
204{ 410{
205 u64 config, id; 411 const char *evt_name;
206 int type; 412 char *flags;
207 unsigned int i; 413 char sys_name[MAX_EVENT_LENGTH];
208 const char *sep, *pstr; 414 char id_buf[4];
415 int fd;
416 unsigned int sys_length, evt_length;
417 u64 id;
418 char evt_path[MAXPATHLEN];
419
420 if (valid_debugfs_mount(debugfs_path))
421 return 0;
209 422
210 if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { 423 evt_name = strchr(*strp, ':');
211 attr->type = PERF_TYPE_RAW; 424 if (!evt_name)
212 attr->config = config; 425 return 0;
213 426
427 sys_length = evt_name - *strp;
428 if (sys_length >= MAX_EVENT_LENGTH)
214 return 0; 429 return 0;
430
431 strncpy(sys_name, *strp, sys_length);
432 sys_name[sys_length] = '\0';
433 evt_name = evt_name + 1;
434
435 flags = strchr(evt_name, ':');
436 if (flags) {
437 *flags = '\0';
438 flags++;
439 if (!strncmp(flags, "record", strlen(flags)))
440 attr->sample_type |= PERF_SAMPLE_RAW;
215 } 441 }
216 442
217 pstr = str; 443 evt_length = strlen(evt_name);
218 sep = strchr(pstr, ':'); 444 if (evt_length >= MAX_EVENT_LENGTH)
219 if (sep) { 445 return 0;
220 type = atoi(pstr); 446
221 pstr = sep + 1; 447 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
222 id = atoi(pstr); 448 sys_name, evt_name);
223 sep = strchr(pstr, ':'); 449 fd = open(evt_path, O_RDONLY);
224 if (sep) { 450 if (fd < 0)
225 pstr = sep + 1; 451 return 0;
226 if (strchr(pstr, 'k'))
227 attr->exclude_user = 1;
228 if (strchr(pstr, 'u'))
229 attr->exclude_kernel = 1;
230 }
231 attr->type = type;
232 attr->config = id;
233 452
453 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
454 close(fd);
234 return 0; 455 return 0;
235 } 456 }
457 close(fd);
458 id = atoll(id_buf);
459 attr->config = id;
460 attr->type = PERF_TYPE_TRACEPOINT;
461 *strp = evt_name + evt_length;
462 return 1;
463}
236 464
237 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 465static int check_events(const char *str, unsigned int i)
238 if (!strncmp(str, event_symbols[i].symbol, 466{
239 strlen(event_symbols[i].symbol))) { 467 int n;
468
469 n = strlen(event_symbols[i].symbol);
470 if (!strncmp(str, event_symbols[i].symbol, n))
471 return n;
472
473 n = strlen(event_symbols[i].alias);
474 if (n)
475 if (!strncmp(str, event_symbols[i].alias, n))
476 return n;
477 return 0;
478}
479
480static int
481parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
482{
483 const char *str = *strp;
484 unsigned int i;
485 int n;
240 486
487 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
488 n = check_events(str, i);
489 if (n > 0) {
241 attr->type = event_symbols[i].type; 490 attr->type = event_symbols[i].type;
242 attr->config = event_symbols[i].config; 491 attr->config = event_symbols[i].config;
492 *strp = str + n;
493 return 1;
494 }
495 }
496 return 0;
497}
498
499static int parse_raw_event(const char **strp, struct perf_counter_attr *attr)
500{
501 const char *str = *strp;
502 u64 config;
503 int n;
243 504
244 return 0; 505 if (*str != 'r')
506 return 0;
507 n = hex2u64(str + 1, &config);
508 if (n > 0) {
509 *strp = str + n + 1;
510 attr->type = PERF_TYPE_RAW;
511 attr->config = config;
512 return 1;
513 }
514 return 0;
515}
516
517static int
518parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
519{
520 const char *str = *strp;
521 char *endp;
522 unsigned long type;
523 u64 config;
524
525 type = strtoul(str, &endp, 0);
526 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
527 str = endp + 1;
528 config = strtoul(str, &endp, 0);
529 if (endp > str) {
530 attr->type = type;
531 attr->config = config;
532 *strp = endp;
533 return 1;
245 } 534 }
246 } 535 }
536 return 0;
537}
538
539static int
540parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
541{
542 const char *str = *strp;
543 int eu = 1, ek = 1, eh = 1;
544
545 if (*str++ != ':')
546 return 0;
547 while (*str) {
548 if (*str == 'u')
549 eu = 0;
550 else if (*str == 'k')
551 ek = 0;
552 else if (*str == 'h')
553 eh = 0;
554 else
555 break;
556 ++str;
557 }
558 if (str >= *strp + 2) {
559 *strp = str;
560 attr->exclude_user = eu;
561 attr->exclude_kernel = ek;
562 attr->exclude_hv = eh;
563 return 1;
564 }
565 return 0;
566}
567
568/*
569 * Each event can have multiple symbolic names.
570 * Symbolic names are (almost) exactly matched.
571 */
572static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
573{
574 if (!(parse_tracepoint_event(str, attr) ||
575 parse_raw_event(str, attr) ||
576 parse_numeric_event(str, attr) ||
577 parse_symbolic_event(str, attr) ||
578 parse_generic_hw_event(str, attr)))
579 return 0;
247 580
248 return parse_generic_hw_symbols(str, attr); 581 parse_event_modifier(str, attr);
582
583 return 1;
249} 584}
250 585
251int parse_events(const struct option *opt, const char *str, int unset) 586int parse_events(const struct option *opt __used, const char *str, int unset __used)
252{ 587{
253 struct perf_counter_attr attr; 588 struct perf_counter_attr attr;
254 int ret;
255 589
256 memset(&attr, 0, sizeof(attr)); 590 for (;;) {
257again: 591 if (nr_counters == MAX_COUNTERS)
258 if (nr_counters == MAX_COUNTERS) 592 return -1;
259 return -1; 593
594 memset(&attr, 0, sizeof(attr));
595 if (!parse_event_symbols(&str, &attr))
596 return -1;
260 597
261 ret = parse_event_symbols(str, &attr); 598 if (!(*str == 0 || *str == ',' || isspace(*str)))
262 if (ret < 0) 599 return -1;
263 return ret;
264 600
265 attrs[nr_counters] = attr; 601 attrs[nr_counters] = attr;
266 nr_counters++; 602 nr_counters++;
267 603
268 str = strstr(str, ","); 604 if (*str == 0)
269 if (str) { 605 break;
270 str++; 606 if (*str == ',')
271 goto again; 607 ++str;
608 while (isspace(*str))
609 ++str;
272 } 610 }
273 611
274 return 0; 612 return 0;
@@ -283,34 +621,99 @@ static const char * const event_type_descriptors[] = {
283}; 621};
284 622
285/* 623/*
624 * Print the events from <debugfs_mount_point>/tracing/events
625 */
626
627static void print_tracepoint_events(void)
628{
629 DIR *sys_dir, *evt_dir;
630 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
631 int sys_dir_fd;
632 char evt_path[MAXPATHLEN];
633
634 if (valid_debugfs_mount(debugfs_path))
635 return;
636
637 sys_dir = opendir(debugfs_path);
638 if (!sys_dir)
639 goto cleanup;
640 sys_dir_fd = dirfd(sys_dir);
641
642 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
643 int dfd = openat(sys_dir_fd, sys_dirent.d_name,
644 O_RDONLY|O_DIRECTORY), evt_dir_fd;
645 if (dfd == -1)
646 continue;
647 evt_dir = fdopendir(dfd);
648 if (!evt_dir) {
649 close(dfd);
650 continue;
651 }
652 evt_dir_fd = dirfd(evt_dir);
653 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
654 snprintf(evt_path, MAXPATHLEN, "%s:%s",
655 sys_dirent.d_name, evt_dirent.d_name);
656 fprintf(stderr, " %-42s [%s]\n", evt_path,
657 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
658 }
659 closedir(evt_dir);
660 }
661
662cleanup:
663 closedir(sys_dir);
664}
665
666/*
286 * Print the help text for the event symbols: 667 * Print the help text for the event symbols:
287 */ 668 */
288void print_events(void) 669void print_events(void)
289{ 670{
290 struct event_symbol *syms = event_symbols; 671 struct event_symbol *syms = event_symbols;
291 unsigned int i, type, prev_type = -1; 672 unsigned int i, type, op, prev_type = -1;
673 char name[40];
292 674
293 fprintf(stderr, "\n"); 675 fprintf(stderr, "\n");
294 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 676 fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
295 677
296 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 678 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
297 type = syms->type + 1; 679 type = syms->type + 1;
298 if (type > ARRAY_SIZE(event_type_descriptors)) 680 if (type >= ARRAY_SIZE(event_type_descriptors))
299 type = 0; 681 type = 0;
300 682
301 if (type != prev_type) 683 if (type != prev_type)
302 fprintf(stderr, "\n"); 684 fprintf(stderr, "\n");
303 685
304 fprintf(stderr, " %-30s [%s]\n", syms->symbol, 686 if (strlen(syms->alias))
687 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
688 else
689 strcpy(name, syms->symbol);
690 fprintf(stderr, " %-42s [%s]\n", name,
305 event_type_descriptors[type]); 691 event_type_descriptors[type]);
306 692
307 prev_type = type; 693 prev_type = type;
308 } 694 }
309 695
310 fprintf(stderr, "\n"); 696 fprintf(stderr, "\n");
311 fprintf(stderr, " %-30s [raw hardware event descriptor]\n", 697 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
698 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
699 /* skip invalid cache type */
700 if (!is_cache_op_valid(type, op))
701 continue;
702
703 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
704 fprintf(stderr, " %-42s [%s]\n",
705 event_cache_name(type, op, i),
706 event_type_descriptors[4]);
707 }
708 }
709 }
710
711 fprintf(stderr, "\n");
712 fprintf(stderr, " %-42s [raw hardware event descriptor]\n",
312 "rNNN"); 713 "rNNN");
313 fprintf(stderr, "\n"); 714 fprintf(stderr, "\n");
314 715
716 print_tracepoint_events();
717
315 exit(129); 718 exit(129);
316} 719}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index e3d552908e60..60704c15961f 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_counter_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..8aa3464c7090 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -90,21 +90,22 @@ 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_DEFAULT(s, l, v, a, h, f, d) \
108 { .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 109
109/* parse_options() will filter out the processed options and leave the 110/* parse_options() will filter out the processed options and leave the
110 * non-option argments in argv[]. 111 * 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/symbol.c b/tools/perf/util/symbol.c
index 86e14375e74e..fd3d9c8e90fc 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)
665{
666 int i;
667 GElf_Ehdr ehdr;
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)
562{ 722{
563 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 723 static const char origin[] = {
564 char *name = malloc(size); 724 [DSO__ORIG_KERNEL] = 'k',
565 int variant = 0; 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,233 @@ 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;
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 }
856
857 if (err < 0) {
858 mod_dso__delete_modules(mods);
859 mod_dso__delete_self(mods);
860 }
861
862 return err;
863}
864
865static inline void dso__fill_symbol_holes(struct dso *self)
866{
867 struct symbol *prev = NULL;
868 struct rb_node *nd;
869
870 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
871 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
872
873 if (prev) {
874 u64 hole = 0;
875 int alias = pos->start == prev->start;
876
877 if (!alias)
878 hole = prev->start - pos->end - 1;
879
880 if (hole || alias) {
881 if (alias)
882 pos->end = prev->end;
883 else if (hole)
884 pos->end = prev->start - 1;
885 }
886 }
887 prev = pos;
888 }
889}
890
610static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 891static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
611 symbol_filter_t filter, int verbose) 892 symbol_filter_t filter, int v)
612{ 893{
613 int err, fd = open(vmlinux, O_RDONLY); 894 int err, fd = open(vmlinux, O_RDONLY);
614 895
615 if (fd < 0) 896 if (fd < 0)
616 return -1; 897 return -1;
617 898
618 err = dso__load_sym(self, fd, vmlinux, filter, verbose); 899 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
900
901 if (err > 0)
902 dso__fill_symbol_holes(self);
903
619 close(fd); 904 close(fd);
620 905
621 return err; 906 return err;
622} 907}
623 908
624int dso__load_kernel(struct dso *self, const char *vmlinux, 909int dso__load_kernel(struct dso *self, const char *vmlinux,
625 symbol_filter_t filter, int verbose) 910 symbol_filter_t filter, int v, int use_modules)
626{ 911{
627 int err = -1; 912 int err = -1;
628 913
629 if (vmlinux) 914 if (vmlinux) {
630 err = dso__load_vmlinux(self, vmlinux, filter, verbose); 915 err = dso__load_vmlinux(self, vmlinux, filter, v);
916 if (err > 0 && use_modules)
917 err = dso__load_modules(self, filter, v);
918 }
631 919
632 if (err) 920 if (err <= 0)
633 err = dso__load_kallsyms(self, filter, verbose); 921 err = dso__load_kallsyms(self, filter, v);
922
923 if (err > 0)
924 self->origin = DSO__ORIG_KERNEL;
634 925
635 return err; 926 return err;
636} 927}
637 928
929LIST_HEAD(dsos);
930struct dso *kernel_dso;
931struct dso *vdso;
932struct dso *hypervisor_dso;
933
934const char *vmlinux_name = "vmlinux";
935int modules;
936
937static void dsos__add(struct dso *dso)
938{
939 list_add_tail(&dso->node, &dsos);
940}
941
942static struct dso *dsos__find(const char *name)
943{
944 struct dso *pos;
945
946 list_for_each_entry(pos, &dsos, node)
947 if (strcmp(pos->name, name) == 0)
948 return pos;
949 return NULL;
950}
951
952struct dso *dsos__findnew(const char *name)
953{
954 struct dso *dso = dsos__find(name);
955 int nr;
956
957 if (dso)
958 return dso;
959
960 dso = dso__new(name, 0);
961 if (!dso)
962 goto out_delete_dso;
963
964 nr = dso__load(dso, NULL, verbose);
965 if (nr < 0) {
966 eprintf("Failed to open: %s\n", name);
967 goto out_delete_dso;
968 }
969 if (!nr)
970 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
971
972 dsos__add(dso);
973
974 return dso;
975
976out_delete_dso:
977 dso__delete(dso);
978 return NULL;
979}
980
981void dsos__fprintf(FILE *fp)
982{
983 struct dso *pos;
984
985 list_for_each_entry(pos, &dsos, node)
986 dso__fprintf(pos, fp);
987}
988
989static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
990{
991 return dso__find_symbol(dso, ip);
992}
993
994int load_kernel(void)
995{
996 int err;
997
998 kernel_dso = dso__new("[kernel]", 0);
999 if (!kernel_dso)
1000 return -1;
1001
1002 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
1003 if (err <= 0) {
1004 dso__delete(kernel_dso);
1005 kernel_dso = NULL;
1006 } else
1007 dsos__add(kernel_dso);
1008
1009 vdso = dso__new("[vdso]", 0);
1010 if (!vdso)
1011 return -1;
1012
1013 vdso->find_symbol = vdso__find_symbol;
1014
1015 dsos__add(vdso);
1016
1017 hypervisor_dso = dso__new("[hypervisor]", 0);
1018 if (!hypervisor_dso)
1019 return -1;
1020 dsos__add(hypervisor_dso);
1021
1022 return err;
1023}
1024
1025
638void symbol__init(void) 1026void symbol__init(void)
639{ 1027{
640 elf_version(EV_CURRENT); 1028 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..7635928ca278
--- /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 = malloc(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, "[init]")) {
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..634f2809a342
--- /dev/null
+++ b/tools/perf/util/thread.h
@@ -0,0 +1,21 @@
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 *comm;
11};
12
13int thread__set_comm(struct thread *self, const char *comm);
14struct thread *
15threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match);
16struct thread *
17register_idle_thread(struct rb_root *threads, struct thread **last_match);
18void thread__insert_map(struct thread *self, struct map *map);
19int thread__fork(struct thread *self, struct thread *parent);
20struct map *thread__find_map(struct thread *self, u64 ip);
21size_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..6c9302a7274c
--- /dev/null
+++ b/tools/perf/util/trace-event-info.c
@@ -0,0 +1,539 @@
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 const 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 return;
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);
478
479}
480
481static struct tracepoint_path *
482get_tracepoints_path(struct perf_counter_attr *pattrs, int nb_counters)
483{
484 struct tracepoint_path path, *ppath = &path;
485 int i;
486
487 for (i = 0; i < nb_counters; i++) {
488 if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
489 continue;
490 ppath->next = tracepoint_id_to_path(pattrs[i].config);
491 if (!ppath->next)
492 die("%s\n", "No memory to alloc tracepoints list");
493 ppath = ppath->next;
494 }
495
496 return path.next;
497}
498void read_tracing_data(struct perf_counter_attr *pattrs, int nb_counters)
499{
500 char buf[BUFSIZ];
501 struct tracepoint_path *tps;
502
503 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
504 if (output_fd < 0)
505 die("creating file '%s'", output_file);
506
507 buf[0] = 23;
508 buf[1] = 8;
509 buf[2] = 68;
510 memcpy(buf + 3, "tracing", 7);
511
512 write_or_die(buf, 10);
513
514 write_or_die(VERSION, strlen(VERSION) + 1);
515
516 /* save endian */
517 if (bigendian())
518 buf[0] = 1;
519 else
520 buf[0] = 0;
521
522 write_or_die(buf, 1);
523
524 /* save size of long */
525 buf[0] = sizeof(long);
526 write_or_die(buf, 1);
527
528 /* save page_size */
529 page_size = getpagesize();
530 write_or_die(&page_size, 4);
531
532 tps = get_tracepoints_path(pattrs, nb_counters);
533
534 read_header_files();
535 read_ftrace_files(tps);
536 read_event_files(tps);
537 read_proc_kallsyms();
538 read_ftrace_printk();
539}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
new file mode 100644
index 000000000000..629e602d9405
--- /dev/null
+++ b/tools/perf/util/trace-event-parse.c
@@ -0,0 +1,2942 @@
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
1779static int get_common_info(const char *type, int *offset, int *size)
1780{
1781 struct event *event;
1782 struct format_field *field;
1783
1784 /*
1785 * All events should have the same common elements.
1786 * Pick any event to find where the type is;
1787 */
1788 if (!event_list)
1789 die("no event_list!");
1790
1791 event = event_list;
1792 field = find_common_field(event, type);
1793 if (!field)
1794 die("field '%s' not found", type);
1795
1796 *offset = field->offset;
1797 *size = field->size;
1798
1799 return 0;
1800}
1801
1802static int parse_common_type(void *data)
1803{
1804 static int type_offset;
1805 static int type_size;
1806 int ret;
1807
1808 if (!type_size) {
1809 ret = get_common_info("common_type",
1810 &type_offset,
1811 &type_size);
1812 if (ret < 0)
1813 return ret;
1814 }
1815 return read_size(data + type_offset, type_size);
1816}
1817
1818static int parse_common_pid(void *data)
1819{
1820 static int pid_offset;
1821 static int pid_size;
1822 int ret;
1823
1824 if (!pid_size) {
1825 ret = get_common_info("common_pid",
1826 &pid_offset,
1827 &pid_size);
1828 if (ret < 0)
1829 return ret;
1830 }
1831
1832 return read_size(data + pid_offset, pid_size);
1833}
1834
1835static struct event *find_event(int id)
1836{
1837 struct event *event;
1838
1839 for (event = event_list; event; event = event->next) {
1840 if (event->id == id)
1841 break;
1842 }
1843 return event;
1844}
1845
1846static unsigned long long eval_num_arg(void *data, int size,
1847 struct event *event, struct print_arg *arg)
1848{
1849 unsigned long long val = 0;
1850 unsigned long long left, right;
1851
1852 switch (arg->type) {
1853 case PRINT_NULL:
1854 /* ?? */
1855 return 0;
1856 case PRINT_ATOM:
1857 return strtoull(arg->atom.atom, NULL, 0);
1858 case PRINT_FIELD:
1859 if (!arg->field.field) {
1860 arg->field.field = find_any_field(event, arg->field.name);
1861 if (!arg->field.field)
1862 die("field %s not found", arg->field.name);
1863 }
1864 /* must be a number */
1865 val = read_size(data + arg->field.field->offset,
1866 arg->field.field->size);
1867 break;
1868 case PRINT_FLAGS:
1869 case PRINT_SYMBOL:
1870 break;
1871 case PRINT_TYPE:
1872 return eval_num_arg(data, size, event, arg->typecast.item);
1873 case PRINT_STRING:
1874 return 0;
1875 break;
1876 case PRINT_OP:
1877 left = eval_num_arg(data, size, event, arg->op.left);
1878 right = eval_num_arg(data, size, event, arg->op.right);
1879 switch (arg->op.op[0]) {
1880 case '|':
1881 if (arg->op.op[1])
1882 val = left || right;
1883 else
1884 val = left | right;
1885 break;
1886 case '&':
1887 if (arg->op.op[1])
1888 val = left && right;
1889 else
1890 val = left & right;
1891 break;
1892 case '<':
1893 switch (arg->op.op[1]) {
1894 case 0:
1895 val = left < right;
1896 break;
1897 case '<':
1898 val = left << right;
1899 break;
1900 case '=':
1901 val = left <= right;
1902 break;
1903 default:
1904 die("unknown op '%s'", arg->op.op);
1905 }
1906 break;
1907 case '>':
1908 switch (arg->op.op[1]) {
1909 case 0:
1910 val = left > right;
1911 break;
1912 case '>':
1913 val = left >> right;
1914 break;
1915 case '=':
1916 val = left >= right;
1917 break;
1918 default:
1919 die("unknown op '%s'", arg->op.op);
1920 }
1921 break;
1922 case '=':
1923 if (arg->op.op[1] != '=')
1924 die("unknown op '%s'", arg->op.op);
1925 val = left == right;
1926 break;
1927 default:
1928 die("unknown op '%s'", arg->op.op);
1929 }
1930 break;
1931 default: /* not sure what to do there */
1932 return 0;
1933 }
1934 return val;
1935}
1936
1937struct flag {
1938 const char *name;
1939 unsigned long long value;
1940};
1941
1942static const struct flag flags[] = {
1943 { "HI_SOFTIRQ", 0 },
1944 { "TIMER_SOFTIRQ", 1 },
1945 { "NET_TX_SOFTIRQ", 2 },
1946 { "NET_RX_SOFTIRQ", 3 },
1947 { "BLOCK_SOFTIRQ", 4 },
1948 { "TASKLET_SOFTIRQ", 5 },
1949 { "SCHED_SOFTIRQ", 6 },
1950 { "HRTIMER_SOFTIRQ", 7 },
1951 { "RCU_SOFTIRQ", 8 },
1952
1953 { "HRTIMER_NORESTART", 0 },
1954 { "HRTIMER_RESTART", 1 },
1955};
1956
1957static unsigned long long eval_flag(const char *flag)
1958{
1959 int i;
1960
1961 /*
1962 * Some flags in the format files do not get converted.
1963 * If the flag is not numeric, see if it is something that
1964 * we already know about.
1965 */
1966 if (isdigit(flag[0]))
1967 return strtoull(flag, NULL, 0);
1968
1969 for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
1970 if (strcmp(flags[i].name, flag) == 0)
1971 return flags[i].value;
1972
1973 return 0;
1974}
1975
1976static void print_str_arg(void *data, int size,
1977 struct event *event, struct print_arg *arg)
1978{
1979 struct print_flag_sym *flag;
1980 unsigned long long val, fval;
1981 char *str;
1982 int print;
1983
1984 switch (arg->type) {
1985 case PRINT_NULL:
1986 /* ?? */
1987 return;
1988 case PRINT_ATOM:
1989 printf("%s", arg->atom.atom);
1990 return;
1991 case PRINT_FIELD:
1992 if (!arg->field.field) {
1993 arg->field.field = find_any_field(event, arg->field.name);
1994 if (!arg->field.field)
1995 die("field %s not found", arg->field.name);
1996 }
1997 str = malloc_or_die(arg->field.field->size + 1);
1998 memcpy(str, data + arg->field.field->offset,
1999 arg->field.field->size);
2000 str[arg->field.field->size] = 0;
2001 printf("%s", str);
2002 free(str);
2003 break;
2004 case PRINT_FLAGS:
2005 val = eval_num_arg(data, size, event, arg->flags.field);
2006 print = 0;
2007 for (flag = arg->flags.flags; flag; flag = flag->next) {
2008 fval = eval_flag(flag->value);
2009 if (!val && !fval) {
2010 printf("%s", flag->str);
2011 break;
2012 }
2013 if (fval && (val & fval) == fval) {
2014 if (print && arg->flags.delim)
2015 printf("%s", arg->flags.delim);
2016 printf("%s", flag->str);
2017 print = 1;
2018 val &= ~fval;
2019 }
2020 }
2021 break;
2022 case PRINT_SYMBOL:
2023 val = eval_num_arg(data, size, event, arg->symbol.field);
2024 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
2025 fval = eval_flag(flag->value);
2026 if (val == fval) {
2027 printf("%s", flag->str);
2028 break;
2029 }
2030 }
2031 break;
2032
2033 case PRINT_TYPE:
2034 break;
2035 case PRINT_STRING: {
2036 int str_offset;
2037
2038 if (arg->string.offset == -1) {
2039 struct format_field *f;
2040
2041 f = find_any_field(event, arg->string.string);
2042 arg->string.offset = f->offset;
2043 }
2044 str_offset = *(int *)(data + arg->string.offset);
2045 str_offset &= 0xffff;
2046 printf("%s", ((char *)data) + str_offset);
2047 break;
2048 }
2049 case PRINT_OP:
2050 /*
2051 * The only op for string should be ? :
2052 */
2053 if (arg->op.op[0] != '?')
2054 return;
2055 val = eval_num_arg(data, size, event, arg->op.left);
2056 if (val)
2057 print_str_arg(data, size, event, arg->op.right->op.left);
2058 else
2059 print_str_arg(data, size, event, arg->op.right->op.right);
2060 break;
2061 default:
2062 /* well... */
2063 break;
2064 }
2065}
2066
2067static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
2068{
2069 static struct format_field *field, *ip_field;
2070 struct print_arg *args, *arg, **next;
2071 unsigned long long ip, val;
2072 char *ptr;
2073 void *bptr;
2074
2075 if (!field) {
2076 field = find_field(event, "buf");
2077 if (!field)
2078 die("can't find buffer field for binary printk");
2079 ip_field = find_field(event, "ip");
2080 if (!ip_field)
2081 die("can't find ip field for binary printk");
2082 }
2083
2084 ip = read_size(data + ip_field->offset, ip_field->size);
2085
2086 /*
2087 * The first arg is the IP pointer.
2088 */
2089 args = malloc_or_die(sizeof(*args));
2090 arg = args;
2091 arg->next = NULL;
2092 next = &arg->next;
2093
2094 arg->type = PRINT_ATOM;
2095 arg->atom.atom = malloc_or_die(32);
2096 sprintf(arg->atom.atom, "%lld", ip);
2097
2098 /* skip the first "%pf : " */
2099 for (ptr = fmt + 6, bptr = data + field->offset;
2100 bptr < data + size && *ptr; ptr++) {
2101 int ls = 0;
2102
2103 if (*ptr == '%') {
2104 process_again:
2105 ptr++;
2106 switch (*ptr) {
2107 case '%':
2108 break;
2109 case 'l':
2110 ls++;
2111 goto process_again;
2112 case 'L':
2113 ls = 2;
2114 goto process_again;
2115 case '0' ... '9':
2116 goto process_again;
2117 case 'p':
2118 ls = 1;
2119 /* fall through */
2120 case 'd':
2121 case 'u':
2122 case 'x':
2123 case 'i':
2124 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) &
2125 ~(long_size - 1));
2126 switch (ls) {
2127 case 0:
2128 case 1:
2129 ls = long_size;
2130 break;
2131 case 2:
2132 ls = 8;
2133 default:
2134 break;
2135 }
2136 val = read_size(bptr, ls);
2137 bptr += ls;
2138 arg = malloc_or_die(sizeof(*arg));
2139 arg->next = NULL;
2140 arg->type = PRINT_ATOM;
2141 arg->atom.atom = malloc_or_die(32);
2142 sprintf(arg->atom.atom, "%lld", val);
2143 *next = arg;
2144 next = &arg->next;
2145 break;
2146 case 's':
2147 arg = malloc_or_die(sizeof(*arg));
2148 arg->next = NULL;
2149 arg->type = PRINT_STRING;
2150 arg->string.string = strdup(bptr);
2151 bptr += strlen(bptr) + 1;
2152 *next = arg;
2153 next = &arg->next;
2154 default:
2155 break;
2156 }
2157 }
2158 }
2159
2160 return args;
2161}
2162
2163static void free_args(struct print_arg *args)
2164{
2165 struct print_arg *next;
2166
2167 while (args) {
2168 next = args->next;
2169
2170 if (args->type == PRINT_ATOM)
2171 free(args->atom.atom);
2172 else
2173 free(args->string.string);
2174 free(args);
2175 args = next;
2176 }
2177}
2178
2179static char *get_bprint_format(void *data, int size __unused, struct event *event)
2180{
2181 unsigned long long addr;
2182 static struct format_field *field;
2183 struct printk_map *printk;
2184 char *format;
2185 char *p;
2186
2187 if (!field) {
2188 field = find_field(event, "fmt");
2189 if (!field)
2190 die("can't find format field for binary printk");
2191 printf("field->offset = %d size=%d\n", field->offset, field->size);
2192 }
2193
2194 addr = read_size(data + field->offset, field->size);
2195
2196 printk = find_printk(addr);
2197 if (!printk) {
2198 format = malloc_or_die(45);
2199 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
2200 addr);
2201 return format;
2202 }
2203
2204 p = printk->printk;
2205 /* Remove any quotes. */
2206 if (*p == '"')
2207 p++;
2208 format = malloc_or_die(strlen(p) + 10);
2209 sprintf(format, "%s : %s", "%pf", p);
2210 /* remove ending quotes and new line since we will add one too */
2211 p = format + strlen(format) - 1;
2212 if (*p == '"')
2213 *p = 0;
2214
2215 p -= 2;
2216 if (strcmp(p, "\\n") == 0)
2217 *p = 0;
2218
2219 return format;
2220}
2221
2222static void pretty_print(void *data, int size, struct event *event)
2223{
2224 struct print_fmt *print_fmt = &event->print_fmt;
2225 struct print_arg *arg = print_fmt->args;
2226 struct print_arg *args = NULL;
2227 const char *ptr = print_fmt->format;
2228 unsigned long long val;
2229 struct func_map *func;
2230 const char *saveptr;
2231 char *bprint_fmt = NULL;
2232 char format[32];
2233 int show_func;
2234 int len;
2235 int ls;
2236
2237 if (event->flags & EVENT_FL_ISFUNC)
2238 ptr = " %pF <-- %pF";
2239
2240 if (event->flags & EVENT_FL_ISBPRINT) {
2241 bprint_fmt = get_bprint_format(data, size, event);
2242 args = make_bprint_args(bprint_fmt, data, size, event);
2243 arg = args;
2244 ptr = bprint_fmt;
2245 }
2246
2247 for (; *ptr; ptr++) {
2248 ls = 0;
2249 if (*ptr == '%') {
2250 saveptr = ptr;
2251 show_func = 0;
2252 cont_process:
2253 ptr++;
2254 switch (*ptr) {
2255 case '%':
2256 printf("%%");
2257 break;
2258 case 'l':
2259 ls++;
2260 goto cont_process;
2261 case 'L':
2262 ls = 2;
2263 goto cont_process;
2264 case 'z':
2265 case 'Z':
2266 case '0' ... '9':
2267 goto cont_process;
2268 case 'p':
2269 if (long_size == 4)
2270 ls = 1;
2271 else
2272 ls = 2;
2273
2274 if (*(ptr+1) == 'F' ||
2275 *(ptr+1) == 'f') {
2276 ptr++;
2277 show_func = *ptr;
2278 }
2279
2280 /* fall through */
2281 case 'd':
2282 case 'i':
2283 case 'x':
2284 case 'X':
2285 case 'u':
2286 if (!arg)
2287 die("no argument match");
2288
2289 len = ((unsigned long)ptr + 1) -
2290 (unsigned long)saveptr;
2291
2292 /* should never happen */
2293 if (len > 32)
2294 die("bad format!");
2295
2296 memcpy(format, saveptr, len);
2297 format[len] = 0;
2298
2299 val = eval_num_arg(data, size, event, arg);
2300 arg = arg->next;
2301
2302 if (show_func) {
2303 func = find_func(val);
2304 if (func) {
2305 printf("%s", func->func);
2306 if (show_func == 'F')
2307 printf("+0x%llx",
2308 val - func->addr);
2309 break;
2310 }
2311 }
2312 switch (ls) {
2313 case 0:
2314 printf(format, (int)val);
2315 break;
2316 case 1:
2317 printf(format, (long)val);
2318 break;
2319 case 2:
2320 printf(format, (long long)val);
2321 break;
2322 default:
2323 die("bad count (%d)", ls);
2324 }
2325 break;
2326 case 's':
2327 if (!arg)
2328 die("no matching argument");
2329
2330 print_str_arg(data, size, event, arg);
2331 arg = arg->next;
2332 break;
2333 default:
2334 printf(">%c<", *ptr);
2335
2336 }
2337 } else
2338 printf("%c", *ptr);
2339 }
2340
2341 if (args) {
2342 free_args(args);
2343 free(bprint_fmt);
2344 }
2345}
2346
2347static inline int log10_cpu(int nb)
2348{
2349 if (nb / 100)
2350 return 3;
2351 if (nb / 10)
2352 return 2;
2353 return 1;
2354}
2355
2356/* taken from Linux, written by Frederic Weisbecker */
2357static void print_graph_cpu(int cpu)
2358{
2359 int i;
2360 int log10_this = log10_cpu(cpu);
2361 int log10_all = log10_cpu(cpus);
2362
2363
2364 /*
2365 * Start with a space character - to make it stand out
2366 * to the right a bit when trace output is pasted into
2367 * email:
2368 */
2369 printf(" ");
2370
2371 /*
2372 * Tricky - we space the CPU field according to the max
2373 * number of online CPUs. On a 2-cpu system it would take
2374 * a maximum of 1 digit - on a 128 cpu system it would
2375 * take up to 3 digits:
2376 */
2377 for (i = 0; i < log10_all - log10_this; i++)
2378 printf(" ");
2379
2380 printf("%d) ", cpu);
2381}
2382
2383#define TRACE_GRAPH_PROCINFO_LENGTH 14
2384#define TRACE_GRAPH_INDENT 2
2385
2386static void print_graph_proc(int pid, const char *comm)
2387{
2388 /* sign + log10(MAX_INT) + '\0' */
2389 char pid_str[11];
2390 int spaces = 0;
2391 int len;
2392 int i;
2393
2394 sprintf(pid_str, "%d", pid);
2395
2396 /* 1 stands for the "-" character */
2397 len = strlen(comm) + strlen(pid_str) + 1;
2398
2399 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
2400 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
2401
2402 /* First spaces to align center */
2403 for (i = 0; i < spaces / 2; i++)
2404 printf(" ");
2405
2406 printf("%s-%s", comm, pid_str);
2407
2408 /* Last spaces to align center */
2409 for (i = 0; i < spaces - (spaces / 2); i++)
2410 printf(" ");
2411}
2412
2413static struct record *
2414get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2415 struct record *next)
2416{
2417 struct format_field *field;
2418 struct event *event;
2419 unsigned long val;
2420 int type;
2421 int pid;
2422
2423 type = parse_common_type(next->data);
2424 event = find_event(type);
2425 if (!event)
2426 return NULL;
2427
2428 if (!(event->flags & EVENT_FL_ISFUNCRET))
2429 return NULL;
2430
2431 pid = parse_common_pid(next->data);
2432 field = find_field(event, "func");
2433 if (!field)
2434 die("function return does not have field func");
2435
2436 val = read_size(next->data + field->offset, field->size);
2437
2438 if (cur_pid != pid || cur_func != val)
2439 return NULL;
2440
2441 /* this is a leaf, now advance the iterator */
2442 return trace_read_data(cpu);
2443}
2444
2445/* Signal a overhead of time execution to the output */
2446static void print_graph_overhead(unsigned long long duration)
2447{
2448 /* Non nested entry or return */
2449 if (duration == ~0ULL)
2450 return (void)printf(" ");
2451
2452 /* Duration exceeded 100 msecs */
2453 if (duration > 100000ULL)
2454 return (void)printf("! ");
2455
2456 /* Duration exceeded 10 msecs */
2457 if (duration > 10000ULL)
2458 return (void)printf("+ ");
2459
2460 printf(" ");
2461}
2462
2463static void print_graph_duration(unsigned long long duration)
2464{
2465 unsigned long usecs = duration / 1000;
2466 unsigned long nsecs_rem = duration % 1000;
2467 /* log10(ULONG_MAX) + '\0' */
2468 char msecs_str[21];
2469 char nsecs_str[5];
2470 int len;
2471 int i;
2472
2473 sprintf(msecs_str, "%lu", usecs);
2474
2475 /* Print msecs */
2476 len = printf("%lu", usecs);
2477
2478 /* Print nsecs (we don't want to exceed 7 numbers) */
2479 if (len < 7) {
2480 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2481 len += printf(".%s", nsecs_str);
2482 }
2483
2484 printf(" us ");
2485
2486 /* Print remaining spaces to fit the row's width */
2487 for (i = len; i < 7; i++)
2488 printf(" ");
2489
2490 printf("| ");
2491}
2492
2493static void
2494print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2495{
2496 unsigned long long rettime, calltime;
2497 unsigned long long duration, depth;
2498 unsigned long long val;
2499 struct format_field *field;
2500 struct func_map *func;
2501 struct event *ret_event;
2502 int type;
2503 int i;
2504
2505 type = parse_common_type(ret_rec->data);
2506 ret_event = find_event(type);
2507
2508 field = find_field(ret_event, "rettime");
2509 if (!field)
2510 die("can't find rettime in return graph");
2511 rettime = read_size(ret_rec->data + field->offset, field->size);
2512
2513 field = find_field(ret_event, "calltime");
2514 if (!field)
2515 die("can't find rettime in return graph");
2516 calltime = read_size(ret_rec->data + field->offset, field->size);
2517
2518 duration = rettime - calltime;
2519
2520 /* Overhead */
2521 print_graph_overhead(duration);
2522
2523 /* Duration */
2524 print_graph_duration(duration);
2525
2526 field = find_field(event, "depth");
2527 if (!field)
2528 die("can't find depth in entry graph");
2529 depth = read_size(data + field->offset, field->size);
2530
2531 /* Function */
2532 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2533 printf(" ");
2534
2535 field = find_field(event, "func");
2536 if (!field)
2537 die("can't find func in entry graph");
2538 val = read_size(data + field->offset, field->size);
2539 func = find_func(val);
2540
2541 if (func)
2542 printf("%s();", func->func);
2543 else
2544 printf("%llx();", val);
2545}
2546
2547static void print_graph_nested(struct event *event, void *data)
2548{
2549 struct format_field *field;
2550 unsigned long long depth;
2551 unsigned long long val;
2552 struct func_map *func;
2553 int i;
2554
2555 /* No overhead */
2556 print_graph_overhead(-1);
2557
2558 /* No time */
2559 printf(" | ");
2560
2561 field = find_field(event, "depth");
2562 if (!field)
2563 die("can't find depth in entry graph");
2564 depth = read_size(data + field->offset, field->size);
2565
2566 /* Function */
2567 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2568 printf(" ");
2569
2570 field = find_field(event, "func");
2571 if (!field)
2572 die("can't find func in entry graph");
2573 val = read_size(data + field->offset, field->size);
2574 func = find_func(val);
2575
2576 if (func)
2577 printf("%s() {", func->func);
2578 else
2579 printf("%llx() {", val);
2580}
2581
2582static void
2583pretty_print_func_ent(void *data, int size, struct event *event,
2584 int cpu, int pid, const char *comm,
2585 unsigned long secs, unsigned long usecs)
2586{
2587 struct format_field *field;
2588 struct record *rec;
2589 void *copy_data;
2590 unsigned long val;
2591
2592 printf("%5lu.%06lu | ", secs, usecs);
2593
2594 print_graph_cpu(cpu);
2595 print_graph_proc(pid, comm);
2596
2597 printf(" | ");
2598
2599 field = find_field(event, "func");
2600 if (!field)
2601 die("function entry does not have func field");
2602
2603 val = read_size(data + field->offset, field->size);
2604
2605 /*
2606 * peek_data may unmap the data pointer. Copy it first.
2607 */
2608 copy_data = malloc_or_die(size);
2609 memcpy(copy_data, data, size);
2610 data = copy_data;
2611
2612 rec = trace_peek_data(cpu);
2613 if (rec) {
2614 rec = get_return_for_leaf(cpu, pid, val, rec);
2615 if (rec) {
2616 print_graph_entry_leaf(event, data, rec);
2617 goto out_free;
2618 }
2619 }
2620 print_graph_nested(event, data);
2621out_free:
2622 free(data);
2623}
2624
2625static void
2626pretty_print_func_ret(void *data, int size __unused, struct event *event,
2627 int cpu, int pid, const char *comm,
2628 unsigned long secs, unsigned long usecs)
2629{
2630 unsigned long long rettime, calltime;
2631 unsigned long long duration, depth;
2632 struct format_field *field;
2633 int i;
2634
2635 printf("%5lu.%06lu | ", secs, usecs);
2636
2637 print_graph_cpu(cpu);
2638 print_graph_proc(pid, comm);
2639
2640 printf(" | ");
2641
2642 field = find_field(event, "rettime");
2643 if (!field)
2644 die("can't find rettime in return graph");
2645 rettime = read_size(data + field->offset, field->size);
2646
2647 field = find_field(event, "calltime");
2648 if (!field)
2649 die("can't find calltime in return graph");
2650 calltime = read_size(data + field->offset, field->size);
2651
2652 duration = rettime - calltime;
2653
2654 /* Overhead */
2655 print_graph_overhead(duration);
2656
2657 /* Duration */
2658 print_graph_duration(duration);
2659
2660 field = find_field(event, "depth");
2661 if (!field)
2662 die("can't find depth in entry graph");
2663 depth = read_size(data + field->offset, field->size);
2664
2665 /* Function */
2666 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2667 printf(" ");
2668
2669 printf("}");
2670}
2671
2672static void
2673pretty_print_func_graph(void *data, int size, struct event *event,
2674 int cpu, int pid, const char *comm,
2675 unsigned long secs, unsigned long usecs)
2676{
2677 if (event->flags & EVENT_FL_ISFUNCENT)
2678 pretty_print_func_ent(data, size, event,
2679 cpu, pid, comm, secs, usecs);
2680 else if (event->flags & EVENT_FL_ISFUNCRET)
2681 pretty_print_func_ret(data, size, event,
2682 cpu, pid, comm, secs, usecs);
2683 printf("\n");
2684}
2685
2686void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2687 char *comm)
2688{
2689 struct event *event;
2690 unsigned long secs;
2691 unsigned long usecs;
2692 int type;
2693 int pid;
2694
2695 secs = nsecs / NSECS_PER_SEC;
2696 nsecs -= secs * NSECS_PER_SEC;
2697 usecs = nsecs / NSECS_PER_USEC;
2698
2699 type = parse_common_type(data);
2700
2701 event = find_event(type);
2702 if (!event)
2703 die("ug! no event found for type %d", type);
2704
2705 pid = parse_common_pid(data);
2706
2707 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2708 return pretty_print_func_graph(data, size, event, cpu,
2709 pid, comm, secs, usecs);
2710
2711 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ",
2712 comm, pid, cpu,
2713 secs, nsecs, event->name);
2714
2715 pretty_print(data, size, event);
2716 printf("\n");
2717}
2718
2719static void print_fields(struct print_flag_sym *field)
2720{
2721 printf("{ %s, %s }", field->value, field->str);
2722 if (field->next) {
2723 printf(", ");
2724 print_fields(field->next);
2725 }
2726}
2727
2728static void print_args(struct print_arg *args)
2729{
2730 int print_paren = 1;
2731
2732 switch (args->type) {
2733 case PRINT_NULL:
2734 printf("null");
2735 break;
2736 case PRINT_ATOM:
2737 printf("%s", args->atom.atom);
2738 break;
2739 case PRINT_FIELD:
2740 printf("REC->%s", args->field.name);
2741 break;
2742 case PRINT_FLAGS:
2743 printf("__print_flags(");
2744 print_args(args->flags.field);
2745 printf(", %s, ", args->flags.delim);
2746 print_fields(args->flags.flags);
2747 printf(")");
2748 break;
2749 case PRINT_SYMBOL:
2750 printf("__print_symbolic(");
2751 print_args(args->symbol.field);
2752 printf(", ");
2753 print_fields(args->symbol.symbols);
2754 printf(")");
2755 break;
2756 case PRINT_STRING:
2757 printf("__get_str(%s)", args->string.string);
2758 break;
2759 case PRINT_TYPE:
2760 printf("(%s)", args->typecast.type);
2761 print_args(args->typecast.item);
2762 break;
2763 case PRINT_OP:
2764 if (strcmp(args->op.op, ":") == 0)
2765 print_paren = 0;
2766 if (print_paren)
2767 printf("(");
2768 print_args(args->op.left);
2769 printf(" %s ", args->op.op);
2770 print_args(args->op.right);
2771 if (print_paren)
2772 printf(")");
2773 break;
2774 default:
2775 /* we should warn... */
2776 return;
2777 }
2778 if (args->next) {
2779 printf("\n");
2780 print_args(args->next);
2781 }
2782}
2783
2784static void parse_header_field(char *type,
2785 int *offset, int *size)
2786{
2787 char *token;
2788
2789 if (read_expected(EVENT_ITEM, (char *)"field") < 0)
2790 return;
2791 if (read_expected(EVENT_OP, (char *)":") < 0)
2792 return;
2793 /* type */
2794 if (read_expect_type(EVENT_ITEM, &token) < 0)
2795 return;
2796 free_token(token);
2797
2798 if (read_expected(EVENT_ITEM, type) < 0)
2799 return;
2800 if (read_expected(EVENT_OP, (char *)";") < 0)
2801 return;
2802 if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
2803 return;
2804 if (read_expected(EVENT_OP, (char *)":") < 0)
2805 return;
2806 if (read_expect_type(EVENT_ITEM, &token) < 0)
2807 return;
2808 *offset = atoi(token);
2809 free_token(token);
2810 if (read_expected(EVENT_OP, (char *)";") < 0)
2811 return;
2812 if (read_expected(EVENT_ITEM, (char *)"size") < 0)
2813 return;
2814 if (read_expected(EVENT_OP, (char *)":") < 0)
2815 return;
2816 if (read_expect_type(EVENT_ITEM, &token) < 0)
2817 return;
2818 *size = atoi(token);
2819 free_token(token);
2820 if (read_expected(EVENT_OP, (char *)";") < 0)
2821 return;
2822 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2823 return;
2824 free_token(token);
2825}
2826
2827int parse_header_page(char *buf, unsigned long size)
2828{
2829 init_input_buf(buf, size);
2830
2831 parse_header_field((char *)"timestamp", &header_page_ts_offset,
2832 &header_page_ts_size);
2833 parse_header_field((char *)"commit", &header_page_size_offset,
2834 &header_page_size_size);
2835 parse_header_field((char *)"data", &header_page_data_offset,
2836 &header_page_data_size);
2837
2838 return 0;
2839}
2840
2841int parse_ftrace_file(char *buf, unsigned long size)
2842{
2843 struct format_field *field;
2844 struct print_arg *arg, **list;
2845 struct event *event;
2846 int ret;
2847
2848 init_input_buf(buf, size);
2849
2850 event = alloc_event();
2851 if (!event)
2852 return -ENOMEM;
2853
2854 event->flags |= EVENT_FL_ISFTRACE;
2855
2856 event->name = event_read_name();
2857 if (!event->name)
2858 die("failed to read ftrace event name");
2859
2860 if (strcmp(event->name, "function") == 0)
2861 event->flags |= EVENT_FL_ISFUNC;
2862
2863 else if (strcmp(event->name, "funcgraph_entry") == 0)
2864 event->flags |= EVENT_FL_ISFUNCENT;
2865
2866 else if (strcmp(event->name, "funcgraph_exit") == 0)
2867 event->flags |= EVENT_FL_ISFUNCRET;
2868
2869 else if (strcmp(event->name, "bprint") == 0)
2870 event->flags |= EVENT_FL_ISBPRINT;
2871
2872 event->id = event_read_id();
2873 if (event->id < 0)
2874 die("failed to read ftrace event id");
2875
2876 add_event(event);
2877
2878 ret = event_read_format(event);
2879 if (ret < 0)
2880 die("failed to read ftrace event format");
2881
2882 ret = event_read_print(event);
2883 if (ret < 0)
2884 die("failed to read ftrace event print fmt");
2885
2886 /*
2887 * The arguments for ftrace files are parsed by the fields.
2888 * Set up the fields as their arguments.
2889 */
2890 list = &event->print_fmt.args;
2891 for (field = event->format.fields; field; field = field->next) {
2892 arg = malloc_or_die(sizeof(*arg));
2893 memset(arg, 0, sizeof(*arg));
2894 *list = arg;
2895 list = &arg->next;
2896 arg->type = PRINT_FIELD;
2897 arg->field.name = field->name;
2898 arg->field.field = field;
2899 }
2900 return 0;
2901}
2902
2903int parse_event_file(char *buf, unsigned long size, char *system__unused __unused)
2904{
2905 struct event *event;
2906 int ret;
2907
2908 init_input_buf(buf, size);
2909
2910 event = alloc_event();
2911 if (!event)
2912 return -ENOMEM;
2913
2914 event->name = event_read_name();
2915 if (!event->name)
2916 die("failed to read event name");
2917
2918 event->id = event_read_id();
2919 if (event->id < 0)
2920 die("failed to read event id");
2921
2922 ret = event_read_format(event);
2923 if (ret < 0)
2924 die("failed to read event format");
2925
2926 ret = event_read_print(event);
2927 if (ret < 0)
2928 die("failed to read event print fmt");
2929
2930#define PRINT_ARGS 0
2931 if (PRINT_ARGS && event->print_fmt.args)
2932 print_args(event->print_fmt.args);
2933
2934 add_event(event);
2935 return 0;
2936}
2937
2938void parse_set_info(int nr_cpus, int long_sz)
2939{
2940 cpus = nr_cpus;
2941 long_size = long_sz;
2942}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
new file mode 100644
index 000000000000..a1217a10632f
--- /dev/null
+++ b/tools/perf/util/trace-event-read.c
@@ -0,0 +1,512 @@
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_funcs = 0;
468 int show_printk = 0;
469
470 input_fd = open(input_file, O_RDONLY);
471 if (input_fd < 0)
472 die("opening '%s'\n", input_file);
473
474 read_or_die(buf, 3);
475 if (memcmp(buf, test, 3) != 0)
476 die("not an trace data file");
477
478 read_or_die(buf, 7);
479 if (memcmp(buf, "tracing", 7) != 0)
480 die("not a trace file (missing tracing)");
481
482 version = read_string();
483 printf("version = %s\n", version);
484 free(version);
485
486 read_or_die(buf, 1);
487 file_bigendian = buf[0];
488 host_bigendian = bigendian();
489
490 read_or_die(buf, 1);
491 long_size = buf[0];
492
493 page_size = read4();
494
495 read_header_files();
496
497 read_ftrace_files();
498 read_event_files();
499 read_proc_kallsyms();
500 read_ftrace_printk();
501
502 if (show_funcs) {
503 print_funcs();
504 return;
505 }
506 if (show_printk) {
507 print_printk();
508 return;
509 }
510
511 return;
512}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
new file mode 100644
index 000000000000..420294a5773e
--- /dev/null
+++ b/tools/perf/util/trace-event.h
@@ -0,0 +1,240 @@
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);
237
238void read_tracing_data(struct perf_counter_attr *pattrs, int nb_counters);
239
240#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)