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/perf-examples.txt225
-rw-r--r--tools/perf/Documentation/perf-record.txt60
-rw-r--r--tools/perf/Documentation/perf-report.txt29
-rw-r--r--tools/perf/Documentation/perf-stat.txt6
-rw-r--r--tools/perf/Documentation/perf-top.txt112
-rw-r--r--tools/perf/Makefile61
-rw-r--r--tools/perf/builtin-annotate.c301
-rw-r--r--tools/perf/builtin-help.c6
-rw-r--r--tools/perf/builtin-list.c2
-rw-r--r--tools/perf/builtin-record.c276
-rw-r--r--tools/perf/builtin-report.c1190
-rw-r--r--tools/perf/builtin-stat.c449
-rw-r--r--tools/perf/builtin-top.c656
-rw-r--r--tools/perf/perf.c82
-rw-r--r--tools/perf/perf.h38
-rw-r--r--tools/perf/util/alias.c2
-rw-r--r--tools/perf/util/cache.h2
-rw-r--r--tools/perf/util/callchain.c343
-rw-r--r--tools/perf/util/callchain.h60
-rw-r--r--tools/perf/util/color.c37
-rw-r--r--tools/perf/util/color.h5
-rw-r--r--tools/perf/util/config.c18
-rw-r--r--tools/perf/util/ctype.c17
-rw-r--r--tools/perf/util/exec_cmd.c5
-rw-r--r--tools/perf/util/header.c245
-rw-r--r--tools/perf/util/header.h37
-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/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.c588
-rw-r--r--tools/perf/util/parse-events.h6
-rw-r--r--tools/perf/util/parse-options.c5
-rw-r--r--tools/perf/util/parse-options.h27
-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.c95
-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.c2
-rw-r--r--tools/perf/util/string.h7
-rw-r--r--tools/perf/util/strlist.c200
-rw-r--r--tools/perf/util/strlist.h39
-rw-r--r--tools/perf/util/symbol.c478
-rw-r--r--tools/perf/util/symbol.h29
-rw-r--r--tools/perf/util/types.h17
-rw-r--r--tools/perf/util/util.h35
-rw-r--r--tools/perf/util/wrapper.c5
61 files changed, 5541 insertions, 2199 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/perf-examples.txt b/tools/perf/Documentation/perf-examples.txt
new file mode 100644
index 000000000000..8eb6c489fb15
--- /dev/null
+++ b/tools/perf/Documentation/perf-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..6be696b0a2bb 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -29,13 +29,67 @@ 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.
39 93
40SEE ALSO 94SEE ALSO
41-------- 95--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 52d3fc6846a9..e72e93110782 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -13,13 +13,40 @@ 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-C::
31--comms=::
32 Only consider symbols in these comms. CSV that understands
33 file://filename entries.
34-S::
35--symbols=::
36 Only consider these symbols. CSV that understands
37 file://filename entries.
38
39-w::
40--field-width=::
41 Force each column width to the provided list, for large terminal
42 readability.
43
44-t::
45--field-separator=::
46
47 Use a special separator character and don't pad with spaces, replacing
48 all occurances of this separator in symbol names (and other output)
49 with a '.' character, that thus it's the only non valid separator.
23 50
24SEE ALSO 51SEE ALSO
25-------- 52--------
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 0cbd5d6874ec..60411e94113b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -157,10 +157,17 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
157uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') 157uname_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
161ifndef NO_64BIT
162 ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
163 M64 := -m64
164 endif
165endif
166
160# 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.
161 168
162CFLAGS = -ggdb3 -Wall -Werror -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -O6 169CFLAGS = $(M64) -ggdb3 -Wall -Wextra -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6
163LDFLAGS = -lpthread -lrt -lelf 170LDFLAGS = -lpthread -lrt -lelf -lm
164ALL_CFLAGS = $(CFLAGS) 171ALL_CFLAGS = $(CFLAGS)
165ALL_LDFLAGS = $(LDFLAGS) 172ALL_LDFLAGS = $(LDFLAGS)
166STRIP ?= strip 173STRIP ?= strip
@@ -218,7 +225,7 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
218# Those must not be GNU-specific; they are shared with perl/ which may 225# Those must not be GNU-specific; they are shared with perl/ which may
219# be built by a different compiler. (Note that this is an artifact now 226# be built by a different compiler. (Note that this is an artifact now
220# but it still might be nice to keep that distinction.) 227# but it still might be nice to keep that distinction.)
221BASIC_CFLAGS = 228BASIC_CFLAGS = -Iutil/include
222BASIC_LDFLAGS = 229BASIC_LDFLAGS =
223 230
224# Guard against environment variables 231# Guard against environment variables
@@ -284,9 +291,11 @@ export PERL_PATH
284LIB_FILE=libperf.a 291LIB_FILE=libperf.a
285 292
286LIB_H += ../../include/linux/perf_counter.h 293LIB_H += ../../include/linux/perf_counter.h
294LIB_H += ../../include/linux/rbtree.h
295LIB_H += ../../include/linux/list.h
296LIB_H += util/include/linux/list.h
287LIB_H += perf.h 297LIB_H += perf.h
288LIB_H += util/list.h 298LIB_H += util/types.h
289LIB_H += util/rbtree.h
290LIB_H += util/levenshtein.h 299LIB_H += util/levenshtein.h
291LIB_H += util/parse-options.h 300LIB_H += util/parse-options.h
292LIB_H += util/parse-events.h 301LIB_H += util/parse-events.h
@@ -295,9 +304,11 @@ LIB_H += util/util.h
295LIB_H += util/help.h 304LIB_H += util/help.h
296LIB_H += util/strbuf.h 305LIB_H += util/strbuf.h
297LIB_H += util/string.h 306LIB_H += util/string.h
307LIB_H += util/strlist.h
298LIB_H += util/run-command.h 308LIB_H += util/run-command.h
299LIB_H += util/sigchain.h 309LIB_H += util/sigchain.h
300LIB_H += util/symbol.h 310LIB_H += util/symbol.h
311LIB_H += util/module.h
301LIB_H += util/color.h 312LIB_H += util/color.h
302 313
303LIB_OBJS += util/abspath.o 314LIB_OBJS += util/abspath.o
@@ -316,12 +327,16 @@ LIB_OBJS += util/run-command.o
316LIB_OBJS += util/quote.o 327LIB_OBJS += util/quote.o
317LIB_OBJS += util/strbuf.o 328LIB_OBJS += util/strbuf.o
318LIB_OBJS += util/string.o 329LIB_OBJS += util/string.o
330LIB_OBJS += util/strlist.o
319LIB_OBJS += util/usage.o 331LIB_OBJS += util/usage.o
320LIB_OBJS += util/wrapper.o 332LIB_OBJS += util/wrapper.o
321LIB_OBJS += util/sigchain.o 333LIB_OBJS += util/sigchain.o
322LIB_OBJS += util/symbol.o 334LIB_OBJS += util/symbol.o
335LIB_OBJS += util/module.o
323LIB_OBJS += util/color.o 336LIB_OBJS += util/color.o
324LIB_OBJS += util/pager.o 337LIB_OBJS += util/pager.o
338LIB_OBJS += util/header.o
339LIB_OBJS += util/callchain.o
325 340
326BUILTIN_OBJS += builtin-annotate.o 341BUILTIN_OBJS += builtin-annotate.o
327BUILTIN_OBJS += builtin-help.o 342BUILTIN_OBJS += builtin-help.o
@@ -332,7 +347,6 @@ BUILTIN_OBJS += builtin-stat.o
332BUILTIN_OBJS += builtin-top.o 347BUILTIN_OBJS += builtin-top.o
333 348
334PERFLIBS = $(LIB_FILE) 349PERFLIBS = $(LIB_FILE)
335EXTLIBS =
336 350
337# 351#
338# Platform specific tweaks 352# Platform specific tweaks
@@ -361,6 +375,32 @@ ifeq ($(uname_S),Darwin)
361 PTHREAD_LIBS = 375 PTHREAD_LIBS =
362endif 376endif
363 377
378ifneq ($(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)
379 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
380endif
381
382ifdef NO_DEMANGLE
383 BASIC_CFLAGS += -DNO_DEMANGLE
384else
385
386 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")
387
388 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")
389
390 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")
391
392 ifeq ($(has_bfd),y)
393 EXTLIBS += -lbfd
394 else ifeq ($(has_bfd_iberty),y)
395 EXTLIBS += -lbfd -liberty
396 else ifeq ($(has_bfd_iberty_z),y)
397 EXTLIBS += -lbfd -liberty -lz
398 else
399 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling)
400 BASIC_CFLAGS += -DNO_DEMANGLE
401 endif
402endif
403
364ifndef CC_LD_DYNPATH 404ifndef CC_LD_DYNPATH
365 ifdef NO_R_TO_GCC_LINKER 405 ifdef NO_R_TO_GCC_LINKER
366 # Some gcc does not accept and pass -R to the linker to specify 406 # Some gcc does not accept and pass -R to the linker to specify
@@ -371,12 +411,6 @@ ifndef CC_LD_DYNPATH
371 endif 411 endif
372endif 412endif
373 413
374ifdef ZLIB_PATH
375 BASIC_CFLAGS += -I$(ZLIB_PATH)/include
376 EXTLIBS += -L$(ZLIB_PATH)/$(lib) $(CC_LD_DYNPATH)$(ZLIB_PATH)/$(lib)
377endif
378EXTLIBS += -lz
379
380ifdef NEEDS_SOCKET 414ifdef NEEDS_SOCKET
381 EXTLIBS += -lsocket 415 EXTLIBS += -lsocket
382endif 416endif
@@ -687,6 +721,9 @@ builtin-init-db.o: builtin-init-db.c PERF-CFLAGS
687util/config.o: util/config.c PERF-CFLAGS 721util/config.o: util/config.c PERF-CFLAGS
688 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 722 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
689 723
724util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
725 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
726
690perf-%$X: %.o $(PERFLIBS) 727perf-%$X: %.o $(PERFLIBS)
691 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 728 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
692 729
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index b1ed5f766cb3..1dba568e1941 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -10,9 +10,9 @@
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
@@ -39,40 +39,39 @@ static int dump_trace = 0;
39 39
40static int verbose; 40static int verbose;
41 41
42static int modules;
43
44static int full_paths;
45
46static int print_line;
47
42static unsigned long page_size; 48static unsigned long page_size;
43static unsigned long mmap_window = 32; 49static unsigned long mmap_window = 32;
44 50
45struct ip_event { 51struct ip_event {
46 struct perf_event_header header; 52 struct perf_event_header header;
47 __u64 ip; 53 u64 ip;
48 __u32 pid, tid; 54 u32 pid, tid;
49}; 55};
50 56
51struct mmap_event { 57struct mmap_event {
52 struct perf_event_header header; 58 struct perf_event_header header;
53 __u32 pid, tid; 59 u32 pid, tid;
54 __u64 start; 60 u64 start;
55 __u64 len; 61 u64 len;
56 __u64 pgoff; 62 u64 pgoff;
57 char filename[PATH_MAX]; 63 char filename[PATH_MAX];
58}; 64};
59 65
60struct comm_event { 66struct comm_event {
61 struct perf_event_header header; 67 struct perf_event_header header;
62 __u32 pid, tid; 68 u32 pid, tid;
63 char comm[16]; 69 char comm[16];
64}; 70};
65 71
66struct fork_event { 72struct fork_event {
67 struct perf_event_header header; 73 struct perf_event_header header;
68 __u32 pid, ppid; 74 u32 pid, ppid;
69};
70
71struct period_event {
72 struct perf_event_header header;
73 __u64 time;
74 __u64 id;
75 __u64 sample_period;
76}; 75};
77 76
78typedef union event_union { 77typedef union event_union {
@@ -81,9 +80,15 @@ typedef union event_union {
81 struct mmap_event mmap; 80 struct mmap_event mmap;
82 struct comm_event comm; 81 struct comm_event comm;
83 struct fork_event fork; 82 struct fork_event fork;
84 struct period_event period;
85} event_t; 83} event_t;
86 84
85
86struct sym_ext {
87 struct rb_node node;
88 double percent;
89 char *path;
90};
91
87static LIST_HEAD(dsos); 92static LIST_HEAD(dsos);
88static struct dso *kernel_dso; 93static struct dso *kernel_dso;
89static struct dso *vdso; 94static struct dso *vdso;
@@ -145,9 +150,9 @@ static void dsos__fprintf(FILE *fp)
145 dso__fprintf(pos, fp); 150 dso__fprintf(pos, fp);
146} 151}
147 152
148static struct symbol *vdso__find_symbol(struct dso *dso, __u64 ip) 153static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
149{ 154{
150 return dso__find_symbol(kernel_dso, ip); 155 return dso__find_symbol(dso, ip);
151} 156}
152 157
153static int load_kernel(void) 158static int load_kernel(void)
@@ -158,8 +163,8 @@ static int load_kernel(void)
158 if (!kernel_dso) 163 if (!kernel_dso)
159 return -1; 164 return -1;
160 165
161 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); 166 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
162 if (err) { 167 if (err <= 0) {
163 dso__delete(kernel_dso); 168 dso__delete(kernel_dso);
164 kernel_dso = NULL; 169 kernel_dso = NULL;
165 } else 170 } else
@@ -178,19 +183,19 @@ static int load_kernel(void)
178 183
179struct map { 184struct map {
180 struct list_head node; 185 struct list_head node;
181 __u64 start; 186 u64 start;
182 __u64 end; 187 u64 end;
183 __u64 pgoff; 188 u64 pgoff;
184 __u64 (*map_ip)(struct map *, __u64); 189 u64 (*map_ip)(struct map *, u64);
185 struct dso *dso; 190 struct dso *dso;
186}; 191};
187 192
188static __u64 map__map_ip(struct map *map, __u64 ip) 193static u64 map__map_ip(struct map *map, u64 ip)
189{ 194{
190 return ip - map->start + map->pgoff; 195 return ip - map->start + map->pgoff;
191} 196}
192 197
193static __u64 vdso__map_ip(struct map *map, __u64 ip) 198static u64 vdso__map_ip(struct map *map __used, u64 ip)
194{ 199{
195 return ip; 200 return ip;
196} 201}
@@ -373,7 +378,7 @@ static int thread__fork(struct thread *self, struct thread *parent)
373 return 0; 378 return 0;
374} 379}
375 380
376static struct map *thread__find_map(struct thread *self, __u64 ip) 381static struct map *thread__find_map(struct thread *self, u64 ip)
377{ 382{
378 struct map *pos; 383 struct map *pos;
379 384
@@ -414,7 +419,7 @@ struct hist_entry {
414 struct map *map; 419 struct map *map;
415 struct dso *dso; 420 struct dso *dso;
416 struct symbol *sym; 421 struct symbol *sym;
417 __u64 ip; 422 u64 ip;
418 char level; 423 char level;
419 424
420 uint32_t count; 425 uint32_t count;
@@ -519,7 +524,7 @@ sort__dso_print(FILE *fp, struct hist_entry *self)
519 if (self->dso) 524 if (self->dso)
520 return fprintf(fp, "%-25s", self->dso->name); 525 return fprintf(fp, "%-25s", self->dso->name);
521 526
522 return fprintf(fp, "%016llx ", (__u64)self->ip); 527 return fprintf(fp, "%016llx ", (u64)self->ip);
523} 528}
524 529
525static struct sort_entry sort_dso = { 530static struct sort_entry sort_dso = {
@@ -533,7 +538,7 @@ static struct sort_entry sort_dso = {
533static int64_t 538static int64_t
534sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 539sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
535{ 540{
536 __u64 ip_l, ip_r; 541 u64 ip_l, ip_r;
537 542
538 if (left->sym == right->sym) 543 if (left->sym == right->sym)
539 return 0; 544 return 0;
@@ -550,13 +555,13 @@ sort__sym_print(FILE *fp, struct hist_entry *self)
550 size_t ret = 0; 555 size_t ret = 0;
551 556
552 if (verbose) 557 if (verbose)
553 ret += fprintf(fp, "%#018llx ", (__u64)self->ip); 558 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
554 559
555 if (self->sym) { 560 if (self->sym) {
556 ret += fprintf(fp, "[%c] %s", 561 ret += fprintf(fp, "[%c] %s",
557 self->dso == kernel_dso ? 'k' : '.', self->sym->name); 562 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
558 } else { 563 } else {
559 ret += fprintf(fp, "%#016llx", (__u64)self->ip); 564 ret += fprintf(fp, "%#016llx", (u64)self->ip);
560 } 565 }
561 566
562 return ret; 567 return ret;
@@ -587,7 +592,7 @@ static LIST_HEAD(hist_entry__sort_list);
587 592
588static int sort_dimension__add(char *tok) 593static int sort_dimension__add(char *tok)
589{ 594{
590 int i; 595 unsigned int i;
591 596
592 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 597 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
593 struct sort_dimension *sd = &sort_dimensions[i]; 598 struct sort_dimension *sd = &sort_dimensions[i];
@@ -647,7 +652,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
647/* 652/*
648 * collect histogram counts 653 * collect histogram counts
649 */ 654 */
650static void hist_hit(struct hist_entry *he, __u64 ip) 655static void hist_hit(struct hist_entry *he, u64 ip)
651{ 656{
652 unsigned int sym_size, offset; 657 unsigned int sym_size, offset;
653 struct symbol *sym = he->sym; 658 struct symbol *sym = he->sym;
@@ -676,7 +681,7 @@ static void hist_hit(struct hist_entry *he, __u64 ip)
676 681
677static int 682static int
678hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 683hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
679 struct symbol *sym, __u64 ip, char level) 684 struct symbol *sym, u64 ip, char level)
680{ 685{
681 struct rb_node **p = &hist.rb_node; 686 struct rb_node **p = &hist.rb_node;
682 struct rb_node *parent = NULL; 687 struct rb_node *parent = NULL;
@@ -842,13 +847,13 @@ static unsigned long total = 0,
842 total_unknown = 0; 847 total_unknown = 0;
843 848
844static int 849static int
845process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 850process_sample_event(event_t *event, unsigned long offset, unsigned long head)
846{ 851{
847 char level; 852 char level;
848 int show = 0; 853 int show = 0;
849 struct dso *dso = NULL; 854 struct dso *dso = NULL;
850 struct thread *thread = threads__findnew(event->ip.pid); 855 struct thread *thread = threads__findnew(event->ip.pid);
851 __u64 ip = event->ip.ip; 856 u64 ip = event->ip.ip;
852 struct map *map = NULL; 857 struct map *map = NULL;
853 858
854 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", 859 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
@@ -985,25 +990,12 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
985} 990}
986 991
987static int 992static int
988process_period_event(event_t *event, unsigned long offset, unsigned long head)
989{
990 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
991 (void *)(offset + head),
992 (void *)(long)(event->header.size),
993 event->period.time,
994 event->period.id,
995 event->period.sample_period);
996
997 return 0;
998}
999
1000static int
1001process_event(event_t *event, unsigned long offset, unsigned long head) 993process_event(event_t *event, unsigned long offset, unsigned long head)
1002{ 994{
1003 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1004 return process_overflow_event(event, offset, head);
1005
1006 switch (event->header.type) { 995 switch (event->header.type) {
996 case PERF_EVENT_SAMPLE:
997 return process_sample_event(event, offset, head);
998
1007 case PERF_EVENT_MMAP: 999 case PERF_EVENT_MMAP:
1008 return process_mmap_event(event, offset, head); 1000 return process_mmap_event(event, offset, head);
1009 1001
@@ -1012,9 +1004,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1012 1004
1013 case PERF_EVENT_FORK: 1005 case PERF_EVENT_FORK:
1014 return process_fork_event(event, offset, head); 1006 return process_fork_event(event, offset, head);
1015
1016 case PERF_EVENT_PERIOD:
1017 return process_period_event(event, offset, head);
1018 /* 1007 /*
1019 * We dont process them right now but they are fine: 1008 * We dont process them right now but they are fine:
1020 */ 1009 */
@@ -1031,12 +1020,14 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1031} 1020}
1032 1021
1033static int 1022static int
1034parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) 1023parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1035{ 1024{
1036 char *line = NULL, *tmp, *tmp2; 1025 char *line = NULL, *tmp, *tmp2;
1026 static const char *prev_line;
1027 static const char *prev_color;
1037 unsigned int offset; 1028 unsigned int offset;
1038 size_t line_len; 1029 size_t line_len;
1039 __u64 line_ip; 1030 s64 line_ip;
1040 int ret; 1031 int ret;
1041 char *c; 1032 char *c;
1042 1033
@@ -1073,27 +1064,36 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1073 } 1064 }
1074 1065
1075 if (line_ip != -1) { 1066 if (line_ip != -1) {
1067 const char *path = NULL;
1076 unsigned int hits = 0; 1068 unsigned int hits = 0;
1077 double percent = 0.0; 1069 double percent = 0.0;
1078 char *color = PERF_COLOR_NORMAL; 1070 char *color;
1071 struct sym_ext *sym_ext = sym->priv;
1079 1072
1080 offset = line_ip - start; 1073 offset = line_ip - start;
1081 if (offset < len) 1074 if (offset < len)
1082 hits = sym->hist[offset]; 1075 hits = sym->hist[offset];
1083 1076
1084 if (sym->hist_sum) 1077 if (offset < len && sym_ext) {
1078 path = sym_ext[offset].path;
1079 percent = sym_ext[offset].percent;
1080 } else if (sym->hist_sum)
1085 percent = 100.0 * hits / sym->hist_sum; 1081 percent = 100.0 * hits / sym->hist_sum;
1086 1082
1083 color = get_percent_color(percent);
1084
1087 /* 1085 /*
1088 * We color high-overhead entries in red, mid-overhead 1086 * Also color the filename and line if needed, with
1089 * entries in green - and keep the low overhead places 1087 * the same color than the percentage. Don't print it
1090 * normal: 1088 * twice for close colored ip with the same filename:line
1091 */ 1089 */
1092 if (percent >= 5.0) 1090 if (path) {
1093 color = PERF_COLOR_RED; 1091 if (!prev_line || strcmp(prev_line, path)
1094 else { 1092 || color != prev_color) {
1095 if (percent > 0.5) 1093 color_fprintf(stdout, color, " %s", path);
1096 color = PERF_COLOR_GREEN; 1094 prev_line = path;
1095 prev_color = color;
1096 }
1097 } 1097 }
1098 1098
1099 color_fprintf(stdout, color, " %7.2f", percent); 1099 color_fprintf(stdout, color, " %7.2f", percent);
@@ -1109,33 +1109,160 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
1109 return 0; 1109 return 0;
1110} 1110}
1111 1111
1112static struct rb_root root_sym_ext;
1113
1114static void insert_source_line(struct sym_ext *sym_ext)
1115{
1116 struct sym_ext *iter;
1117 struct rb_node **p = &root_sym_ext.rb_node;
1118 struct rb_node *parent = NULL;
1119
1120 while (*p != NULL) {
1121 parent = *p;
1122 iter = rb_entry(parent, struct sym_ext, node);
1123
1124 if (sym_ext->percent > iter->percent)
1125 p = &(*p)->rb_left;
1126 else
1127 p = &(*p)->rb_right;
1128 }
1129
1130 rb_link_node(&sym_ext->node, parent, p);
1131 rb_insert_color(&sym_ext->node, &root_sym_ext);
1132}
1133
1134static void free_source_line(struct symbol *sym, int len)
1135{
1136 struct sym_ext *sym_ext = sym->priv;
1137 int i;
1138
1139 if (!sym_ext)
1140 return;
1141
1142 for (i = 0; i < len; i++)
1143 free(sym_ext[i].path);
1144 free(sym_ext);
1145
1146 sym->priv = NULL;
1147 root_sym_ext = RB_ROOT;
1148}
1149
1150/* Get the filename:line for the colored entries */
1151static void
1152get_source_line(struct symbol *sym, u64 start, int len, char *filename)
1153{
1154 int i;
1155 char cmd[PATH_MAX * 2];
1156 struct sym_ext *sym_ext;
1157
1158 if (!sym->hist_sum)
1159 return;
1160
1161 sym->priv = calloc(len, sizeof(struct sym_ext));
1162 if (!sym->priv)
1163 return;
1164
1165 sym_ext = sym->priv;
1166
1167 for (i = 0; i < len; i++) {
1168 char *path = NULL;
1169 size_t line_len;
1170 u64 offset;
1171 FILE *fp;
1172
1173 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
1174 if (sym_ext[i].percent <= 0.5)
1175 continue;
1176
1177 offset = start + i;
1178 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
1179 fp = popen(cmd, "r");
1180 if (!fp)
1181 continue;
1182
1183 if (getline(&path, &line_len, fp) < 0 || !line_len)
1184 goto next;
1185
1186 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
1187 if (!sym_ext[i].path)
1188 goto next;
1189
1190 strcpy(sym_ext[i].path, path);
1191 insert_source_line(&sym_ext[i]);
1192
1193 next:
1194 pclose(fp);
1195 }
1196}
1197
1198static void print_summary(char *filename)
1199{
1200 struct sym_ext *sym_ext;
1201 struct rb_node *node;
1202
1203 printf("\nSorted summary for file %s\n", filename);
1204 printf("----------------------------------------------\n\n");
1205
1206 if (RB_EMPTY_ROOT(&root_sym_ext)) {
1207 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
1208 return;
1209 }
1210
1211 node = rb_first(&root_sym_ext);
1212 while (node) {
1213 double percent;
1214 char *color;
1215 char *path;
1216
1217 sym_ext = rb_entry(node, struct sym_ext, node);
1218 percent = sym_ext->percent;
1219 color = get_percent_color(percent);
1220 path = sym_ext->path;
1221
1222 color_fprintf(stdout, color, " %7.2f %s", percent, path);
1223 node = rb_next(node);
1224 }
1225}
1226
1112static void annotate_sym(struct dso *dso, struct symbol *sym) 1227static void annotate_sym(struct dso *dso, struct symbol *sym)
1113{ 1228{
1114 char *filename = dso->name; 1229 char *filename = dso->name, *d_filename;
1115 __u64 start, end, len; 1230 u64 start, end, len;
1116 char command[PATH_MAX*2]; 1231 char command[PATH_MAX*2];
1117 FILE *file; 1232 FILE *file;
1118 1233
1119 if (!filename) 1234 if (!filename)
1120 return; 1235 return;
1121 if (dso == kernel_dso) 1236 if (sym->module)
1237 filename = sym->module->path;
1238 else if (dso == kernel_dso)
1122 filename = vmlinux; 1239 filename = vmlinux;
1123 1240
1124 printf("\n------------------------------------------------\n");
1125 printf(" Percent | Source code & Disassembly of %s\n", filename);
1126 printf("------------------------------------------------\n");
1127
1128 if (verbose >= 2)
1129 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1130
1131 start = sym->obj_start; 1241 start = sym->obj_start;
1132 if (!start) 1242 if (!start)
1133 start = sym->start; 1243 start = sym->start;
1244 if (full_paths)
1245 d_filename = filename;
1246 else
1247 d_filename = basename(filename);
1134 1248
1135 end = start + sym->end - sym->start + 1; 1249 end = start + sym->end - sym->start + 1;
1136 len = sym->end - sym->start; 1250 len = sym->end - sym->start;
1137 1251
1138 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); 1252 if (print_line) {
1253 get_source_line(sym, start, len, filename);
1254 print_summary(filename);
1255 }
1256
1257 printf("\n\n------------------------------------------------\n");
1258 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
1259 printf("------------------------------------------------\n");
1260
1261 if (verbose >= 2)
1262 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1263
1264 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
1265 (u64)start, (u64)end, filename, filename);
1139 1266
1140 if (verbose >= 3) 1267 if (verbose >= 3)
1141 printf("doing: %s\n", command); 1268 printf("doing: %s\n", command);
@@ -1150,6 +1277,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1150 } 1277 }
1151 1278
1152 pclose(file); 1279 pclose(file);
1280 if (print_line)
1281 free_source_line(sym, len);
1153} 1282}
1154 1283
1155static void find_annotations(void) 1284static void find_annotations(void)
@@ -1264,7 +1393,7 @@ more:
1264 1393
1265 head += size; 1394 head += size;
1266 1395
1267 if (offset + head < stat.st_size) 1396 if (offset + head < (unsigned long)stat.st_size)
1268 goto more; 1397 goto more;
1269 1398
1270 rc = EXIT_SUCCESS; 1399 rc = EXIT_SUCCESS;
@@ -1308,6 +1437,12 @@ static const struct option options[] = {
1308 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1437 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1309 "dump raw trace in ASCII"), 1438 "dump raw trace in ASCII"),
1310 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1439 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1440 OPT_BOOLEAN('m', "modules", &modules,
1441 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1442 OPT_BOOLEAN('l', "print-line", &print_line,
1443 "print matching source lines (may be slow)"),
1444 OPT_BOOLEAN('P', "full-paths", &full_paths,
1445 "Don't shorten the displayed pathnames"),
1311 OPT_END() 1446 OPT_END()
1312}; 1447};
1313 1448
@@ -1326,7 +1461,7 @@ static void setup_sorting(void)
1326 free(str); 1461 free(str);
1327} 1462}
1328 1463
1329int cmd_annotate(int argc, const char **argv, const char *prefix) 1464int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1330{ 1465{
1331 symbol__init(); 1466 symbol__init();
1332 1467
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 0f32dc3f3c4c..2599d86a733b 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);
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index fe60e37c96ef..f990fa8a35c9 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -13,7 +13,7 @@
13#include "util/parse-options.h" 13#include "util/parse-options.h"
14#include "util/parse-events.h" 14#include "util/parse-events.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 print_events(); 18 print_events();
19 return 0; 19 return 0;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 0f5771f615da..0345aad8eba5 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -14,6 +14,8 @@
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
17#include <unistd.h> 19#include <unistd.h>
18#include <sched.h> 20#include <sched.h>
19 21
@@ -37,33 +39,41 @@ static pid_t target_pid = -1;
37static int inherit = 1; 39static int inherit = 1;
38static int force = 0; 40static int force = 0;
39static int append_file = 0; 41static int append_file = 0;
42static int call_graph = 0;
40static int verbose = 0; 43static int verbose = 0;
44static int inherit_stat = 0;
45static int no_samples = 0;
46static int sample_address = 0;
41 47
42static long samples; 48static long samples;
43static struct timeval last_read; 49static struct timeval last_read;
44static struct timeval this_read; 50static struct timeval this_read;
45 51
46static __u64 bytes_written; 52static u64 bytes_written;
47 53
48static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 54static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
49 55
50static int nr_poll; 56static int nr_poll;
51static int nr_cpu; 57static int nr_cpu;
52 58
59static int file_new = 1;
60
61struct perf_header *header;
62
53struct mmap_event { 63struct mmap_event {
54 struct perf_event_header header; 64 struct perf_event_header header;
55 __u32 pid; 65 u32 pid;
56 __u32 tid; 66 u32 tid;
57 __u64 start; 67 u64 start;
58 __u64 len; 68 u64 len;
59 __u64 pgoff; 69 u64 pgoff;
60 char filename[PATH_MAX]; 70 char filename[PATH_MAX];
61}; 71};
62 72
63struct comm_event { 73struct comm_event {
64 struct perf_event_header header; 74 struct perf_event_header header;
65 __u32 pid; 75 u32 pid;
66 __u32 tid; 76 u32 tid;
67 char comm[16]; 77 char comm[16];
68}; 78};
69 79
@@ -77,10 +87,10 @@ struct mmap_data {
77 87
78static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 88static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
79 89
80static unsigned int mmap_read_head(struct mmap_data *md) 90static unsigned long mmap_read_head(struct mmap_data *md)
81{ 91{
82 struct perf_counter_mmap_page *pc = md->base; 92 struct perf_counter_mmap_page *pc = md->base;
83 int head; 93 long head;
84 94
85 head = pc->data_head; 95 head = pc->data_head;
86 rmb(); 96 rmb();
@@ -88,6 +98,32 @@ static unsigned int mmap_read_head(struct mmap_data *md)
88 return head; 98 return head;
89} 99}
90 100
101static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
102{
103 struct perf_counter_mmap_page *pc = md->base;
104
105 /*
106 * ensure all reads are done before we write the tail out.
107 */
108 /* mb(); */
109 pc->data_tail = tail;
110}
111
112static void write_output(void *buf, size_t size)
113{
114 while (size) {
115 int ret = write(output, buf, size);
116
117 if (ret < 0)
118 die("failed to write");
119
120 size -= ret;
121 buf += ret;
122
123 bytes_written += ret;
124 }
125}
126
91static void mmap_read(struct mmap_data *md) 127static void mmap_read(struct mmap_data *md)
92{ 128{
93 unsigned int head = mmap_read_head(md); 129 unsigned int head = mmap_read_head(md);
@@ -108,7 +144,7 @@ static void mmap_read(struct mmap_data *md)
108 * In either case, truncate and restart at head. 144 * In either case, truncate and restart at head.
109 */ 145 */
110 diff = head - old; 146 diff = head - old;
111 if (diff > md->mask / 2 || diff < 0) { 147 if (diff < 0) {
112 struct timeval iv; 148 struct timeval iv;
113 unsigned long msecs; 149 unsigned long msecs;
114 150
@@ -136,36 +172,17 @@ static void mmap_read(struct mmap_data *md)
136 size = md->mask + 1 - (old & md->mask); 172 size = md->mask + 1 - (old & md->mask);
137 old += size; 173 old += size;
138 174
139 while (size) { 175 write_output(buf, size);
140 int ret = write(output, buf, size);
141
142 if (ret < 0)
143 die("failed to write");
144
145 size -= ret;
146 buf += ret;
147
148 bytes_written += ret;
149 }
150 } 176 }
151 177
152 buf = &data[old & md->mask]; 178 buf = &data[old & md->mask];
153 size = head - old; 179 size = head - old;
154 old += size; 180 old += size;
155 181
156 while (size) { 182 write_output(buf, size);
157 int ret = write(output, buf, size);
158
159 if (ret < 0)
160 die("failed to write");
161
162 size -= ret;
163 buf += ret;
164
165 bytes_written += ret;
166 }
167 183
168 md->prev = old; 184 md->prev = old;
185 mmap_write_tail(md, old);
169} 186}
170 187
171static volatile int done = 0; 188static volatile int done = 0;
@@ -191,7 +208,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
191 struct comm_event comm_ev; 208 struct comm_event comm_ev;
192 char filename[PATH_MAX]; 209 char filename[PATH_MAX];
193 char bf[BUFSIZ]; 210 char bf[BUFSIZ];
194 int fd, ret; 211 int fd;
195 size_t size; 212 size_t size;
196 char *field, *sep; 213 char *field, *sep;
197 DIR *tasks; 214 DIR *tasks;
@@ -201,8 +218,12 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
201 218
202 fd = open(filename, O_RDONLY); 219 fd = open(filename, O_RDONLY);
203 if (fd < 0) { 220 if (fd < 0) {
204 fprintf(stderr, "couldn't open %s\n", filename); 221 /*
205 exit(EXIT_FAILURE); 222 * We raced with a task exiting - just return:
223 */
224 if (verbose)
225 fprintf(stderr, "couldn't open %s\n", filename);
226 return;
206 } 227 }
207 if (read(fd, bf, sizeof(bf)) < 0) { 228 if (read(fd, bf, sizeof(bf)) < 0) {
208 fprintf(stderr, "couldn't read %s\n", filename); 229 fprintf(stderr, "couldn't read %s\n", filename);
@@ -223,17 +244,13 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
223 244
224 comm_ev.pid = pid; 245 comm_ev.pid = pid;
225 comm_ev.header.type = PERF_EVENT_COMM; 246 comm_ev.header.type = PERF_EVENT_COMM;
226 size = ALIGN(size, sizeof(__u64)); 247 size = ALIGN(size, sizeof(u64));
227 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); 248 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
228 249
229 if (!full) { 250 if (!full) {
230 comm_ev.tid = pid; 251 comm_ev.tid = pid;
231 252
232 ret = write(output, &comm_ev, comm_ev.header.size); 253 write_output(&comm_ev, comm_ev.header.size);
233 if (ret < 0) {
234 perror("failed to write");
235 exit(-1);
236 }
237 return; 254 return;
238 } 255 }
239 256
@@ -248,11 +265,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
248 265
249 comm_ev.tid = pid; 266 comm_ev.tid = pid;
250 267
251 ret = write(output, &comm_ev, comm_ev.header.size); 268 write_output(&comm_ev, comm_ev.header.size);
252 if (ret < 0) {
253 perror("failed to write");
254 exit(-1);
255 }
256 } 269 }
257 closedir(tasks); 270 closedir(tasks);
258 return; 271 return;
@@ -272,13 +285,17 @@ static void pid_synthesize_mmap_samples(pid_t pid)
272 285
273 fp = fopen(filename, "r"); 286 fp = fopen(filename, "r");
274 if (fp == NULL) { 287 if (fp == NULL) {
275 fprintf(stderr, "couldn't open %s\n", filename); 288 /*
276 exit(EXIT_FAILURE); 289 * We raced with a task exiting - just return:
290 */
291 if (verbose)
292 fprintf(stderr, "couldn't open %s\n", filename);
293 return;
277 } 294 }
278 while (1) { 295 while (1) {
279 char bf[BUFSIZ], *pbf = bf; 296 char bf[BUFSIZ], *pbf = bf;
280 struct mmap_event mmap_ev = { 297 struct mmap_event mmap_ev = {
281 .header.type = PERF_EVENT_MMAP, 298 .header = { .type = PERF_EVENT_MMAP },
282 }; 299 };
283 int n; 300 int n;
284 size_t size; 301 size_t size;
@@ -295,33 +312,33 @@ static void pid_synthesize_mmap_samples(pid_t pid)
295 continue; 312 continue;
296 pbf += n + 3; 313 pbf += n + 3;
297 if (*pbf == 'x') { /* vm_exec */ 314 if (*pbf == 'x') { /* vm_exec */
298 char *execname = strrchr(bf, ' '); 315 char *execname = strchr(bf, '/');
316
317 /* Catch VDSO */
318 if (execname == NULL)
319 execname = strstr(bf, "[vdso]");
299 320
300 if (execname == NULL || execname[1] != '/') 321 if (execname == NULL)
301 continue; 322 continue;
302 323
303 execname += 1;
304 size = strlen(execname); 324 size = strlen(execname);
305 execname[size - 1] = '\0'; /* Remove \n */ 325 execname[size - 1] = '\0'; /* Remove \n */
306 memcpy(mmap_ev.filename, execname, size); 326 memcpy(mmap_ev.filename, execname, size);
307 size = ALIGN(size, sizeof(__u64)); 327 size = ALIGN(size, sizeof(u64));
308 mmap_ev.len -= mmap_ev.start; 328 mmap_ev.len -= mmap_ev.start;
309 mmap_ev.header.size = (sizeof(mmap_ev) - 329 mmap_ev.header.size = (sizeof(mmap_ev) -
310 (sizeof(mmap_ev.filename) - size)); 330 (sizeof(mmap_ev.filename) - size));
311 mmap_ev.pid = pid; 331 mmap_ev.pid = pid;
312 mmap_ev.tid = pid; 332 mmap_ev.tid = pid;
313 333
314 if (write(output, &mmap_ev, mmap_ev.header.size) < 0) { 334 write_output(&mmap_ev, mmap_ev.header.size);
315 perror("failed to write");
316 exit(-1);
317 }
318 } 335 }
319 } 336 }
320 337
321 fclose(fp); 338 fclose(fp);
322} 339}
323 340
324static void synthesize_samples(void) 341static void synthesize_all(void)
325{ 342{
326 DIR *proc; 343 DIR *proc;
327 struct dirent dirent, *next; 344 struct dirent dirent, *next;
@@ -345,24 +362,62 @@ static void synthesize_samples(void)
345 362
346static int group_fd; 363static int group_fd;
347 364
365static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr)
366{
367 struct perf_header_attr *h_attr;
368
369 if (nr < header->attrs) {
370 h_attr = header->attr[nr];
371 } else {
372 h_attr = perf_header_attr__new(a);
373 perf_header__add_attr(header, h_attr);
374 }
375
376 return h_attr;
377}
378
348static void create_counter(int counter, int cpu, pid_t pid) 379static void create_counter(int counter, int cpu, pid_t pid)
349{ 380{
350 struct perf_counter_attr *attr = attrs + counter; 381 struct perf_counter_attr *attr = attrs + counter;
351 int track = 1; 382 struct perf_header_attr *h_attr;
383 int track = !counter; /* only the first counter needs these */
384 struct {
385 u64 count;
386 u64 time_enabled;
387 u64 time_running;
388 u64 id;
389 } read_data;
390
391 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
392 PERF_FORMAT_TOTAL_TIME_RUNNING |
393 PERF_FORMAT_ID;
352 394
353 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 395 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
396
354 if (freq) { 397 if (freq) {
355 attr->sample_type |= PERF_SAMPLE_PERIOD; 398 attr->sample_type |= PERF_SAMPLE_PERIOD;
356 attr->freq = 1; 399 attr->freq = 1;
357 attr->sample_freq = freq; 400 attr->sample_freq = freq;
358 } 401 }
402
403 if (no_samples)
404 attr->sample_freq = 0;
405
406 if (inherit_stat)
407 attr->inherit_stat = 1;
408
409 if (sample_address)
410 attr->sample_type |= PERF_SAMPLE_ADDR;
411
412 if (call_graph)
413 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
414
415
359 attr->mmap = track; 416 attr->mmap = track;
360 attr->comm = track; 417 attr->comm = track;
361 attr->inherit = (cpu < 0) && inherit; 418 attr->inherit = (cpu < 0) && inherit;
362 attr->disabled = 1; 419 attr->disabled = 1;
363 420
364 track = 0; /* only the first counter needs these */
365
366try_again: 421try_again:
367 fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); 422 fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
368 423
@@ -393,6 +448,22 @@ try_again:
393 exit(-1); 448 exit(-1);
394 } 449 }
395 450
451 h_attr = get_header_attr(attr, counter);
452
453 if (!file_new) {
454 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
455 fprintf(stderr, "incompatible append\n");
456 exit(-1);
457 }
458 }
459
460 if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) {
461 perror("Unable to read perf file descriptor\n");
462 exit(-1);
463 }
464
465 perf_header_attr__add_id(h_attr, read_data.id);
466
396 assert(fd[nr_cpu][counter] >= 0); 467 assert(fd[nr_cpu][counter] >= 0);
397 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 468 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
398 469
@@ -410,7 +481,7 @@ try_again:
410 mmap_array[nr_cpu][counter].prev = 0; 481 mmap_array[nr_cpu][counter].prev = 0;
411 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; 482 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1;
412 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, 483 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
413 PROT_READ, MAP_SHARED, fd[nr_cpu][counter], 0); 484 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0);
414 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { 485 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) {
415 error("failed to mmap with %d (%s)\n", errno, strerror(errno)); 486 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
416 exit(-1); 487 exit(-1);
@@ -423,11 +494,6 @@ static void open_counters(int cpu, pid_t pid)
423{ 494{
424 int counter; 495 int counter;
425 496
426 if (pid > 0) {
427 pid_synthesize_comm_event(pid, 0);
428 pid_synthesize_mmap_samples(pid);
429 }
430
431 group_fd = -1; 497 group_fd = -1;
432 for (counter = 0; counter < nr_counters; counter++) 498 for (counter = 0; counter < nr_counters; counter++)
433 create_counter(counter, cpu, pid); 499 create_counter(counter, cpu, pid);
@@ -435,11 +501,18 @@ static void open_counters(int cpu, pid_t pid)
435 nr_cpu++; 501 nr_cpu++;
436} 502}
437 503
504static void atexit_header(void)
505{
506 header->data_size += bytes_written;
507
508 perf_header__write(header, output);
509}
510
438static int __cmd_record(int argc, const char **argv) 511static int __cmd_record(int argc, const char **argv)
439{ 512{
440 int i, counter; 513 int i, counter;
441 struct stat st; 514 struct stat st;
442 pid_t pid; 515 pid_t pid = 0;
443 int flags; 516 int flags;
444 int ret; 517 int ret;
445 518
@@ -448,15 +521,23 @@ static int __cmd_record(int argc, const char **argv)
448 assert(nr_cpus <= MAX_NR_CPUS); 521 assert(nr_cpus <= MAX_NR_CPUS);
449 assert(nr_cpus >= 0); 522 assert(nr_cpus >= 0);
450 523
451 if (!stat(output_name, &st) && !force && !append_file) { 524 atexit(sig_atexit);
452 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 525 signal(SIGCHLD, sig_handler);
453 output_name); 526 signal(SIGINT, sig_handler);
454 exit(-1); 527
528 if (!stat(output_name, &st) && st.st_size) {
529 if (!force && !append_file) {
530 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
531 output_name);
532 exit(-1);
533 }
534 } else {
535 append_file = 0;
455 } 536 }
456 537
457 flags = O_CREAT|O_RDWR; 538 flags = O_CREAT|O_RDWR;
458 if (append_file) 539 if (append_file)
459 flags |= O_APPEND; 540 file_new = 0;
460 else 541 else
461 flags |= O_TRUNC; 542 flags |= O_TRUNC;
462 543
@@ -466,14 +547,30 @@ static int __cmd_record(int argc, const char **argv)
466 exit(-1); 547 exit(-1);
467 } 548 }
468 549
550 if (!file_new)
551 header = perf_header__read(output);
552 else
553 header = perf_header__new();
554
555 atexit(atexit_header);
556
469 if (!system_wide) { 557 if (!system_wide) {
470 open_counters(-1, target_pid != -1 ? target_pid : getpid()); 558 pid = target_pid;
559 if (pid == -1)
560 pid = getpid();
561
562 open_counters(-1, pid);
471 } else for (i = 0; i < nr_cpus; i++) 563 } else for (i = 0; i < nr_cpus; i++)
472 open_counters(i, target_pid); 564 open_counters(i, target_pid);
473 565
474 atexit(sig_atexit); 566 if (file_new)
475 signal(SIGCHLD, sig_handler); 567 perf_header__write(header, output);
476 signal(SIGINT, sig_handler); 568
569 if (!system_wide) {
570 pid_synthesize_comm_event(pid, 0);
571 pid_synthesize_mmap_samples(pid);
572 } else
573 synthesize_all();
477 574
478 if (target_pid == -1 && argc) { 575 if (target_pid == -1 && argc) {
479 pid = fork(); 576 pid = fork();
@@ -498,10 +595,7 @@ static int __cmd_record(int argc, const char **argv)
498 } 595 }
499 } 596 }
500 597
501 if (system_wide) 598 for (;;) {
502 synthesize_samples();
503
504 while (!done) {
505 int hits = samples; 599 int hits = samples;
506 600
507 for (i = 0; i < nr_cpu; i++) { 601 for (i = 0; i < nr_cpu; i++) {
@@ -509,8 +603,11 @@ static int __cmd_record(int argc, const char **argv)
509 mmap_read(&mmap_array[i][counter]); 603 mmap_read(&mmap_array[i][counter]);
510 } 604 }
511 605
512 if (hits == samples) 606 if (hits == samples) {
607 if (done)
608 break;
513 ret = poll(event_array, nr_poll, 100); 609 ret = poll(event_array, nr_poll, 100);
610 }
514 } 611 }
515 612
516 /* 613 /*
@@ -555,16 +652,25 @@ static const struct option options[] = {
555 "profile at this frequency"), 652 "profile at this frequency"),
556 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 653 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
557 "number of mmap data pages"), 654 "number of mmap data pages"),
655 OPT_BOOLEAN('g', "call-graph", &call_graph,
656 "do call-graph (stack chain/backtrace) recording"),
558 OPT_BOOLEAN('v', "verbose", &verbose, 657 OPT_BOOLEAN('v', "verbose", &verbose,
559 "be more verbose (show counter open errors, etc)"), 658 "be more verbose (show counter open errors, etc)"),
659 OPT_BOOLEAN('s', "stat", &inherit_stat,
660 "per thread counts"),
661 OPT_BOOLEAN('d', "data", &sample_address,
662 "Sample addresses"),
663 OPT_BOOLEAN('n', "no-samples", &no_samples,
664 "don't sample"),
560 OPT_END() 665 OPT_END()
561}; 666};
562 667
563int cmd_record(int argc, const char **argv, const char *prefix) 668int cmd_record(int argc, const char **argv, const char *prefix __used)
564{ 669{
565 int counter; 670 int counter;
566 671
567 argc = parse_options(argc, argv, options, record_usage, 0); 672 argc = parse_options(argc, argv, options, record_usage,
673 PARSE_OPT_STOP_AT_NON_OPTION);
568 if (!argc && target_pid == -1 && !system_wide) 674 if (!argc && target_pid == -1 && !system_wide)
569 usage_with_options(record_usage, options); 675 usage_with_options(record_usage, options);
570 676
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 82fa93b4db99..99274cec0adb 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -10,13 +10,16 @@
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"
18 20
19#include "perf.h" 21#include "perf.h"
22#include "util/header.h"
20 23
21#include "util/parse-options.h" 24#include "util/parse-options.h"
22#include "util/parse-events.h" 25#include "util/parse-events.h"
@@ -28,53 +31,90 @@
28static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
29static char *vmlinux = NULL; 32static char *vmlinux = NULL;
30 33
31static char default_sort_order[] = "comm,dso"; 34static char default_sort_order[] = "comm,dso,symbol";
32static char *sort_order = default_sort_order; 35static char *sort_order = default_sort_order;
36static char *dso_list_str, *comm_list_str, *sym_list_str,
37 *col_width_list_str;
38static struct strlist *dso_list, *comm_list, *sym_list;
39static char *field_sep;
33 40
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 dump_trace = 0;
38#define dprintf(x...) do { if (dump_trace) printf(x); } while (0) 45#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
46#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
39 47
40static int verbose; 48static int verbose;
49#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
50
51static int modules;
52
41static int full_paths; 53static int full_paths;
54static int show_nr_samples;
42 55
43static unsigned long page_size; 56static unsigned long page_size;
44static unsigned long mmap_window = 32; 57static unsigned long mmap_window = 32;
45 58
59static char default_parent_pattern[] = "^sys_|^do_page_fault";
60static char *parent_pattern = default_parent_pattern;
61static regex_t parent_regex;
62
63static int exclude_other = 1;
64
65static char callchain_default_opt[] = "fractal,0.5";
66
67static int callchain;
68
69static
70struct callchain_param callchain_param = {
71 .mode = CHAIN_GRAPH_REL,
72 .min_percent = 0.5
73};
74
75static u64 sample_type;
76
46struct ip_event { 77struct ip_event {
47 struct perf_event_header header; 78 struct perf_event_header header;
48 __u64 ip; 79 u64 ip;
49 __u32 pid, tid; 80 u32 pid, tid;
50 __u64 period; 81 unsigned char __more_data[];
51}; 82};
52 83
53struct mmap_event { 84struct mmap_event {
54 struct perf_event_header header; 85 struct perf_event_header header;
55 __u32 pid, tid; 86 u32 pid, tid;
56 __u64 start; 87 u64 start;
57 __u64 len; 88 u64 len;
58 __u64 pgoff; 89 u64 pgoff;
59 char filename[PATH_MAX]; 90 char filename[PATH_MAX];
60}; 91};
61 92
62struct comm_event { 93struct comm_event {
63 struct perf_event_header header; 94 struct perf_event_header header;
64 __u32 pid, tid; 95 u32 pid, tid;
65 char comm[16]; 96 char comm[16];
66}; 97};
67 98
68struct fork_event { 99struct fork_event {
69 struct perf_event_header header; 100 struct perf_event_header header;
70 __u32 pid, ppid; 101 u32 pid, ppid;
102 u32 tid, ptid;
103};
104
105struct lost_event {
106 struct perf_event_header header;
107 u64 id;
108 u64 lost;
71}; 109};
72 110
73struct period_event { 111struct read_event {
74 struct perf_event_header header; 112 struct perf_event_header header;
75 __u64 time; 113 u32 pid,tid;
76 __u64 id; 114 u64 value;
77 __u64 sample_period; 115 u64 time_enabled;
116 u64 time_running;
117 u64 id;
78}; 118};
79 119
80typedef union event_union { 120typedef union event_union {
@@ -83,12 +123,41 @@ typedef union event_union {
83 struct mmap_event mmap; 123 struct mmap_event mmap;
84 struct comm_event comm; 124 struct comm_event comm;
85 struct fork_event fork; 125 struct fork_event fork;
86 struct period_event period; 126 struct lost_event lost;
127 struct read_event read;
87} event_t; 128} event_t;
88 129
130static int repsep_fprintf(FILE *fp, const char *fmt, ...)
131{
132 int n;
133 va_list ap;
134
135 va_start(ap, fmt);
136 if (!field_sep)
137 n = vfprintf(fp, fmt, ap);
138 else {
139 char *bf = NULL;
140 n = vasprintf(&bf, fmt, ap);
141 if (n > 0) {
142 char *sep = bf;
143 while (1) {
144 sep = strchr(sep, *field_sep);
145 if (sep == NULL)
146 break;
147 *sep = '.';
148 }
149 }
150 fputs(bf, fp);
151 free(bf);
152 }
153 va_end(ap);
154 return n;
155}
156
89static LIST_HEAD(dsos); 157static LIST_HEAD(dsos);
90static struct dso *kernel_dso; 158static struct dso *kernel_dso;
91static struct dso *vdso; 159static struct dso *vdso;
160static struct dso *hypervisor_dso;
92 161
93static void dsos__add(struct dso *dso) 162static void dsos__add(struct dso *dso)
94{ 163{
@@ -119,15 +188,11 @@ static struct dso *dsos__findnew(const char *name)
119 188
120 nr = dso__load(dso, NULL, verbose); 189 nr = dso__load(dso, NULL, verbose);
121 if (nr < 0) { 190 if (nr < 0) {
122 if (verbose) 191 eprintf("Failed to open: %s\n", name);
123 fprintf(stderr, "Failed to open: %s\n", name);
124 goto out_delete_dso; 192 goto out_delete_dso;
125 } 193 }
126 if (!nr && verbose) { 194 if (!nr)
127 fprintf(stderr, 195 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
128 "No symbols found in: %s, maybe install a debug package?\n",
129 name);
130 }
131 196
132 dsos__add(dso); 197 dsos__add(dso);
133 198
@@ -146,9 +211,9 @@ static void dsos__fprintf(FILE *fp)
146 dso__fprintf(pos, fp); 211 dso__fprintf(pos, fp);
147} 212}
148 213
149static struct symbol *vdso__find_symbol(struct dso *dso, __u64 ip) 214static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
150{ 215{
151 return dso__find_symbol(kernel_dso, ip); 216 return dso__find_symbol(dso, ip);
152} 217}
153 218
154static int load_kernel(void) 219static int load_kernel(void)
@@ -159,8 +224,8 @@ static int load_kernel(void)
159 if (!kernel_dso) 224 if (!kernel_dso)
160 return -1; 225 return -1;
161 226
162 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); 227 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
163 if (err) { 228 if (err <= 0) {
164 dso__delete(kernel_dso); 229 dso__delete(kernel_dso);
165 kernel_dso = NULL; 230 kernel_dso = NULL;
166 } else 231 } else
@@ -174,6 +239,11 @@ static int load_kernel(void)
174 239
175 dsos__add(vdso); 240 dsos__add(vdso);
176 241
242 hypervisor_dso = dso__new("[hypervisor]", 0);
243 if (!hypervisor_dso)
244 return -1;
245 dsos__add(hypervisor_dso);
246
177 return err; 247 return err;
178} 248}
179 249
@@ -185,7 +255,7 @@ static int strcommon(const char *pathname)
185{ 255{
186 int n = 0; 256 int n = 0;
187 257
188 while (pathname[n] == cwd[n] && n < cwdlen) 258 while (n < cwdlen && pathname[n] == cwd[n])
189 ++n; 259 ++n;
190 260
191 return n; 261 return n;
@@ -193,26 +263,26 @@ static int strcommon(const char *pathname)
193 263
194struct map { 264struct map {
195 struct list_head node; 265 struct list_head node;
196 __u64 start; 266 u64 start;
197 __u64 end; 267 u64 end;
198 __u64 pgoff; 268 u64 pgoff;
199 __u64 (*map_ip)(struct map *, __u64); 269 u64 (*map_ip)(struct map *, u64);
200 struct dso *dso; 270 struct dso *dso;
201}; 271};
202 272
203static __u64 map__map_ip(struct map *map, __u64 ip) 273static u64 map__map_ip(struct map *map, u64 ip)
204{ 274{
205 return ip - map->start + map->pgoff; 275 return ip - map->start + map->pgoff;
206} 276}
207 277
208static __u64 vdso__map_ip(struct map *map, __u64 ip) 278static u64 vdso__map_ip(struct map *map __used, u64 ip)
209{ 279{
210 return ip; 280 return ip;
211} 281}
212 282
213static inline int is_anon_memory(const char *filename) 283static inline int is_anon_memory(const char *filename)
214{ 284{
215 return strcmp(filename, "//anon") == 0; 285 return strcmp(filename, "//anon") == 0;
216} 286}
217 287
218static struct map *map__new(struct mmap_event *event) 288static struct map *map__new(struct mmap_event *event)
@@ -315,12 +385,28 @@ static struct thread *thread__new(pid_t pid)
315 return self; 385 return self;
316} 386}
317 387
388static unsigned int dsos__col_width,
389 comms__col_width,
390 threads__col_width;
391
318static int thread__set_comm(struct thread *self, const char *comm) 392static int thread__set_comm(struct thread *self, const char *comm)
319{ 393{
320 if (self->comm) 394 if (self->comm)
321 free(self->comm); 395 free(self->comm);
322 self->comm = strdup(comm); 396 self->comm = strdup(comm);
323 return self->comm ? 0 : -ENOMEM; 397 if (!self->comm)
398 return -ENOMEM;
399
400 if (!col_width_list_str && !field_sep &&
401 (!comm_list || strlist__has_entry(comm_list, comm))) {
402 unsigned int slen = strlen(comm);
403 if (slen > comms__col_width) {
404 comms__col_width = slen;
405 threads__col_width = slen + 6;
406 }
407 }
408
409 return 0;
324} 410}
325 411
326static size_t thread__fprintf(struct thread *self, FILE *fp) 412static size_t thread__fprintf(struct thread *self, FILE *fp)
@@ -383,9 +469,27 @@ static void thread__insert_map(struct thread *self, struct map *map)
383 469
384 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 470 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
385 if (map__overlap(pos, map)) { 471 if (map__overlap(pos, map)) {
386 list_del_init(&pos->node); 472 if (verbose >= 2) {
387 /* XXX leaks dsos */ 473 printf("overlapping maps:\n");
388 free(pos); 474 map__fprintf(map, stdout);
475 map__fprintf(pos, stdout);
476 }
477
478 if (map->start <= pos->start && map->end > pos->start)
479 pos->start = map->end;
480
481 if (map->end >= pos->end && map->start < pos->end)
482 pos->end = map->start;
483
484 if (verbose >= 2) {
485 printf("after collision:\n");
486 map__fprintf(pos, stdout);
487 }
488
489 if (pos->start >= pos->end) {
490 list_del_init(&pos->node);
491 free(pos);
492 }
389 } 493 }
390 } 494 }
391 495
@@ -412,7 +516,7 @@ static int thread__fork(struct thread *self, struct thread *parent)
412 return 0; 516 return 0;
413} 517}
414 518
415static struct map *thread__find_map(struct thread *self, __u64 ip) 519static struct map *thread__find_map(struct thread *self, u64 ip)
416{ 520{
417 struct map *pos; 521 struct map *pos;
418 522
@@ -447,16 +551,19 @@ static size_t threads__fprintf(FILE *fp)
447static struct rb_root hist; 551static struct rb_root hist;
448 552
449struct hist_entry { 553struct hist_entry {
450 struct rb_node rb_node; 554 struct rb_node rb_node;
451 555
452 struct thread *thread; 556 struct thread *thread;
453 struct map *map; 557 struct map *map;
454 struct dso *dso; 558 struct dso *dso;
455 struct symbol *sym; 559 struct symbol *sym;
456 __u64 ip; 560 struct symbol *parent;
457 char level; 561 u64 ip;
458 562 char level;
459 __u64 count; 563 struct callchain_node callchain;
564 struct rb_root sorted_chain;
565
566 u64 count;
460}; 567};
461 568
462/* 569/*
@@ -470,9 +577,21 @@ struct sort_entry {
470 577
471 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 578 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
472 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 579 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
473 size_t (*print)(FILE *fp, struct hist_entry *); 580 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
581 unsigned int *width;
582 bool elide;
474}; 583};
475 584
585static int64_t cmp_null(void *l, void *r)
586{
587 if (!l && !r)
588 return 0;
589 else if (!l)
590 return -1;
591 else
592 return 1;
593}
594
476/* --sort pid */ 595/* --sort pid */
477 596
478static int64_t 597static int64_t
@@ -482,15 +601,17 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
482} 601}
483 602
484static size_t 603static size_t
485sort__thread_print(FILE *fp, struct hist_entry *self) 604sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
486{ 605{
487 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); 606 return repsep_fprintf(fp, "%*s:%5d", width - 6,
607 self->thread->comm ?: "", self->thread->pid);
488} 608}
489 609
490static struct sort_entry sort_thread = { 610static struct sort_entry sort_thread = {
491 .header = " Command: Pid", 611 .header = "Command: Pid",
492 .cmp = sort__thread_cmp, 612 .cmp = sort__thread_cmp,
493 .print = sort__thread_print, 613 .print = sort__thread_print,
614 .width = &threads__col_width,
494}; 615};
495 616
496/* --sort comm */ 617/* --sort comm */
@@ -507,29 +628,24 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
507 char *comm_l = left->thread->comm; 628 char *comm_l = left->thread->comm;
508 char *comm_r = right->thread->comm; 629 char *comm_r = right->thread->comm;
509 630
510 if (!comm_l || !comm_r) { 631 if (!comm_l || !comm_r)
511 if (!comm_l && !comm_r) 632 return cmp_null(comm_l, comm_r);
512 return 0;
513 else if (!comm_l)
514 return -1;
515 else
516 return 1;
517 }
518 633
519 return strcmp(comm_l, comm_r); 634 return strcmp(comm_l, comm_r);
520} 635}
521 636
522static size_t 637static size_t
523sort__comm_print(FILE *fp, struct hist_entry *self) 638sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
524{ 639{
525 return fprintf(fp, "%16s", self->thread->comm); 640 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
526} 641}
527 642
528static struct sort_entry sort_comm = { 643static struct sort_entry sort_comm = {
529 .header = " Command", 644 .header = "Command",
530 .cmp = sort__comm_cmp, 645 .cmp = sort__comm_cmp,
531 .collapse = sort__comm_collapse, 646 .collapse = sort__comm_collapse,
532 .print = sort__comm_print, 647 .print = sort__comm_print,
648 .width = &comms__col_width,
533}; 649};
534 650
535/* --sort dso */ 651/* --sort dso */
@@ -540,31 +656,26 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
540 struct dso *dso_l = left->dso; 656 struct dso *dso_l = left->dso;
541 struct dso *dso_r = right->dso; 657 struct dso *dso_r = right->dso;
542 658
543 if (!dso_l || !dso_r) { 659 if (!dso_l || !dso_r)
544 if (!dso_l && !dso_r) 660 return cmp_null(dso_l, dso_r);
545 return 0;
546 else if (!dso_l)
547 return -1;
548 else
549 return 1;
550 }
551 661
552 return strcmp(dso_l->name, dso_r->name); 662 return strcmp(dso_l->name, dso_r->name);
553} 663}
554 664
555static size_t 665static size_t
556sort__dso_print(FILE *fp, struct hist_entry *self) 666sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
557{ 667{
558 if (self->dso) 668 if (self->dso)
559 return fprintf(fp, "%-25s", self->dso->name); 669 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
560 670
561 return fprintf(fp, "%016llx ", (__u64)self->ip); 671 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
562} 672}
563 673
564static struct sort_entry sort_dso = { 674static struct sort_entry sort_dso = {
565 .header = "Shared Object ", 675 .header = "Shared Object",
566 .cmp = sort__dso_cmp, 676 .cmp = sort__dso_cmp,
567 .print = sort__dso_print, 677 .print = sort__dso_print,
678 .width = &dsos__col_width,
568}; 679};
569 680
570/* --sort symbol */ 681/* --sort symbol */
@@ -572,7 +683,7 @@ static struct sort_entry sort_dso = {
572static int64_t 683static int64_t
573sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 684sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
574{ 685{
575 __u64 ip_l, ip_r; 686 u64 ip_l, ip_r;
576 687
577 if (left->sym == right->sym) 688 if (left->sym == right->sym)
578 return 0; 689 return 0;
@@ -584,18 +695,23 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
584} 695}
585 696
586static size_t 697static size_t
587sort__sym_print(FILE *fp, struct hist_entry *self) 698sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
588{ 699{
589 size_t ret = 0; 700 size_t ret = 0;
590 701
591 if (verbose) 702 if (verbose)
592 ret += fprintf(fp, "%#018llx ", (__u64)self->ip); 703 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
704 dso__symtab_origin(self->dso));
593 705
706 ret += repsep_fprintf(fp, "[%c] ", self->level);
594 if (self->sym) { 707 if (self->sym) {
595 ret += fprintf(fp, "[%c] %s", 708 ret += repsep_fprintf(fp, "%s", self->sym->name);
596 self->dso == kernel_dso ? 'k' : '.', self->sym->name); 709
710 if (self->sym->module)
711 ret += repsep_fprintf(fp, "\t[%s]",
712 self->sym->module->name);
597 } else { 713 } else {
598 ret += fprintf(fp, "%#016llx", (__u64)self->ip); 714 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
599 } 715 }
600 716
601 return ret; 717 return ret;
@@ -607,7 +723,38 @@ static struct sort_entry sort_sym = {
607 .print = sort__sym_print, 723 .print = sort__sym_print,
608}; 724};
609 725
726/* --sort parent */
727
728static int64_t
729sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
730{
731 struct symbol *sym_l = left->parent;
732 struct symbol *sym_r = right->parent;
733
734 if (!sym_l || !sym_r)
735 return cmp_null(sym_l, sym_r);
736
737 return strcmp(sym_l->name, sym_r->name);
738}
739
740static size_t
741sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
742{
743 return repsep_fprintf(fp, "%-*s", width,
744 self->parent ? self->parent->name : "[other]");
745}
746
747static unsigned int parent_symbol__col_width;
748
749static struct sort_entry sort_parent = {
750 .header = "Parent symbol",
751 .cmp = sort__parent_cmp,
752 .print = sort__parent_print,
753 .width = &parent_symbol__col_width,
754};
755
610static int sort__need_collapse = 0; 756static int sort__need_collapse = 0;
757static int sort__has_parent = 0;
611 758
612struct sort_dimension { 759struct sort_dimension {
613 char *name; 760 char *name;
@@ -620,13 +767,14 @@ static struct sort_dimension sort_dimensions[] = {
620 { .name = "comm", .entry = &sort_comm, }, 767 { .name = "comm", .entry = &sort_comm, },
621 { .name = "dso", .entry = &sort_dso, }, 768 { .name = "dso", .entry = &sort_dso, },
622 { .name = "symbol", .entry = &sort_sym, }, 769 { .name = "symbol", .entry = &sort_sym, },
770 { .name = "parent", .entry = &sort_parent, },
623}; 771};
624 772
625static LIST_HEAD(hist_entry__sort_list); 773static LIST_HEAD(hist_entry__sort_list);
626 774
627static int sort_dimension__add(char *tok) 775static int sort_dimension__add(char *tok)
628{ 776{
629 int i; 777 unsigned int i;
630 778
631 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 779 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
632 struct sort_dimension *sd = &sort_dimensions[i]; 780 struct sort_dimension *sd = &sort_dimensions[i];
@@ -640,6 +788,19 @@ static int sort_dimension__add(char *tok)
640 if (sd->entry->collapse) 788 if (sd->entry->collapse)
641 sort__need_collapse = 1; 789 sort__need_collapse = 1;
642 790
791 if (sd->entry == &sort_parent) {
792 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
793 if (ret) {
794 char err[BUFSIZ];
795
796 regerror(ret, &parent_regex, err, sizeof(err));
797 fprintf(stderr, "Invalid regex: %s\n%s",
798 parent_pattern, err);
799 exit(-1);
800 }
801 sort__has_parent = 1;
802 }
803
643 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 804 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
644 sd->taken = 1; 805 sd->taken = 1;
645 806
@@ -683,54 +844,388 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
683 return cmp; 844 return cmp;
684} 845}
685 846
847static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
848{
849 int i;
850 size_t ret = 0;
851
852 ret += fprintf(fp, "%s", " ");
853
854 for (i = 0; i < depth; i++)
855 if (depth_mask & (1 << i))
856 ret += fprintf(fp, "| ");
857 else
858 ret += fprintf(fp, " ");
859
860 ret += fprintf(fp, "\n");
861
862 return ret;
863}
686static size_t 864static size_t
687hist_entry__fprintf(FILE *fp, struct hist_entry *self, __u64 total_samples) 865ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
866 int depth_mask, int count, u64 total_samples,
867 int hits)
688{ 868{
689 struct sort_entry *se; 869 int i;
690 size_t ret; 870 size_t ret = 0;
691 871
692 if (total_samples) { 872 ret += fprintf(fp, "%s", " ");
693 double percent = self->count * 100.0 / total_samples; 873 for (i = 0; i < depth; i++) {
694 char *color = PERF_COLOR_NORMAL; 874 if (depth_mask & (1 << i))
875 ret += fprintf(fp, "|");
876 else
877 ret += fprintf(fp, " ");
878 if (!count && i == depth - 1) {
879 double percent;
880
881 percent = hits * 100.0 / total_samples;
882 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
883 } else
884 ret += fprintf(fp, "%s", " ");
885 }
886 if (chain->sym)
887 ret += fprintf(fp, "%s\n", chain->sym->name);
888 else
889 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
890
891 return ret;
892}
893
894static struct symbol *rem_sq_bracket;
895static struct callchain_list rem_hits;
896
897static void init_rem_hits(void)
898{
899 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
900 if (!rem_sq_bracket) {
901 fprintf(stderr, "Not enough memory to display remaining hits\n");
902 return;
903 }
904
905 strcpy(rem_sq_bracket->name, "[...]");
906 rem_hits.sym = rem_sq_bracket;
907}
908
909static size_t
910callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
911 u64 total_samples, int depth, int depth_mask)
912{
913 struct rb_node *node, *next;
914 struct callchain_node *child;
915 struct callchain_list *chain;
916 int new_depth_mask = depth_mask;
917 u64 new_total;
918 u64 remaining;
919 size_t ret = 0;
920 int i;
921
922 if (callchain_param.mode == CHAIN_GRAPH_REL)
923 new_total = self->children_hit;
924 else
925 new_total = total_samples;
926
927 remaining = new_total;
928
929 node = rb_first(&self->rb_root);
930 while (node) {
931 u64 cumul;
932
933 child = rb_entry(node, struct callchain_node, rb_node);
934 cumul = cumul_hits(child);
935 remaining -= cumul;
695 936
696 /* 937 /*
697 * We color high-overhead entries in red, mid-overhead 938 * The depth mask manages the output of pipes that show
698 * entries in green - and keep the low overhead places 939 * the depth. We don't want to keep the pipes of the current
699 * normal: 940 * level for the last child of this depth.
941 * Except if we have remaining filtered hits. They will
942 * supersede the last child
700 */ 943 */
701 if (percent >= 5.0) { 944 next = rb_next(node);
702 color = PERF_COLOR_RED; 945 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
703 } else { 946 new_depth_mask &= ~(1 << (depth - 1));
704 if (percent >= 0.5) 947
705 color = PERF_COLOR_GREEN; 948 /*
949 * But we keep the older depth mask for the line seperator
950 * to keep the level link until we reach the last child
951 */
952 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
953 i = 0;
954 list_for_each_entry(chain, &child->val, list) {
955 if (chain->ip >= PERF_CONTEXT_MAX)
956 continue;
957 ret += ipchain__fprintf_graph(fp, chain, depth,
958 new_depth_mask, i++,
959 new_total,
960 cumul);
706 } 961 }
962 ret += callchain__fprintf_graph(fp, child, new_total,
963 depth + 1,
964 new_depth_mask | (1 << depth));
965 node = next;
966 }
707 967
708 ret = color_fprintf(fp, color, " %6.2f%%", 968 if (callchain_param.mode == CHAIN_GRAPH_REL &&
709 (self->count * 100.0) / total_samples); 969 remaining && remaining != new_total) {
710 } else 970
711 ret = fprintf(fp, "%12Ld ", self->count); 971 if (!rem_sq_bracket)
972 return ret;
973
974 new_depth_mask &= ~(1 << (depth - 1));
975
976 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
977 new_depth_mask, 0, new_total,
978 remaining);
979 }
980
981 return ret;
982}
983
984static size_t
985callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
986 u64 total_samples)
987{
988 struct callchain_list *chain;
989 size_t ret = 0;
990
991 if (!self)
992 return 0;
993
994 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
995
996
997 list_for_each_entry(chain, &self->val, list) {
998 if (chain->ip >= PERF_CONTEXT_MAX)
999 continue;
1000 if (chain->sym)
1001 ret += fprintf(fp, " %s\n", chain->sym->name);
1002 else
1003 ret += fprintf(fp, " %p\n",
1004 (void *)(long)chain->ip);
1005 }
1006
1007 return ret;
1008}
1009
1010static size_t
1011hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
1012 u64 total_samples)
1013{
1014 struct rb_node *rb_node;
1015 struct callchain_node *chain;
1016 size_t ret = 0;
1017
1018 rb_node = rb_first(&self->sorted_chain);
1019 while (rb_node) {
1020 double percent;
1021
1022 chain = rb_entry(rb_node, struct callchain_node, rb_node);
1023 percent = chain->hit * 100.0 / total_samples;
1024 switch (callchain_param.mode) {
1025 case CHAIN_FLAT:
1026 ret += percent_color_fprintf(fp, " %6.2f%%\n",
1027 percent);
1028 ret += callchain__fprintf_flat(fp, chain, total_samples);
1029 break;
1030 case CHAIN_GRAPH_ABS: /* Falldown */
1031 case CHAIN_GRAPH_REL:
1032 ret += callchain__fprintf_graph(fp, chain,
1033 total_samples, 1, 1);
1034 default:
1035 break;
1036 }
1037 ret += fprintf(fp, "\n");
1038 rb_node = rb_next(rb_node);
1039 }
1040
1041 return ret;
1042}
1043
1044
1045static size_t
1046hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
1047{
1048 struct sort_entry *se;
1049 size_t ret;
1050
1051 if (exclude_other && !self->parent)
1052 return 0;
1053
1054 if (total_samples)
1055 ret = percent_color_fprintf(fp,
1056 field_sep ? "%.2f" : " %6.2f%%",
1057 (self->count * 100.0) / total_samples);
1058 else
1059 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
1060
1061 if (show_nr_samples) {
1062 if (field_sep)
1063 fprintf(fp, "%c%lld", *field_sep, self->count);
1064 else
1065 fprintf(fp, "%11lld", self->count);
1066 }
712 1067
713 list_for_each_entry(se, &hist_entry__sort_list, list) { 1068 list_for_each_entry(se, &hist_entry__sort_list, list) {
714 fprintf(fp, " "); 1069 if (se->elide)
715 ret += se->print(fp, self); 1070 continue;
1071
1072 fprintf(fp, "%s", field_sep ?: " ");
1073 ret += se->print(fp, self, se->width ? *se->width : 0);
716 } 1074 }
717 1075
718 ret += fprintf(fp, "\n"); 1076 ret += fprintf(fp, "\n");
719 1077
1078 if (callchain)
1079 hist_entry_callchain__fprintf(fp, self, total_samples);
1080
720 return ret; 1081 return ret;
721} 1082}
722 1083
723/* 1084/*
1085 *
1086 */
1087
1088static void dso__calc_col_width(struct dso *self)
1089{
1090 if (!col_width_list_str && !field_sep &&
1091 (!dso_list || strlist__has_entry(dso_list, self->name))) {
1092 unsigned int slen = strlen(self->name);
1093 if (slen > dsos__col_width)
1094 dsos__col_width = slen;
1095 }
1096
1097 self->slen_calculated = 1;
1098}
1099
1100static struct symbol *
1101resolve_symbol(struct thread *thread, struct map **mapp,
1102 struct dso **dsop, u64 *ipp)
1103{
1104 struct dso *dso = dsop ? *dsop : NULL;
1105 struct map *map = mapp ? *mapp : NULL;
1106 u64 ip = *ipp;
1107
1108 if (!thread)
1109 return NULL;
1110
1111 if (dso)
1112 goto got_dso;
1113
1114 if (map)
1115 goto got_map;
1116
1117 map = thread__find_map(thread, ip);
1118 if (map != NULL) {
1119 /*
1120 * We have to do this here as we may have a dso
1121 * with no symbol hit that has a name longer than
1122 * the ones with symbols sampled.
1123 */
1124 if (!sort_dso.elide && !map->dso->slen_calculated)
1125 dso__calc_col_width(map->dso);
1126
1127 if (mapp)
1128 *mapp = map;
1129got_map:
1130 ip = map->map_ip(map, ip);
1131
1132 dso = map->dso;
1133 } else {
1134 /*
1135 * If this is outside of all known maps,
1136 * and is a negative address, try to look it
1137 * up in the kernel dso, as it might be a
1138 * vsyscall (which executes in user-mode):
1139 */
1140 if ((long long)ip < 0)
1141 dso = kernel_dso;
1142 }
1143 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
1144 dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
1145 *ipp = ip;
1146
1147 if (dsop)
1148 *dsop = dso;
1149
1150 if (!dso)
1151 return NULL;
1152got_dso:
1153 return dso->find_symbol(dso, ip);
1154}
1155
1156static int call__match(struct symbol *sym)
1157{
1158 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
1159 return 1;
1160
1161 return 0;
1162}
1163
1164static struct symbol **
1165resolve_callchain(struct thread *thread, struct map *map __used,
1166 struct ip_callchain *chain, struct hist_entry *entry)
1167{
1168 u64 context = PERF_CONTEXT_MAX;
1169 struct symbol **syms = NULL;
1170 unsigned int i;
1171
1172 if (callchain) {
1173 syms = calloc(chain->nr, sizeof(*syms));
1174 if (!syms) {
1175 fprintf(stderr, "Can't allocate memory for symbols\n");
1176 exit(-1);
1177 }
1178 }
1179
1180 for (i = 0; i < chain->nr; i++) {
1181 u64 ip = chain->ips[i];
1182 struct dso *dso = NULL;
1183 struct symbol *sym;
1184
1185 if (ip >= PERF_CONTEXT_MAX) {
1186 context = ip;
1187 continue;
1188 }
1189
1190 switch (context) {
1191 case PERF_CONTEXT_HV:
1192 dso = hypervisor_dso;
1193 break;
1194 case PERF_CONTEXT_KERNEL:
1195 dso = kernel_dso;
1196 break;
1197 default:
1198 break;
1199 }
1200
1201 sym = resolve_symbol(thread, NULL, &dso, &ip);
1202
1203 if (sym) {
1204 if (sort__has_parent && call__match(sym) &&
1205 !entry->parent)
1206 entry->parent = sym;
1207 if (!callchain)
1208 break;
1209 syms[i] = sym;
1210 }
1211 }
1212
1213 return syms;
1214}
1215
1216/*
724 * collect histogram counts 1217 * collect histogram counts
725 */ 1218 */
726 1219
727static int 1220static int
728hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 1221hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
729 struct symbol *sym, __u64 ip, char level, __u64 count) 1222 struct symbol *sym, u64 ip, struct ip_callchain *chain,
1223 char level, u64 count)
730{ 1224{
731 struct rb_node **p = &hist.rb_node; 1225 struct rb_node **p = &hist.rb_node;
732 struct rb_node *parent = NULL; 1226 struct rb_node *parent = NULL;
733 struct hist_entry *he; 1227 struct hist_entry *he;
1228 struct symbol **syms = NULL;
734 struct hist_entry entry = { 1229 struct hist_entry entry = {
735 .thread = thread, 1230 .thread = thread,
736 .map = map, 1231 .map = map,
@@ -739,9 +1234,14 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
739 .ip = ip, 1234 .ip = ip,
740 .level = level, 1235 .level = level,
741 .count = count, 1236 .count = count,
1237 .parent = NULL,
1238 .sorted_chain = RB_ROOT
742 }; 1239 };
743 int cmp; 1240 int cmp;
744 1241
1242 if ((sort__has_parent || callchain) && chain)
1243 syms = resolve_callchain(thread, map, chain, &entry);
1244
745 while (*p != NULL) { 1245 while (*p != NULL) {
746 parent = *p; 1246 parent = *p;
747 he = rb_entry(parent, struct hist_entry, rb_node); 1247 he = rb_entry(parent, struct hist_entry, rb_node);
@@ -750,6 +1250,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
750 1250
751 if (!cmp) { 1251 if (!cmp) {
752 he->count += count; 1252 he->count += count;
1253 if (callchain) {
1254 append_chain(&he->callchain, chain, syms);
1255 free(syms);
1256 }
753 return 0; 1257 return 0;
754 } 1258 }
755 1259
@@ -763,6 +1267,11 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
763 if (!he) 1267 if (!he)
764 return -ENOMEM; 1268 return -ENOMEM;
765 *he = entry; 1269 *he = entry;
1270 if (callchain) {
1271 callchain_init(&he->callchain);
1272 append_chain(&he->callchain, chain, syms);
1273 free(syms);
1274 }
766 rb_link_node(&he->rb_node, parent, p); 1275 rb_link_node(&he->rb_node, parent, p);
767 rb_insert_color(&he->rb_node, &hist); 1276 rb_insert_color(&he->rb_node, &hist);
768 1277
@@ -833,12 +1342,16 @@ static void collapse__resort(void)
833 1342
834static struct rb_root output_hists; 1343static struct rb_root output_hists;
835 1344
836static void output__insert_entry(struct hist_entry *he) 1345static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
837{ 1346{
838 struct rb_node **p = &output_hists.rb_node; 1347 struct rb_node **p = &output_hists.rb_node;
839 struct rb_node *parent = NULL; 1348 struct rb_node *parent = NULL;
840 struct hist_entry *iter; 1349 struct hist_entry *iter;
841 1350
1351 if (callchain)
1352 callchain_param.sort(&he->sorted_chain, &he->callchain,
1353 min_callchain_hits, &callchain_param);
1354
842 while (*p != NULL) { 1355 while (*p != NULL) {
843 parent = *p; 1356 parent = *p;
844 iter = rb_entry(parent, struct hist_entry, rb_node); 1357 iter = rb_entry(parent, struct hist_entry, rb_node);
@@ -853,11 +1366,14 @@ static void output__insert_entry(struct hist_entry *he)
853 rb_insert_color(&he->rb_node, &output_hists); 1366 rb_insert_color(&he->rb_node, &output_hists);
854} 1367}
855 1368
856static void output__resort(void) 1369static void output__resort(u64 total_samples)
857{ 1370{
858 struct rb_node *next; 1371 struct rb_node *next;
859 struct hist_entry *n; 1372 struct hist_entry *n;
860 struct rb_root *tree = &hist; 1373 struct rb_root *tree = &hist;
1374 u64 min_callchain_hits;
1375
1376 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
861 1377
862 if (sort__need_collapse) 1378 if (sort__need_collapse)
863 tree = &collapse_hists; 1379 tree = &collapse_hists;
@@ -869,51 +1385,94 @@ static void output__resort(void)
869 next = rb_next(&n->rb_node); 1385 next = rb_next(&n->rb_node);
870 1386
871 rb_erase(&n->rb_node, tree); 1387 rb_erase(&n->rb_node, tree);
872 output__insert_entry(n); 1388 output__insert_entry(n, min_callchain_hits);
873 } 1389 }
874} 1390}
875 1391
876static size_t output__fprintf(FILE *fp, __u64 total_samples) 1392static size_t output__fprintf(FILE *fp, u64 total_samples)
877{ 1393{
878 struct hist_entry *pos; 1394 struct hist_entry *pos;
879 struct sort_entry *se; 1395 struct sort_entry *se;
880 struct rb_node *nd; 1396 struct rb_node *nd;
881 size_t ret = 0; 1397 size_t ret = 0;
1398 unsigned int width;
1399 char *col_width = col_width_list_str;
882 1400
883 fprintf(fp, "\n"); 1401 init_rem_hits();
884 fprintf(fp, "#\n"); 1402
885 fprintf(fp, "# (%Ld samples)\n", (__u64)total_samples); 1403 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
886 fprintf(fp, "#\n"); 1404 fprintf(fp, "#\n");
887 1405
888 fprintf(fp, "# Overhead"); 1406 fprintf(fp, "# Overhead");
889 list_for_each_entry(se, &hist_entry__sort_list, list) 1407 if (show_nr_samples) {
890 fprintf(fp, " %s", se->header); 1408 if (field_sep)
1409 fprintf(fp, "%cSamples", *field_sep);
1410 else
1411 fputs(" Samples ", fp);
1412 }
1413 list_for_each_entry(se, &hist_entry__sort_list, list) {
1414 if (se->elide)
1415 continue;
1416 if (field_sep) {
1417 fprintf(fp, "%c%s", *field_sep, se->header);
1418 continue;
1419 }
1420 width = strlen(se->header);
1421 if (se->width) {
1422 if (col_width_list_str) {
1423 if (col_width) {
1424 *se->width = atoi(col_width);
1425 col_width = strchr(col_width, ',');
1426 if (col_width)
1427 ++col_width;
1428 }
1429 }
1430 width = *se->width = max(*se->width, width);
1431 }
1432 fprintf(fp, " %*s", width, se->header);
1433 }
891 fprintf(fp, "\n"); 1434 fprintf(fp, "\n");
892 1435
1436 if (field_sep)
1437 goto print_entries;
1438
893 fprintf(fp, "# ........"); 1439 fprintf(fp, "# ........");
1440 if (show_nr_samples)
1441 fprintf(fp, " ..........");
894 list_for_each_entry(se, &hist_entry__sort_list, list) { 1442 list_for_each_entry(se, &hist_entry__sort_list, list) {
895 int i; 1443 unsigned int i;
1444
1445 if (se->elide)
1446 continue;
896 1447
897 fprintf(fp, " "); 1448 fprintf(fp, " ");
898 for (i = 0; i < strlen(se->header); i++) 1449 if (se->width)
1450 width = *se->width;
1451 else
1452 width = strlen(se->header);
1453 for (i = 0; i < width; i++)
899 fprintf(fp, "."); 1454 fprintf(fp, ".");
900 } 1455 }
901 fprintf(fp, "\n"); 1456 fprintf(fp, "\n");
902 1457
903 fprintf(fp, "#\n"); 1458 fprintf(fp, "#\n");
904 1459
1460print_entries:
905 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 1461 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
906 pos = rb_entry(nd, struct hist_entry, rb_node); 1462 pos = rb_entry(nd, struct hist_entry, rb_node);
907 ret += hist_entry__fprintf(fp, pos, total_samples); 1463 ret += hist_entry__fprintf(fp, pos, total_samples);
908 } 1464 }
909 1465
910 if (!strcmp(sort_order, default_sort_order)) { 1466 if (sort_order == default_sort_order &&
1467 parent_pattern == default_parent_pattern) {
911 fprintf(fp, "#\n"); 1468 fprintf(fp, "#\n");
912 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); 1469 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
913 fprintf(fp, "#\n"); 1470 fprintf(fp, "#\n");
914 } 1471 }
915 fprintf(fp, "\n"); 1472 fprintf(fp, "\n");
916 1473
1474 free(rem_sq_bracket);
1475
917 return ret; 1476 return ret;
918} 1477}
919 1478
@@ -932,23 +1491,42 @@ static unsigned long total = 0,
932 total_mmap = 0, 1491 total_mmap = 0,
933 total_comm = 0, 1492 total_comm = 0,
934 total_fork = 0, 1493 total_fork = 0,
935 total_unknown = 0; 1494 total_unknown = 0,
1495 total_lost = 0;
1496
1497static int validate_chain(struct ip_callchain *chain, event_t *event)
1498{
1499 unsigned int chain_size;
1500
1501 chain_size = event->header.size;
1502 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
1503
1504 if (chain->nr*sizeof(u64) > chain_size)
1505 return -1;
1506
1507 return 0;
1508}
936 1509
937static int 1510static int
938process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 1511process_sample_event(event_t *event, unsigned long offset, unsigned long head)
939{ 1512{
940 char level; 1513 char level;
941 int show = 0; 1514 int show = 0;
942 struct dso *dso = NULL; 1515 struct dso *dso = NULL;
943 struct thread *thread = threads__findnew(event->ip.pid); 1516 struct thread *thread = threads__findnew(event->ip.pid);
944 __u64 ip = event->ip.ip; 1517 u64 ip = event->ip.ip;
945 __u64 period = 1; 1518 u64 period = 1;
946 struct map *map = NULL; 1519 struct map *map = NULL;
1520 void *more_data = event->ip.__more_data;
1521 struct ip_callchain *chain = NULL;
1522 int cpumode;
947 1523
948 if (event->header.type & PERF_SAMPLE_PERIOD) 1524 if (sample_type & PERF_SAMPLE_PERIOD) {
949 period = event->ip.period; 1525 period = *(u64 *)more_data;
1526 more_data += sizeof(u64);
1527 }
950 1528
951 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n", 1529 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n",
952 (void *)(offset + head), 1530 (void *)(offset + head),
953 (void *)(long)(event->header.size), 1531 (void *)(long)(event->header.size),
954 event->header.misc, 1532 event->header.misc,
@@ -956,15 +1534,38 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
956 (void *)(long)ip, 1534 (void *)(long)ip,
957 (long long)period); 1535 (long long)period);
958 1536
1537 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1538 unsigned int i;
1539
1540 chain = (void *)more_data;
1541
1542 dprintf("... chain: nr:%Lu\n", chain->nr);
1543
1544 if (validate_chain(chain, event) < 0) {
1545 eprintf("call-chain problem with event, skipping it.\n");
1546 return 0;
1547 }
1548
1549 if (dump_trace) {
1550 for (i = 0; i < chain->nr; i++)
1551 dprintf("..... %2d: %016Lx\n", i, chain->ips[i]);
1552 }
1553 }
1554
959 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1555 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
960 1556
961 if (thread == NULL) { 1557 if (thread == NULL) {
962 fprintf(stderr, "problem processing %d event, skipping it.\n", 1558 eprintf("problem processing %d event, skipping it.\n",
963 event->header.type); 1559 event->header.type);
964 return -1; 1560 return -1;
965 } 1561 }
966 1562
967 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 1563 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1564 return 0;
1565
1566 cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
1567
1568 if (cpumode == PERF_EVENT_MISC_KERNEL) {
968 show = SHOW_KERNEL; 1569 show = SHOW_KERNEL;
969 level = 'k'; 1570 level = 'k';
970 1571
@@ -972,42 +1573,31 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
972 1573
973 dprintf(" ...... dso: %s\n", dso->name); 1574 dprintf(" ...... dso: %s\n", dso->name);
974 1575
975 } else if (event->header.misc & PERF_EVENT_MISC_USER) { 1576 } else if (cpumode == PERF_EVENT_MISC_USER) {
976 1577
977 show = SHOW_USER; 1578 show = SHOW_USER;
978 level = '.'; 1579 level = '.';
979 1580
980 map = thread__find_map(thread, ip);
981 if (map != NULL) {
982 ip = map->map_ip(map, ip);
983 dso = map->dso;
984 } else {
985 /*
986 * If this is outside of all known maps,
987 * and is a negative address, try to look it
988 * up in the kernel dso, as it might be a
989 * vsyscall (which executes in user-mode):
990 */
991 if ((long long)ip < 0)
992 dso = kernel_dso;
993 }
994 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
995
996 } else { 1581 } else {
997 show = SHOW_HV; 1582 show = SHOW_HV;
998 level = 'H'; 1583 level = 'H';
1584
1585 dso = hypervisor_dso;
1586
999 dprintf(" ...... dso: [hypervisor]\n"); 1587 dprintf(" ...... dso: [hypervisor]\n");
1000 } 1588 }
1001 1589
1002 if (show & show_mask) { 1590 if (show & show_mask) {
1003 struct symbol *sym = NULL; 1591 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1004 1592
1005 if (dso) 1593 if (dso_list && dso && dso->name && !strlist__has_entry(dso_list, dso->name))
1006 sym = dso->find_symbol(dso, ip); 1594 return 0;
1595
1596 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
1597 return 0;
1007 1598
1008 if (hist_entry__add(thread, map, dso, sym, ip, level, period)) { 1599 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1009 fprintf(stderr, 1600 eprintf("problem incrementing symbol count, skipping event\n");
1010 "problem incrementing symbol count, skipping event\n");
1011 return -1; 1601 return -1;
1012 } 1602 }
1013 } 1603 }
@@ -1063,15 +1653,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1063} 1653}
1064 1654
1065static int 1655static int
1066process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1656process_task_event(event_t *event, unsigned long offset, unsigned long head)
1067{ 1657{
1068 struct thread *thread = threads__findnew(event->fork.pid); 1658 struct thread *thread = threads__findnew(event->fork.pid);
1069 struct thread *parent = threads__findnew(event->fork.ppid); 1659 struct thread *parent = threads__findnew(event->fork.ppid);
1070 1660
1071 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1661 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1072 (void *)(offset + head), 1662 (void *)(offset + head),
1073 (void *)(long)(event->header.size), 1663 (void *)(long)(event->header.size),
1074 event->fork.pid, event->fork.ppid); 1664 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1665 event->fork.pid, event->fork.tid,
1666 event->fork.ppid, event->fork.ptid);
1667
1668 /*
1669 * A thread clone will have the same PID for both
1670 * parent and child.
1671 */
1672 if (thread == parent)
1673 return 0;
1674
1675 if (event->header.type == PERF_EVENT_EXIT)
1676 return 0;
1075 1677
1076 if (!thread || !parent || thread__fork(thread, parent)) { 1678 if (!thread || !parent || thread__fork(thread, parent)) {
1077 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1679 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
@@ -1083,14 +1685,87 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1083} 1685}
1084 1686
1085static int 1687static int
1086process_period_event(event_t *event, unsigned long offset, unsigned long head) 1688process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1087{ 1689{
1088 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n", 1690 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
1089 (void *)(offset + head), 1691 (void *)(offset + head),
1090 (void *)(long)(event->header.size), 1692 (void *)(long)(event->header.size),
1091 event->period.time, 1693 event->lost.id,
1092 event->period.id, 1694 event->lost.lost);
1093 event->period.sample_period); 1695
1696 total_lost += event->lost.lost;
1697
1698 return 0;
1699}
1700
1701static void trace_event(event_t *event)
1702{
1703 unsigned char *raw_event = (void *)event;
1704 char *color = PERF_COLOR_BLUE;
1705 int i, j;
1706
1707 if (!dump_trace)
1708 return;
1709
1710 dprintf(".");
1711 cdprintf("\n. ... raw event: size %d bytes\n", event->header.size);
1712
1713 for (i = 0; i < event->header.size; i++) {
1714 if ((i & 15) == 0) {
1715 dprintf(".");
1716 cdprintf(" %04x: ", i);
1717 }
1718
1719 cdprintf(" %02x", raw_event[i]);
1720
1721 if (((i & 15) == 15) || i == event->header.size-1) {
1722 cdprintf(" ");
1723 for (j = 0; j < 15-(i & 15); j++)
1724 cdprintf(" ");
1725 for (j = 0; j < (i & 15); j++) {
1726 if (isprint(raw_event[i-15+j]))
1727 cdprintf("%c", raw_event[i-15+j]);
1728 else
1729 cdprintf(".");
1730 }
1731 cdprintf("\n");
1732 }
1733 }
1734 dprintf(".\n");
1735}
1736
1737static struct perf_header *header;
1738
1739static struct perf_counter_attr *perf_header__find_attr(u64 id)
1740{
1741 int i;
1742
1743 for (i = 0; i < header->attrs; i++) {
1744 struct perf_header_attr *attr = header->attr[i];
1745 int j;
1746
1747 for (j = 0; j < attr->ids; j++) {
1748 if (attr->id[j] == id)
1749 return &attr->attr;
1750 }
1751 }
1752
1753 return NULL;
1754}
1755
1756static int
1757process_read_event(event_t *event, unsigned long offset, unsigned long head)
1758{
1759 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1760
1761 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
1762 (void *)(offset + head),
1763 (void *)(long)(event->header.size),
1764 event->read.pid,
1765 event->read.tid,
1766 attr ? __event_name(attr->type, attr->config)
1767 : "FAIL",
1768 event->read.value);
1094 1769
1095 return 0; 1770 return 0;
1096} 1771}
@@ -1098,10 +1773,12 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head)
1098static int 1773static int
1099process_event(event_t *event, unsigned long offset, unsigned long head) 1774process_event(event_t *event, unsigned long offset, unsigned long head)
1100{ 1775{
1101 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) 1776 trace_event(event);
1102 return process_overflow_event(event, offset, head);
1103 1777
1104 switch (event->header.type) { 1778 switch (event->header.type) {
1779 case PERF_EVENT_SAMPLE:
1780 return process_sample_event(event, offset, head);
1781
1105 case PERF_EVENT_MMAP: 1782 case PERF_EVENT_MMAP:
1106 return process_mmap_event(event, offset, head); 1783 return process_mmap_event(event, offset, head);
1107 1784
@@ -1109,10 +1786,15 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1109 return process_comm_event(event, offset, head); 1786 return process_comm_event(event, offset, head);
1110 1787
1111 case PERF_EVENT_FORK: 1788 case PERF_EVENT_FORK:
1112 return process_fork_event(event, offset, head); 1789 case PERF_EVENT_EXIT:
1790 return process_task_event(event, offset, head);
1791
1792 case PERF_EVENT_LOST:
1793 return process_lost_event(event, offset, head);
1794
1795 case PERF_EVENT_READ:
1796 return process_read_event(event, offset, head);
1113 1797
1114 case PERF_EVENT_PERIOD:
1115 return process_period_event(event, offset, head);
1116 /* 1798 /*
1117 * We dont process them right now but they are fine: 1799 * We dont process them right now but they are fine:
1118 */ 1800 */
@@ -1128,11 +1810,28 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1128 return 0; 1810 return 0;
1129} 1811}
1130 1812
1813static u64 perf_header__sample_type(void)
1814{
1815 u64 sample_type = 0;
1816 int i;
1817
1818 for (i = 0; i < header->attrs; i++) {
1819 struct perf_header_attr *attr = header->attr[i];
1820
1821 if (!sample_type)
1822 sample_type = attr->attr.sample_type;
1823 else if (sample_type != attr->attr.sample_type)
1824 die("non matching sample_type");
1825 }
1826
1827 return sample_type;
1828}
1829
1131static int __cmd_report(void) 1830static int __cmd_report(void)
1132{ 1831{
1133 int ret, rc = EXIT_FAILURE; 1832 int ret, rc = EXIT_FAILURE;
1134 unsigned long offset = 0; 1833 unsigned long offset = 0;
1135 unsigned long head = 0; 1834 unsigned long head, shift;
1136 struct stat stat; 1835 struct stat stat;
1137 event_t *event; 1836 event_t *event;
1138 uint32_t size; 1837 uint32_t size;
@@ -1160,6 +1859,33 @@ static int __cmd_report(void)
1160 exit(0); 1859 exit(0);
1161 } 1860 }
1162 1861
1862 header = perf_header__read(input);
1863 head = header->data_offset;
1864
1865 sample_type = perf_header__sample_type();
1866
1867 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1868 if (sort__has_parent) {
1869 fprintf(stderr, "selected --sort parent, but no"
1870 " callchain data. Did you call"
1871 " perf record without -g?\n");
1872 exit(-1);
1873 }
1874 if (callchain) {
1875 fprintf(stderr, "selected -c but no callchain data."
1876 " Did you call perf record without"
1877 " -g?\n");
1878 exit(-1);
1879 }
1880 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1881 callchain = 1;
1882 if (register_callchain_param(&callchain_param) < 0) {
1883 fprintf(stderr, "Can't register callchain"
1884 " params\n");
1885 exit(-1);
1886 }
1887 }
1888
1163 if (load_kernel() < 0) { 1889 if (load_kernel() < 0) {
1164 perror("failed to load kernel symbols"); 1890 perror("failed to load kernel symbols");
1165 return EXIT_FAILURE; 1891 return EXIT_FAILURE;
@@ -1175,6 +1901,11 @@ static int __cmd_report(void)
1175 cwd = NULL; 1901 cwd = NULL;
1176 cwdlen = 0; 1902 cwdlen = 0;
1177 } 1903 }
1904
1905 shift = page_size * (head / page_size);
1906 offset += shift;
1907 head -= shift;
1908
1178remap: 1909remap:
1179 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 1910 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1180 MAP_SHARED, input, offset); 1911 MAP_SHARED, input, offset);
@@ -1191,9 +1922,10 @@ more:
1191 size = 8; 1922 size = 8;
1192 1923
1193 if (head + event->header.size >= page_size * mmap_window) { 1924 if (head + event->header.size >= page_size * mmap_window) {
1194 unsigned long shift = page_size * (head / page_size);
1195 int ret; 1925 int ret;
1196 1926
1927 shift = page_size * (head / page_size);
1928
1197 ret = munmap(buf, page_size * mmap_window); 1929 ret = munmap(buf, page_size * mmap_window);
1198 assert(ret == 0); 1930 assert(ret == 0);
1199 1931
@@ -1204,7 +1936,7 @@ more:
1204 1936
1205 size = event->header.size; 1937 size = event->header.size;
1206 1938
1207 dprintf("%p [%p]: event: %d\n", 1939 dprintf("\n%p [%p]: event: %d\n",
1208 (void *)(offset + head), 1940 (void *)(offset + head),
1209 (void *)(long)event->header.size, 1941 (void *)(long)event->header.size,
1210 event->header.type); 1942 event->header.type);
@@ -1231,9 +1963,13 @@ more:
1231 1963
1232 head += size; 1964 head += size;
1233 1965
1234 if (offset + head < stat.st_size) 1966 if (offset + head >= header->data_offset + header->data_size)
1967 goto done;
1968
1969 if (offset + head < (unsigned long)stat.st_size)
1235 goto more; 1970 goto more;
1236 1971
1972done:
1237 rc = EXIT_SUCCESS; 1973 rc = EXIT_SUCCESS;
1238 close(input); 1974 close(input);
1239 1975
@@ -1241,6 +1977,7 @@ more:
1241 dprintf(" mmap events: %10ld\n", total_mmap); 1977 dprintf(" mmap events: %10ld\n", total_mmap);
1242 dprintf(" comm events: %10ld\n", total_comm); 1978 dprintf(" comm events: %10ld\n", total_comm);
1243 dprintf(" fork events: %10ld\n", total_fork); 1979 dprintf(" fork events: %10ld\n", total_fork);
1980 dprintf(" lost events: %10ld\n", total_lost);
1244 dprintf(" unknown events: %10ld\n", total_unknown); 1981 dprintf(" unknown events: %10ld\n", total_unknown);
1245 1982
1246 if (dump_trace) 1983 if (dump_trace)
@@ -1253,12 +1990,65 @@ more:
1253 dsos__fprintf(stdout); 1990 dsos__fprintf(stdout);
1254 1991
1255 collapse__resort(); 1992 collapse__resort();
1256 output__resort(); 1993 output__resort(total);
1257 output__fprintf(stdout, total); 1994 output__fprintf(stdout, total);
1258 1995
1259 return rc; 1996 return rc;
1260} 1997}
1261 1998
1999static int
2000parse_callchain_opt(const struct option *opt __used, const char *arg,
2001 int unset __used)
2002{
2003 char *tok;
2004 char *endptr;
2005
2006 callchain = 1;
2007
2008 if (!arg)
2009 return 0;
2010
2011 tok = strtok((char *)arg, ",");
2012 if (!tok)
2013 return -1;
2014
2015 /* get the output mode */
2016 if (!strncmp(tok, "graph", strlen(arg)))
2017 callchain_param.mode = CHAIN_GRAPH_ABS;
2018
2019 else if (!strncmp(tok, "flat", strlen(arg)))
2020 callchain_param.mode = CHAIN_FLAT;
2021
2022 else if (!strncmp(tok, "fractal", strlen(arg)))
2023 callchain_param.mode = CHAIN_GRAPH_REL;
2024
2025 else if (!strncmp(tok, "none", strlen(arg))) {
2026 callchain_param.mode = CHAIN_NONE;
2027 callchain = 0;
2028
2029 return 0;
2030 }
2031
2032 else
2033 return -1;
2034
2035 /* get the min percentage */
2036 tok = strtok(NULL, ",");
2037 if (!tok)
2038 goto setup;
2039
2040 callchain_param.min_percent = strtod(tok, &endptr);
2041 if (tok == endptr)
2042 return -1;
2043
2044setup:
2045 if (register_callchain_param(&callchain_param) < 0) {
2046 fprintf(stderr, "Can't register callchain params\n");
2047 return -1;
2048 }
2049 return 0;
2050}
2051
1262static const char * const report_usage[] = { 2052static const char * const report_usage[] = {
1263 "perf report [<options>] <command>", 2053 "perf report [<options>] <command>",
1264 NULL 2054 NULL
@@ -1272,10 +2062,33 @@ static const struct option options[] = {
1272 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 2062 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1273 "dump raw trace in ASCII"), 2063 "dump raw trace in ASCII"),
1274 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 2064 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
2065 OPT_BOOLEAN('m', "modules", &modules,
2066 "load module symbols - WARNING: use only with -k and LIVE kernel"),
2067 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2068 "Show a column with the number of samples"),
1275 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 2069 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1276 "sort by key(s): pid, comm, dso, symbol. Default: pid,symbol"), 2070 "sort by key(s): pid, comm, dso, symbol, parent"),
1277 OPT_BOOLEAN('P', "full-paths", &full_paths, 2071 OPT_BOOLEAN('P', "full-paths", &full_paths,
1278 "Don't shorten the pathnames taking into account the cwd"), 2072 "Don't shorten the pathnames taking into account the cwd"),
2073 OPT_STRING('p', "parent", &parent_pattern, "regex",
2074 "regex filter to identify parent, see: '--sort parent'"),
2075 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
2076 "Only display entries with parent-match"),
2077 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
2078 "Display callchains using output_type and min percent threshold. "
2079 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
2080 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
2081 "only consider symbols in these dsos"),
2082 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
2083 "only consider symbols in these comms"),
2084 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
2085 "only consider these symbols"),
2086 OPT_STRING('w', "column-widths", &col_width_list_str,
2087 "width[,width...]",
2088 "don't try to adjust column width, use these fixed values"),
2089 OPT_STRING('t', "field-separator", &field_sep, "separator",
2090 "separator for columns, no spaces will be added between "
2091 "columns '.' is reserved."),
1279 OPT_END() 2092 OPT_END()
1280}; 2093};
1281 2094
@@ -1294,7 +2107,26 @@ static void setup_sorting(void)
1294 free(str); 2107 free(str);
1295} 2108}
1296 2109
1297int cmd_report(int argc, const char **argv, const char *prefix) 2110static void setup_list(struct strlist **list, const char *list_str,
2111 struct sort_entry *se, const char *list_name,
2112 FILE *fp)
2113{
2114 if (list_str) {
2115 *list = strlist__new(true, list_str);
2116 if (!*list) {
2117 fprintf(stderr, "problems parsing %s list\n",
2118 list_name);
2119 exit(129);
2120 }
2121 if (strlist__nr_entries(*list) == 1) {
2122 fprintf(fp, "# %s: %s\n", list_name,
2123 strlist__entry(*list, 0)->s);
2124 se->elide = true;
2125 }
2126 }
2127}
2128
2129int cmd_report(int argc, const char **argv, const char *prefix __used)
1298{ 2130{
1299 symbol__init(); 2131 symbol__init();
1300 2132
@@ -1304,6 +2136,12 @@ int cmd_report(int argc, const char **argv, const char *prefix)
1304 2136
1305 setup_sorting(); 2137 setup_sorting();
1306 2138
2139 if (parent_pattern != default_parent_pattern) {
2140 sort_dimension__add("parent");
2141 sort_parent.elide = 1;
2142 } else
2143 exclude_other = 0;
2144
1307 /* 2145 /*
1308 * Any (unrecognized) arguments left? 2146 * Any (unrecognized) arguments left?
1309 */ 2147 */
@@ -1312,5 +2150,15 @@ int cmd_report(int argc, const char **argv, const char *prefix)
1312 2150
1313 setup_pager(); 2151 setup_pager();
1314 2152
2153 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2154 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2155 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
2156
2157 if (field_sep && *field_sep == '.') {
2158 fputs("'.' is the only non valid --field-separator argument\n",
2159 stderr);
2160 exit(129);
2161 }
2162
1315 return __cmd_report(); 2163 return __cmd_report();
1316} 2164}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c43e4a97dc42..b4b06c7903e1 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 */
@@ -43,8 +44,9 @@
43#include "util/parse-events.h" 44#include "util/parse-events.h"
44 45
45#include <sys/prctl.h> 46#include <sys/prctl.h>
47#include <math.h>
46 48
47static struct perf_counter_attr default_attrs[MAX_COUNTERS] = { 49static struct perf_counter_attr default_attrs[] = {
48 50
49 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 51 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
50 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES}, 52 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
@@ -58,35 +60,50 @@ static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
58 60
59}; 61};
60 62
63#define MAX_RUN 100
64
61static int system_wide = 0; 65static int system_wide = 0;
62static int inherit = 1;
63static int verbose = 0; 66static int verbose = 0;
67static unsigned int nr_cpus = 0;
68static int run_idx = 0;
69
70static int run_count = 1;
71static int inherit = 1;
72static int scale = 1;
73static int target_pid = -1;
74static int null_run = 0;
64 75
65static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 76static int fd[MAX_NR_CPUS][MAX_COUNTERS];
66 77
67static int target_pid = -1; 78static u64 runtime_nsecs[MAX_RUN];
68static int nr_cpus = 0; 79static u64 walltime_nsecs[MAX_RUN];
69static unsigned int page_size; 80static u64 runtime_cycles[MAX_RUN];
70 81
71static int scale = 1; 82static u64 event_res[MAX_RUN][MAX_COUNTERS][3];
83static u64 event_scaled[MAX_RUN][MAX_COUNTERS];
72 84
73static const unsigned int default_count[] = { 85static u64 event_res_avg[MAX_COUNTERS][3];
74 1000000, 86static u64 event_res_noise[MAX_COUNTERS][3];
75 1000000, 87
76 10000, 88static u64 event_scaled_avg[MAX_COUNTERS];
77 10000, 89
78 1000000, 90static u64 runtime_nsecs_avg;
79 10000, 91static u64 runtime_nsecs_noise;
80}; 92
93static u64 walltime_nsecs_avg;
94static u64 walltime_nsecs_noise;
81 95
82static __u64 event_res[MAX_COUNTERS][3]; 96static u64 runtime_cycles_avg;
83static __u64 event_scaled[MAX_COUNTERS]; 97static u64 runtime_cycles_noise;
84 98
85static __u64 runtime_nsecs; 99#define MATCH_EVENT(t, c, counter) \
86static __u64 walltime_nsecs; 100 (attrs[counter].type == PERF_TYPE_##t && \
87static __u64 runtime_cycles; 101 attrs[counter].config == PERF_COUNT_##c)
88 102
89static void create_perf_stat_counter(int counter) 103#define ERR_PERF_OPEN \
104"Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n"
105
106static void create_perf_stat_counter(int counter, int pid)
90{ 107{
91 struct perf_counter_attr *attr = attrs + counter; 108 struct perf_counter_attr *attr = attrs + counter;
92 109
@@ -95,21 +112,23 @@ static void create_perf_stat_counter(int counter)
95 PERF_FORMAT_TOTAL_TIME_RUNNING; 112 PERF_FORMAT_TOTAL_TIME_RUNNING;
96 113
97 if (system_wide) { 114 if (system_wide) {
98 int cpu; 115 unsigned int cpu;
99 for (cpu = 0; cpu < nr_cpus; cpu ++) { 116
117 for (cpu = 0; cpu < nr_cpus; cpu++) {
100 fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0); 118 fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
101 if (fd[cpu][counter] < 0 && verbose) { 119 if (fd[cpu][counter] < 0 && verbose)
102 printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[cpu][counter], strerror(errno)); 120 fprintf(stderr, ERR_PERF_OPEN, counter,
103 } 121 fd[cpu][counter], strerror(errno));
104 } 122 }
105 } else { 123 } else {
106 attr->inherit = inherit; 124 attr->inherit = inherit;
107 attr->disabled = 1; 125 attr->disabled = 1;
108 126 attr->enable_on_exec = 1;
109 fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0); 127
110 if (fd[0][counter] < 0 && verbose) { 128 fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0);
111 printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[0][counter], strerror(errno)); 129 if (fd[0][counter] < 0 && verbose)
112 } 130 fprintf(stderr, ERR_PERF_OPEN, counter,
131 fd[0][counter], strerror(errno));
113 } 132 }
114} 133}
115 134
@@ -118,13 +137,8 @@ static void create_perf_stat_counter(int counter)
118 */ 137 */
119static inline int nsec_counter(int counter) 138static inline int nsec_counter(int counter)
120{ 139{
121 if (attrs[counter].type != PERF_TYPE_SOFTWARE) 140 if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) ||
122 return 0; 141 MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
123
124 if (attrs[counter].config == PERF_COUNT_SW_CPU_CLOCK)
125 return 1;
126
127 if (attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
128 return 1; 142 return 1;
129 143
130 return 0; 144 return 0;
@@ -135,22 +149,25 @@ static inline int nsec_counter(int counter)
135 */ 149 */
136static void read_counter(int counter) 150static void read_counter(int counter)
137{ 151{
138 __u64 *count, single_count[3]; 152 u64 *count, single_count[3];
139 ssize_t res; 153 unsigned int cpu;
140 int cpu, nv; 154 size_t res, nv;
141 int scaled; 155 int scaled;
142 156
143 count = event_res[counter]; 157 count = event_res[run_idx][counter];
144 158
145 count[0] = count[1] = count[2] = 0; 159 count[0] = count[1] = count[2] = 0;
146 160
147 nv = scale ? 3 : 1; 161 nv = scale ? 3 : 1;
148 for (cpu = 0; cpu < nr_cpus; cpu ++) { 162 for (cpu = 0; cpu < nr_cpus; cpu++) {
149 if (fd[cpu][counter] < 0) 163 if (fd[cpu][counter] < 0)
150 continue; 164 continue;
151 165
152 res = read(fd[cpu][counter], single_count, nv * sizeof(__u64)); 166 res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
153 assert(res == nv * sizeof(__u64)); 167 assert(res == nv * sizeof(u64));
168
169 close(fd[cpu][counter]);
170 fd[cpu][counter] = -1;
154 171
155 count[0] += single_count[0]; 172 count[0] += single_count[0];
156 if (scale) { 173 if (scale) {
@@ -162,13 +179,13 @@ static void read_counter(int counter)
162 scaled = 0; 179 scaled = 0;
163 if (scale) { 180 if (scale) {
164 if (count[2] == 0) { 181 if (count[2] == 0) {
165 event_scaled[counter] = -1; 182 event_scaled[run_idx][counter] = -1;
166 count[0] = 0; 183 count[0] = 0;
167 return; 184 return;
168 } 185 }
169 186
170 if (count[2] < count[1]) { 187 if (count[2] < count[1]) {
171 event_scaled[counter] = 1; 188 event_scaled[run_idx][counter] = 1;
172 count[0] = (unsigned long long) 189 count[0] = (unsigned long long)
173 ((double)count[0] * count[1] / count[2] + 0.5); 190 ((double)count[0] * count[1] / count[2] + 0.5);
174 } 191 }
@@ -176,12 +193,127 @@ static void read_counter(int counter)
176 /* 193 /*
177 * Save the full runtime - to allow normalization during printout: 194 * Save the full runtime - to allow normalization during printout:
178 */ 195 */
179 if (attrs[counter].type == PERF_TYPE_SOFTWARE && 196 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
180 attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) 197 runtime_nsecs[run_idx] = count[0];
181 runtime_nsecs = count[0]; 198 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
182 if (attrs[counter].type == PERF_TYPE_HARDWARE && 199 runtime_cycles[run_idx] = count[0];
183 attrs[counter].config == PERF_COUNT_HW_CPU_CYCLES) 200}
184 runtime_cycles = count[0]; 201
202static int run_perf_stat(int argc __used, const char **argv)
203{
204 unsigned long long t0, t1;
205 int status = 0;
206 int counter;
207 int pid;
208 int child_ready_pipe[2], go_pipe[2];
209 char buf;
210
211 if (!system_wide)
212 nr_cpus = 1;
213
214 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
215 perror("failed to create pipes");
216 exit(1);
217 }
218
219 if ((pid = fork()) < 0)
220 perror("failed to fork");
221
222 if (!pid) {
223 close(child_ready_pipe[0]);
224 close(go_pipe[1]);
225 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
226
227 /*
228 * Do a dummy execvp to get the PLT entry resolved,
229 * so we avoid the resolver overhead on the real
230 * execvp call.
231 */
232 execvp("", (char **)argv);
233
234 /*
235 * Tell the parent we're ready to go
236 */
237 close(child_ready_pipe[1]);
238
239 /*
240 * Wait until the parent tells us to go.
241 */
242 if (read(go_pipe[0], &buf, 1) == -1)
243 perror("unable to read pipe");
244
245 execvp(argv[0], (char **)argv);
246
247 perror(argv[0]);
248 exit(-1);
249 }
250
251 /*
252 * Wait for the child to be ready to exec.
253 */
254 close(child_ready_pipe[1]);
255 close(go_pipe[0]);
256 if (read(child_ready_pipe[0], &buf, 1) == -1)
257 perror("unable to read pipe");
258 close(child_ready_pipe[0]);
259
260 for (counter = 0; counter < nr_counters; counter++)
261 create_perf_stat_counter(counter, pid);
262
263 /*
264 * Enable counters and exec the command:
265 */
266 t0 = rdclock();
267
268 close(go_pipe[1]);
269 wait(&status);
270
271 t1 = rdclock();
272
273 walltime_nsecs[run_idx] = t1 - t0;
274
275 for (counter = 0; counter < nr_counters; counter++)
276 read_counter(counter);
277
278 return WEXITSTATUS(status);
279}
280
281static void print_noise(u64 *count, u64 *noise)
282{
283 if (run_count > 1)
284 fprintf(stderr, " ( +- %7.3f%% )",
285 (double)noise[0]/(count[0]+1)*100.0);
286}
287
288static void nsec_printout(int counter, u64 *count, u64 *noise)
289{
290 double msecs = (double)count[0] / 1000000;
291
292 fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter));
293
294 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
295 if (walltime_nsecs_avg)
296 fprintf(stderr, " # %10.3f CPUs ",
297 (double)count[0] / (double)walltime_nsecs_avg);
298 }
299 print_noise(count, noise);
300}
301
302static void abs_printout(int counter, u64 *count, u64 *noise)
303{
304 fprintf(stderr, " %14Ld %-24s", count[0], event_name(counter));
305
306 if (runtime_cycles_avg &&
307 MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
308 fprintf(stderr, " # %10.3f IPC ",
309 (double)count[0] / (double)runtime_cycles_avg);
310 } else {
311 if (runtime_nsecs_avg) {
312 fprintf(stderr, " # %10.3f M/sec",
313 (double)count[0]/runtime_nsecs_avg*1000.0);
314 }
315 }
316 print_noise(count, noise);
185} 317}
186 318
187/* 319/*
@@ -189,87 +321,123 @@ static void read_counter(int counter)
189 */ 321 */
190static void print_counter(int counter) 322static void print_counter(int counter)
191{ 323{
192 __u64 *count; 324 u64 *count, *noise;
193 int scaled; 325 int scaled;
194 326
195 count = event_res[counter]; 327 count = event_res_avg[counter];
196 scaled = event_scaled[counter]; 328 noise = event_res_noise[counter];
329 scaled = event_scaled_avg[counter];
197 330
198 if (scaled == -1) { 331 if (scaled == -1) {
199 fprintf(stderr, " %14s %-20s\n", 332 fprintf(stderr, " %14s %-24s\n",
200 "<not counted>", event_name(counter)); 333 "<not counted>", event_name(counter));
201 return; 334 return;
202 } 335 }
203 336
204 if (nsec_counter(counter)) { 337 if (nsec_counter(counter))
205 double msecs = (double)count[0] / 1000000; 338 nsec_printout(counter, count, noise);
206 339 else
207 fprintf(stderr, " %14.6f %-20s", 340 abs_printout(counter, count, noise);
208 msecs, event_name(counter));
209 if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
210 attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) {
211 341
212 if (walltime_nsecs)
213 fprintf(stderr, " # %11.3f CPU utilization factor",
214 (double)count[0] / (double)walltime_nsecs);
215 }
216 } else {
217 fprintf(stderr, " %14Ld %-20s",
218 count[0], event_name(counter));
219 if (runtime_nsecs)
220 fprintf(stderr, " # %11.3f M/sec",
221 (double)count[0]/runtime_nsecs*1000.0);
222 if (runtime_cycles &&
223 attrs[counter].type == PERF_TYPE_HARDWARE &&
224 attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) {
225
226 fprintf(stderr, " # %1.3f per cycle",
227 (double)count[0] / (double)runtime_cycles);
228 }
229 }
230 if (scaled) 342 if (scaled)
231 fprintf(stderr, " (scaled from %.2f%%)", 343 fprintf(stderr, " (scaled from %.2f%%)",
232 (double) count[2] / count[1] * 100); 344 (double) count[2] / count[1] * 100);
345
233 fprintf(stderr, "\n"); 346 fprintf(stderr, "\n");
234} 347}
235 348
236static int do_perf_stat(int argc, const char **argv) 349/*
350 * normalize_noise noise values down to stddev:
351 */
352static void normalize_noise(u64 *val)
237{ 353{
238 unsigned long long t0, t1; 354 double res;
239 int counter;
240 int status;
241 int pid;
242 int i;
243 355
244 if (!system_wide) 356 res = (double)*val / (run_count * sqrt((double)run_count));
245 nr_cpus = 1;
246 357
247 for (counter = 0; counter < nr_counters; counter++) 358 *val = (u64)res;
248 create_perf_stat_counter(counter); 359}
249 360
250 /* 361static void update_avg(const char *name, int idx, u64 *avg, u64 *val)
251 * Enable counters and exec the command: 362{
252 */ 363 *avg += *val;
253 t0 = rdclock();
254 prctl(PR_TASK_PERF_COUNTERS_ENABLE);
255 364
256 if ((pid = fork()) < 0) 365 if (verbose > 1)
257 perror("failed to fork"); 366 fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val);
367}
368/*
369 * Calculate the averages and noises:
370 */
371static void calc_avg(void)
372{
373 int i, j;
374
375 if (verbose > 1)
376 fprintf(stderr, "\n");
377
378 for (i = 0; i < run_count; i++) {
379 update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i);
380 update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i);
381 update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i);
382
383 for (j = 0; j < nr_counters; j++) {
384 update_avg("counter/0", j,
385 event_res_avg[j]+0, event_res[i][j]+0);
386 update_avg("counter/1", j,
387 event_res_avg[j]+1, event_res[i][j]+1);
388 update_avg("counter/2", j,
389 event_res_avg[j]+2, event_res[i][j]+2);
390 if (event_scaled[i][j] != (u64)-1)
391 update_avg("scaled", j,
392 event_scaled_avg + j, event_scaled[i]+j);
393 else
394 event_scaled_avg[j] = -1;
395 }
396 }
397 runtime_nsecs_avg /= run_count;
398 walltime_nsecs_avg /= run_count;
399 runtime_cycles_avg /= run_count;
400
401 for (j = 0; j < nr_counters; j++) {
402 event_res_avg[j][0] /= run_count;
403 event_res_avg[j][1] /= run_count;
404 event_res_avg[j][2] /= run_count;
405 }
258 406
259 if (!pid) { 407 for (i = 0; i < run_count; i++) {
260 if (execvp(argv[0], (char **)argv)) { 408 runtime_nsecs_noise +=
261 perror(argv[0]); 409 abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg));
262 exit(-1); 410 walltime_nsecs_noise +=
411 abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg));
412 runtime_cycles_noise +=
413 abs((s64)(runtime_cycles[i] - runtime_cycles_avg));
414
415 for (j = 0; j < nr_counters; j++) {
416 event_res_noise[j][0] +=
417 abs((s64)(event_res[i][j][0] - event_res_avg[j][0]));
418 event_res_noise[j][1] +=
419 abs((s64)(event_res[i][j][1] - event_res_avg[j][1]));
420 event_res_noise[j][2] +=
421 abs((s64)(event_res[i][j][2] - event_res_avg[j][2]));
263 } 422 }
264 } 423 }
265 424
266 while (wait(&status) >= 0) 425 normalize_noise(&runtime_nsecs_noise);
267 ; 426 normalize_noise(&walltime_nsecs_noise);
427 normalize_noise(&runtime_cycles_noise);
268 428
269 prctl(PR_TASK_PERF_COUNTERS_DISABLE); 429 for (j = 0; j < nr_counters; j++) {
270 t1 = rdclock(); 430 normalize_noise(&event_res_noise[j][0]);
431 normalize_noise(&event_res_noise[j][1]);
432 normalize_noise(&event_res_noise[j][2]);
433 }
434}
271 435
272 walltime_nsecs = t1 - t0; 436static void print_stat(int argc, const char **argv)
437{
438 int i, counter;
439
440 calc_avg();
273 441
274 fflush(stdout); 442 fflush(stdout);
275 443
@@ -279,22 +447,22 @@ static int do_perf_stat(int argc, const char **argv)
279 for (i = 1; i < argc; i++) 447 for (i = 1; i < argc; i++)
280 fprintf(stderr, " %s", argv[i]); 448 fprintf(stderr, " %s", argv[i]);
281 449
282 fprintf(stderr, "\':\n"); 450 fprintf(stderr, "\'");
283 fprintf(stderr, "\n"); 451 if (run_count > 1)
284 452 fprintf(stderr, " (%d runs)", run_count);
285 for (counter = 0; counter < nr_counters; counter++) 453 fprintf(stderr, ":\n\n");
286 read_counter(counter);
287 454
288 for (counter = 0; counter < nr_counters; counter++) 455 for (counter = 0; counter < nr_counters; counter++)
289 print_counter(counter); 456 print_counter(counter);
290 457
291
292 fprintf(stderr, "\n"); 458 fprintf(stderr, "\n");
293 fprintf(stderr, " Wall-clock time elapsed: %12.6f msecs\n", 459 fprintf(stderr, " %14.9f seconds time elapsed",
294 (double)(t1-t0)/1e6); 460 (double)walltime_nsecs_avg/1e9);
295 fprintf(stderr, "\n"); 461 if (run_count > 1) {
296 462 fprintf(stderr, " ( +- %7.3f%% )",
297 return 0; 463 100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg);
464 }
465 fprintf(stderr, "\n\n");
298} 466}
299 467
300static volatile int signr = -1; 468static volatile int signr = -1;
@@ -327,30 +495,38 @@ static const struct option options[] = {
327 OPT_INTEGER('p', "pid", &target_pid, 495 OPT_INTEGER('p', "pid", &target_pid,
328 "stat events on existing pid"), 496 "stat events on existing pid"),
329 OPT_BOOLEAN('a', "all-cpus", &system_wide, 497 OPT_BOOLEAN('a', "all-cpus", &system_wide,
330 "system-wide collection from all CPUs"), 498 "system-wide collection from all CPUs"),
331 OPT_BOOLEAN('S', "scale", &scale, 499 OPT_BOOLEAN('c', "scale", &scale,
332 "scale/normalize counters"), 500 "scale/normalize counters"),
333 OPT_BOOLEAN('v', "verbose", &verbose, 501 OPT_BOOLEAN('v', "verbose", &verbose,
334 "be more verbose (show counter open errors, etc)"), 502 "be more verbose (show counter open errors, etc)"),
503 OPT_INTEGER('r', "repeat", &run_count,
504 "repeat command and print average + stddev (max: 100)"),
505 OPT_BOOLEAN('n', "null", &null_run,
506 "null run - dont start any counters"),
335 OPT_END() 507 OPT_END()
336}; 508};
337 509
338int cmd_stat(int argc, const char **argv, const char *prefix) 510int cmd_stat(int argc, const char **argv, const char *prefix __used)
339{ 511{
340 page_size = sysconf(_SC_PAGE_SIZE); 512 int status;
341
342 memcpy(attrs, default_attrs, sizeof(attrs));
343 513
344 argc = parse_options(argc, argv, options, stat_usage, 0); 514 argc = parse_options(argc, argv, options, stat_usage,
515 PARSE_OPT_STOP_AT_NON_OPTION);
345 if (!argc) 516 if (!argc)
346 usage_with_options(stat_usage, options); 517 usage_with_options(stat_usage, options);
518 if (run_count <= 0 || run_count > MAX_RUN)
519 usage_with_options(stat_usage, options);
347 520
348 if (!nr_counters) 521 /* Set attrs and nr_counters if no event is selected and !null_run */
349 nr_counters = 8; 522 if (!null_run && !nr_counters) {
523 memcpy(attrs, default_attrs, sizeof(default_attrs));
524 nr_counters = ARRAY_SIZE(default_attrs);
525 }
350 526
351 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 527 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
352 assert(nr_cpus <= MAX_NR_CPUS); 528 assert(nr_cpus <= MAX_NR_CPUS);
353 assert(nr_cpus >= 0); 529 assert((int)nr_cpus >= 0);
354 530
355 /* 531 /*
356 * We dont want to block the signals - that would cause 532 * We dont want to block the signals - that would cause
@@ -363,5 +539,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
363 signal(SIGALRM, skip_signal); 539 signal(SIGALRM, skip_signal);
364 signal(SIGABRT, skip_signal); 540 signal(SIGABRT, skip_signal);
365 541
366 return do_perf_stat(argc, argv); 542 status = 0;
543 for (run_idx = 0; run_idx < run_count; run_idx++) {
544 if (run_count != 1 && verbose)
545 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
546 status = run_perf_stat(argc, argv);
547 }
548
549 print_stat(argc, argv);
550
551 return status;
367} 552}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index fe338d3c5d7e..7de28ce9ca26 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -23,7 +23,7 @@
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
@@ -31,6 +31,8 @@
31#include <fcntl.h> 31#include <fcntl.h>
32 32
33#include <stdio.h> 33#include <stdio.h>
34#include <termios.h>
35#include <unistd.h>
34 36
35#include <errno.h> 37#include <errno.h>
36#include <time.h> 38#include <time.h>
@@ -54,10 +56,11 @@ static int system_wide = 0;
54 56
55static int default_interval = 100000; 57static int default_interval = 100000;
56 58
57static __u64 count_filter = 5; 59static int count_filter = 5;
58static int print_entries = 15; 60static int print_entries = 15;
59 61
60static int target_pid = -1; 62static int target_pid = -1;
63static int inherit = 0;
61static int profile_cpu = -1; 64static int profile_cpu = -1;
62static int nr_cpus = 0; 65static int nr_cpus = 0;
63static unsigned int realtime_prio = 0; 66static unsigned int realtime_prio = 0;
@@ -66,21 +69,35 @@ static unsigned int page_size;
66static unsigned int mmap_pages = 16; 69static unsigned int mmap_pages = 16;
67static int freq = 0; 70static int freq = 0;
68static int verbose = 0; 71static int verbose = 0;
69 72static char *vmlinux = NULL;
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
82static __u64 min_ip; 99static u64 min_ip;
83static __u64 max_ip = -1ll; 100static u64 max_ip = -1ll;
84 101
85struct sym_entry { 102struct sym_entry {
86 struct rb_node rb_node; 103 struct rb_node rb_node;
@@ -89,9 +106,237 @@ 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], *path = vmlinux;
126 u64 start, end, len;
127
128 if (!syme)
129 return;
130
131 if (syme->lines) {
132 pthread_mutex_lock(&syme->source_lock);
133 goto out_assign;
134 }
135
136 sym = (struct symbol *)(syme + 1);
137 module = sym->module;
138
139 if (module)
140 path = module->path;
141 if (!path)
142 return;
143
144 start = sym->obj_start;
145 if (!start)
146 start = sym->start;
147
148 if (module) {
149 section = module->sections->find_section(module->sections, ".text");
150 if (section)
151 start -= section->vma;
152 }
153
154 end = start + sym->end - sym->start + 1;
155 len = sym->end - sym->start;
156
157 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path);
158
159 file = popen(command, "r");
160 if (!file)
161 return;
162
163 pthread_mutex_lock(&syme->source_lock);
164 syme->lines_tail = &syme->lines;
165 while (!feof(file)) {
166 struct source_line *src;
167 size_t dummy = 0;
168 char *c;
169
170 src = malloc(sizeof(struct source_line));
171 assert(src != NULL);
172 memset(src, 0, sizeof(struct source_line));
173
174 if (getline(&src->line, &dummy, file) < 0)
175 break;
176 if (!src->line)
177 break;
178
179 c = strchr(src->line, '\n');
180 if (c)
181 *c = 0;
182
183 src->next = NULL;
184 *syme->lines_tail = src;
185 syme->lines_tail = &src->next;
186
187 if (strlen(src->line)>8 && src->line[8] == ':') {
188 src->eip = strtoull(src->line, NULL, 16);
189 if (section)
190 src->eip += section->vma;
191 }
192 if (strlen(src->line)>8 && src->line[16] == ':') {
193 src->eip = strtoull(src->line, NULL, 16);
194 if (section)
195 src->eip += section->vma;
196 }
197 }
198 pclose(file);
199out_assign:
200 sym_filter_entry = syme;
201 pthread_mutex_unlock(&syme->source_lock);
202}
203
204static void __zero_source_counters(struct sym_entry *syme)
205{
206 int i;
207 struct source_line *line;
208
209 line = syme->lines;
210 while (line) {
211 for (i = 0; i < nr_counters; i++)
212 line->count[i] = 0;
213 line = line->next;
214 }
215}
216
217static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
218{
219 struct source_line *line;
220
221 if (syme != sym_filter_entry)
222 return;
223
224 if (pthread_mutex_trylock(&syme->source_lock))
225 return;
226
227 if (!syme->source)
228 goto out_unlock;
229
230 for (line = syme->lines; line; line = line->next) {
231 if (line->eip == ip) {
232 line->count[counter]++;
233 break;
234 }
235 if (line->eip > ip)
236 break;
237 }
238out_unlock:
239 pthread_mutex_unlock(&syme->source_lock);
240}
241
242static void lookup_sym_source(struct sym_entry *syme)
243{
244 struct symbol *symbol = (struct symbol *)(syme + 1);
245 struct source_line *line;
246 char pattern[PATH_MAX];
247 char *idx;
248
249 sprintf(pattern, "<%s>:", symbol->name);
250
251 if (symbol->module) {
252 idx = strstr(pattern, "\t");
253 if (idx)
254 *idx = 0;
255 }
256
257 pthread_mutex_lock(&syme->source_lock);
258 for (line = syme->lines; line; line = line->next) {
259 if (strstr(line->line, pattern)) {
260 syme->source = line;
261 break;
262 }
263 }
264 pthread_mutex_unlock(&syme->source_lock);
265}
266
267static void show_lines(struct source_line *queue, int count, int total)
268{
269 int i;
270 struct source_line *line;
271
272 line = queue;
273 for (i = 0; i < count; i++) {
274 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
275
276 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line);
277 line = line->next;
278 }
279}
280
281#define TRACE_COUNT 3
282
283static void show_details(struct sym_entry *syme)
284{
285 struct symbol *symbol;
286 struct source_line *line;
287 struct source_line *line_queue = NULL;
288 int displayed = 0;
289 int line_queue_count = 0, total = 0, more = 0;
290
291 if (!syme)
292 return;
293
294 if (!syme->source)
295 lookup_sym_source(syme);
296
297 if (!syme->source)
298 return;
299
300 symbol = (struct symbol *)(syme + 1);
301 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
302 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
303
304 pthread_mutex_lock(&syme->source_lock);
305 line = syme->source;
306 while (line) {
307 total += line->count[sym_counter];
308 line = line->next;
309 }
310
311 line = syme->source;
312 while (line) {
313 float pcnt = 0.0;
314
315 if (!line_queue_count)
316 line_queue = line;
317 line_queue_count++;
318
319 if (line->count[sym_counter])
320 pcnt = 100.0 * line->count[sym_counter] / (float)total;
321 if (pcnt >= (float)sym_pcnt_filter) {
322 if (displayed <= print_entries)
323 show_lines(line_queue, line_queue_count, total);
324 else more++;
325 displayed += line_queue_count;
326 line_queue_count = 0;
327 line_queue = NULL;
328 } else if (line_queue_count > TRACE_COUNT) {
329 line_queue = line_queue->next;
330 line_queue_count--;
331 }
332
333 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
334 line = line->next;
335 }
336 pthread_mutex_unlock(&syme->source_lock);
337 if (more)
338 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
339}
95 340
96struct dso *kernel_dso; 341struct dso *kernel_dso;
97 342
@@ -110,6 +355,9 @@ static double sym_weight(const struct sym_entry *sym)
110 double weight = sym->snap_count; 355 double weight = sym->snap_count;
111 int counter; 356 int counter;
112 357
358 if (!display_weighted)
359 return weight;
360
113 for (counter = 1; counter < nr_counters-1; counter++) 361 for (counter = 1; counter < nr_counters-1; counter++)
114 weight *= sym->count[counter]; 362 weight *= sym->count[counter];
115 363
@@ -157,7 +405,7 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
157static void print_sym_table(void) 405static void print_sym_table(void)
158{ 406{
159 int printed = 0, j; 407 int printed = 0, j;
160 int counter; 408 int counter, snap = !display_weighted ? sym_counter : 0;
161 float samples_per_sec = samples/delay_secs; 409 float samples_per_sec = samples/delay_secs;
162 float ksamples_per_sec = (samples-userspace_samples)/delay_secs; 410 float ksamples_per_sec = (samples-userspace_samples)/delay_secs;
163 float sum_ksamples = 0.0; 411 float sum_ksamples = 0.0;
@@ -173,7 +421,7 @@ static void print_sym_table(void)
173 pthread_mutex_unlock(&active_symbols_lock); 421 pthread_mutex_unlock(&active_symbols_lock);
174 422
175 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 423 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
176 syme->snap_count = syme->count[0]; 424 syme->snap_count = syme->count[snap];
177 if (syme->snap_count != 0) { 425 if (syme->snap_count != 0) {
178 syme->weight = sym_weight(syme); 426 syme->weight = sym_weight(syme);
179 rb_insert_active_sym(&tmp, syme); 427 rb_insert_active_sym(&tmp, syme);
@@ -193,15 +441,17 @@ static void print_sym_table(void)
193 samples_per_sec, 441 samples_per_sec,
194 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 442 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
195 443
196 if (nr_counters == 1) { 444 if (nr_counters == 1 || !display_weighted) {
197 printf("%Ld", attrs[0].sample_period); 445 printf("%Ld", (u64)attrs[0].sample_period);
198 if (freq) 446 if (freq)
199 printf("Hz "); 447 printf("Hz ");
200 else 448 else
201 printf(" "); 449 printf(" ");
202 } 450 }
203 451
204 for (counter = 0; counter < nr_counters; counter++) { 452 if (!display_weighted)
453 printf("%s", event_name(sym_counter));
454 else for (counter = 0; counter < nr_counters; counter++) {
205 if (counter) 455 if (counter)
206 printf("/"); 456 printf("/");
207 457
@@ -226,6 +476,11 @@ static void print_sym_table(void)
226 476
227 printf("------------------------------------------------------------------------------\n\n"); 477 printf("------------------------------------------------------------------------------\n\n");
228 478
479 if (sym_filter_entry) {
480 show_details(sym_filter_entry);
481 return;
482 }
483
229 if (nr_counters == 1) 484 if (nr_counters == 1)
230 printf(" samples pcnt"); 485 printf(" samples pcnt");
231 else 486 else
@@ -238,59 +493,300 @@ static void print_sym_table(void)
238 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 493 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
239 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); 494 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
240 struct symbol *sym = (struct symbol *)(syme + 1); 495 struct symbol *sym = (struct symbol *)(syme + 1);
241 char *color = PERF_COLOR_NORMAL;
242 double pcnt; 496 double pcnt;
243 497
244 if (++printed > print_entries || syme->snap_count < count_filter) 498 if (++printed > print_entries || (int)syme->snap_count < count_filter)
245 continue; 499 continue;
246 500
247 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 501 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
248 sum_ksamples)); 502 sum_ksamples));
249 503
250 /* 504 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); 505 printf("%20.2f - ", syme->weight);
264 else 506 else
265 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 507 printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
266 508
267 color_fprintf(stdout, color, "%4.1f%%", pcnt); 509 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
268 printf(" - %016llx : %s\n", sym->start, sym->name); 510 printf(" - %016llx : %s", sym->start, sym->name);
511 if (sym->module)
512 printf("\t[%s]", sym->module->name);
513 printf("\n");
514 }
515}
516
517static void prompt_integer(int *target, const char *msg)
518{
519 char *buf = malloc(0), *p;
520 size_t dummy = 0;
521 int tmp;
522
523 fprintf(stdout, "\n%s: ", msg);
524 if (getline(&buf, &dummy, stdin) < 0)
525 return;
526
527 p = strchr(buf, '\n');
528 if (p)
529 *p = 0;
530
531 p = buf;
532 while(*p) {
533 if (!isdigit(*p))
534 goto out_free;
535 p++;
536 }
537 tmp = strtoul(buf, NULL, 10);
538 *target = tmp;
539out_free:
540 free(buf);
541}
542
543static void prompt_percent(int *target, const char *msg)
544{
545 int tmp = 0;
546
547 prompt_integer(&tmp, msg);
548 if (tmp >= 0 && tmp <= 100)
549 *target = tmp;
550}
551
552static void prompt_symbol(struct sym_entry **target, const char *msg)
553{
554 char *buf = malloc(0), *p;
555 struct sym_entry *syme = *target, *n, *found = NULL;
556 size_t dummy = 0;
557
558 /* zero counters of active symbol */
559 if (syme) {
560 pthread_mutex_lock(&syme->source_lock);
561 __zero_source_counters(syme);
562 *target = NULL;
563 pthread_mutex_unlock(&syme->source_lock);
564 }
565
566 fprintf(stdout, "\n%s: ", msg);
567 if (getline(&buf, &dummy, stdin) < 0)
568 goto out_free;
569
570 p = strchr(buf, '\n');
571 if (p)
572 *p = 0;
573
574 pthread_mutex_lock(&active_symbols_lock);
575 syme = list_entry(active_symbols.next, struct sym_entry, node);
576 pthread_mutex_unlock(&active_symbols_lock);
577
578 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
579 struct symbol *sym = (struct symbol *)(syme + 1);
580
581 if (!strcmp(buf, sym->name)) {
582 found = syme;
583 break;
584 }
269 } 585 }
586
587 if (!found) {
588 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter);
589 sleep(1);
590 return;
591 } else
592 parse_source(found);
593
594out_free:
595 free(buf);
270} 596}
271 597
272static void *display_thread(void *arg) 598static void print_mapped_keys(void)
599{
600 char *name = NULL;
601
602 if (sym_filter_entry) {
603 struct symbol *sym = (struct symbol *)(sym_filter_entry+1);
604 name = sym->name;
605 }
606
607 fprintf(stdout, "\nMapped keys:\n");
608 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs);
609 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries);
610
611 if (nr_counters > 1)
612 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter));
613
614 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
615
616 if (vmlinux) {
617 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
618 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
619 fprintf(stdout, "\t[S] stop annotation.\n");
620 }
621
622 if (nr_counters > 1)
623 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
624
625 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0);
626 fprintf(stdout, "\t[qQ] quit.\n");
627}
628
629static int key_mapped(int c)
630{
631 switch (c) {
632 case 'd':
633 case 'e':
634 case 'f':
635 case 'z':
636 case 'q':
637 case 'Q':
638 return 1;
639 case 'E':
640 case 'w':
641 return nr_counters > 1 ? 1 : 0;
642 case 'F':
643 case 's':
644 case 'S':
645 return vmlinux ? 1 : 0;
646 }
647
648 return 0;
649}
650
651static void handle_keypress(int c)
652{
653 if (!key_mapped(c)) {
654 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
655 struct termios tc, save;
656
657 print_mapped_keys();
658 fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
659 fflush(stdout);
660
661 tcgetattr(0, &save);
662 tc = save;
663 tc.c_lflag &= ~(ICANON | ECHO);
664 tc.c_cc[VMIN] = 0;
665 tc.c_cc[VTIME] = 0;
666 tcsetattr(0, TCSANOW, &tc);
667
668 poll(&stdin_poll, 1, -1);
669 c = getc(stdin);
670
671 tcsetattr(0, TCSAFLUSH, &save);
672 if (!key_mapped(c))
673 return;
674 }
675
676 switch (c) {
677 case 'd':
678 prompt_integer(&delay_secs, "Enter display delay");
679 break;
680 case 'e':
681 prompt_integer(&print_entries, "Enter display entries (lines)");
682 break;
683 case 'E':
684 if (nr_counters > 1) {
685 int i;
686
687 fprintf(stderr, "\nAvailable events:");
688 for (i = 0; i < nr_counters; i++)
689 fprintf(stderr, "\n\t%d %s", i, event_name(i));
690
691 prompt_integer(&sym_counter, "Enter details event counter");
692
693 if (sym_counter >= nr_counters) {
694 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0));
695 sym_counter = 0;
696 sleep(1);
697 }
698 } else sym_counter = 0;
699 break;
700 case 'f':
701 prompt_integer(&count_filter, "Enter display event count filter");
702 break;
703 case 'F':
704 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
705 break;
706 case 'q':
707 case 'Q':
708 printf("exiting.\n");
709 exit(0);
710 case 's':
711 prompt_symbol(&sym_filter_entry, "Enter details symbol");
712 break;
713 case 'S':
714 if (!sym_filter_entry)
715 break;
716 else {
717 struct sym_entry *syme = sym_filter_entry;
718
719 pthread_mutex_lock(&syme->source_lock);
720 sym_filter_entry = NULL;
721 __zero_source_counters(syme);
722 pthread_mutex_unlock(&syme->source_lock);
723 }
724 break;
725 case 'w':
726 display_weighted = ~display_weighted;
727 break;
728 case 'z':
729 zero = ~zero;
730 break;
731 }
732}
733
734static void *display_thread(void *arg __used)
273{ 735{
274 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 736 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
275 int delay_msecs = delay_secs * 1000; 737 struct termios tc, save;
738 int delay_msecs, c;
276 739
277 printf("PerfTop refresh period: %d seconds\n", delay_secs); 740 tcgetattr(0, &save);
741 tc = save;
742 tc.c_lflag &= ~(ICANON | ECHO);
743 tc.c_cc[VMIN] = 0;
744 tc.c_cc[VTIME] = 0;
745
746repeat:
747 delay_msecs = delay_secs * 1000;
748 tcsetattr(0, TCSANOW, &tc);
749 /* trash return*/
750 getc(stdin);
278 751
279 do { 752 do {
280 print_sym_table(); 753 print_sym_table();
281 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 754 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
282 755
283 printf("key pressed - exiting.\n"); 756 c = getc(stdin);
284 exit(0); 757 tcsetattr(0, TCSAFLUSH, &save);
758
759 handle_keypress(c);
760 goto repeat;
285 761
286 return NULL; 762 return NULL;
287} 763}
288 764
765/* Tag samples to be skipped. */
766static const char *skip_symbols[] = {
767 "default_idle",
768 "cpu_idle",
769 "enter_idle",
770 "exit_idle",
771 "mwait_idle",
772 "mwait_idle_with_hints",
773 "ppc64_runlatch_off",
774 "pseries_dedicated_idle_sleep",
775 NULL
776};
777
289static int symbol_filter(struct dso *self, struct symbol *sym) 778static int symbol_filter(struct dso *self, struct symbol *sym)
290{ 779{
291 static int filter_match;
292 struct sym_entry *syme; 780 struct sym_entry *syme;
293 const char *name = sym->name; 781 const char *name = sym->name;
782 int i;
783
784 /*
785 * ppc64 uses function descriptors and appends a '.' to the
786 * start of every instruction address. Remove it.
787 */
788 if (name[0] == '.')
789 name++;
294 790
295 if (!strcmp(name, "_text") || 791 if (!strcmp(name, "_text") ||
296 !strcmp(name, "_etext") || 792 !strcmp(name, "_etext") ||
@@ -302,37 +798,17 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
302 return 1; 798 return 1;
303 799
304 syme = dso__sym_priv(self, sym); 800 syme = dso__sym_priv(self, sym);
305 /* Tag samples to be skipped. */ 801 pthread_mutex_init(&syme->source_lock, NULL);
306 if (!strcmp("default_idle", name) || 802 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
307 !strcmp("cpu_idle", name) || 803 sym_filter_entry = syme;
308 !strcmp("enter_idle", name) || 804
309 !strcmp("exit_idle", name) || 805 for (i = 0; skip_symbols[i]; i++) {
310 !strcmp("mwait_idle", name)) 806 if (!strcmp(skip_symbols[i], name)) {
311 syme->skip = 1; 807 syme->skip = 1;
312 808 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 } 809 }
328 } 810 }
329 811
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; 812 return 0;
337} 813}
338 814
@@ -340,12 +816,13 @@ static int parse_symbols(void)
340{ 816{
341 struct rb_node *node; 817 struct rb_node *node;
342 struct symbol *sym; 818 struct symbol *sym;
819 int modules = vmlinux ? 1 : 0;
343 820
344 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); 821 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
345 if (kernel_dso == NULL) 822 if (kernel_dso == NULL)
346 return -1; 823 return -1;
347 824
348 if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0) 825 if (dso__load_kernel(kernel_dso, vmlinux, symbol_filter, verbose, modules) <= 0)
349 goto out_delete_dso; 826 goto out_delete_dso;
350 827
351 node = rb_first(&kernel_dso->syms); 828 node = rb_first(&kernel_dso->syms);
@@ -367,12 +844,10 @@ out_delete_dso:
367 return -1; 844 return -1;
368} 845}
369 846
370#define TRACE_COUNT 3
371
372/* 847/*
373 * Binary search in the histogram table and record the hit: 848 * Binary search in the histogram table and record the hit:
374 */ 849 */
375static void record_ip(__u64 ip, int counter) 850static void record_ip(u64 ip, int counter)
376{ 851{
377 struct symbol *sym = dso__find_symbol(kernel_dso, ip); 852 struct symbol *sym = dso__find_symbol(kernel_dso, ip);
378 853
@@ -381,6 +856,7 @@ static void record_ip(__u64 ip, int counter)
381 856
382 if (!syme->skip) { 857 if (!syme->skip) {
383 syme->count[counter]++; 858 syme->count[counter]++;
859 record_precise_ip(syme, counter, ip);
384 pthread_mutex_lock(&active_symbols_lock); 860 pthread_mutex_lock(&active_symbols_lock);
385 if (list_empty(&syme->node) || !syme->node.next) 861 if (list_empty(&syme->node) || !syme->node.next)
386 __list_insert_active_sym(syme); 862 __list_insert_active_sym(syme);
@@ -392,11 +868,11 @@ static void record_ip(__u64 ip, int counter)
392 samples--; 868 samples--;
393} 869}
394 870
395static void process_event(__u64 ip, int counter) 871static void process_event(u64 ip, int counter, int user)
396{ 872{
397 samples++; 873 samples++;
398 874
399 if (ip < min_ip || ip > max_ip) { 875 if (user) {
400 userspace_samples++; 876 userspace_samples++;
401 return; 877 return;
402 } 878 }
@@ -407,7 +883,7 @@ static void process_event(__u64 ip, int counter)
407struct mmap_data { 883struct mmap_data {
408 int counter; 884 int counter;
409 void *base; 885 void *base;
410 unsigned int mask; 886 int mask;
411 unsigned int prev; 887 unsigned int prev;
412}; 888};
413 889
@@ -463,15 +939,15 @@ static void mmap_read_counter(struct mmap_data *md)
463 for (; old != head;) { 939 for (; old != head;) {
464 struct ip_event { 940 struct ip_event {
465 struct perf_event_header header; 941 struct perf_event_header header;
466 __u64 ip; 942 u64 ip;
467 __u32 pid, target_pid; 943 u32 pid, target_pid;
468 }; 944 };
469 struct mmap_event { 945 struct mmap_event {
470 struct perf_event_header header; 946 struct perf_event_header header;
471 __u32 pid, target_pid; 947 u32 pid, target_pid;
472 __u64 start; 948 u64 start;
473 __u64 len; 949 u64 len;
474 __u64 pgoff; 950 u64 pgoff;
475 char filename[PATH_MAX]; 951 char filename[PATH_MAX];
476 }; 952 };
477 953
@@ -509,9 +985,10 @@ static void mmap_read_counter(struct mmap_data *md)
509 985
510 old += size; 986 old += size;
511 987
512 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) { 988 if (event->header.type == PERF_EVENT_SAMPLE) {
513 if (event->header.type & PERF_SAMPLE_IP) 989 int user =
514 process_event(event->ip.ip, md->counter); 990 (event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER;
991 process_event(event->ip.ip, md->counter, user);
515 } 992 }
516 } 993 }
517 994
@@ -537,7 +1014,7 @@ int group_fd;
537static void start_counter(int i, int counter) 1014static void start_counter(int i, int counter)
538{ 1015{
539 struct perf_counter_attr *attr; 1016 struct perf_counter_attr *attr;
540 unsigned int cpu; 1017 int cpu;
541 1018
542 cpu = profile_cpu; 1019 cpu = profile_cpu;
543 if (target_pid == -1 && profile_cpu == -1) 1020 if (target_pid == -1 && profile_cpu == -1)
@@ -547,6 +1024,7 @@ static void start_counter(int i, int counter)
547 1024
548 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1025 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
549 attr->freq = freq; 1026 attr->freq = freq;
1027 attr->inherit = (cpu < 0) && inherit;
550 1028
551try_again: 1029try_again:
552 fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0); 1030 fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0);
@@ -660,6 +1138,7 @@ static const struct option options[] = {
660 "system-wide collection from all CPUs"), 1138 "system-wide collection from all CPUs"),
661 OPT_INTEGER('C', "CPU", &profile_cpu, 1139 OPT_INTEGER('C', "CPU", &profile_cpu,
662 "CPU to profile on"), 1140 "CPU to profile on"),
1141 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
663 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1142 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
664 "number of mmap data pages"), 1143 "number of mmap data pages"),
665 OPT_INTEGER('r', "realtime", &realtime_prio, 1144 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -672,9 +1151,11 @@ static const struct option options[] = {
672 "only display functions with more events than this"), 1151 "only display functions with more events than this"),
673 OPT_BOOLEAN('g', "group", &group, 1152 OPT_BOOLEAN('g', "group", &group,
674 "put the counters into a counter group"), 1153 "put the counters into a counter group"),
675 OPT_STRING('s', "sym-filter", &sym_filter, "pattern", 1154 OPT_BOOLEAN('i', "inherit", &inherit,
676 "only display symbols matchig this pattern"), 1155 "child tasks inherit counters"),
677 OPT_BOOLEAN('z', "zero", &group, 1156 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1157 "symbol to annotate - requires -k option"),
1158 OPT_BOOLEAN('z', "zero", &zero,
678 "zero history across updates"), 1159 "zero history across updates"),
679 OPT_INTEGER('F', "freq", &freq, 1160 OPT_INTEGER('F', "freq", &freq,
680 "profile at this frequency"), 1161 "profile at this frequency"),
@@ -685,10 +1166,12 @@ static const struct option options[] = {
685 OPT_END() 1166 OPT_END()
686}; 1167};
687 1168
688int cmd_top(int argc, const char **argv, const char *prefix) 1169int cmd_top(int argc, const char **argv, const char *prefix __used)
689{ 1170{
690 int counter; 1171 int counter;
691 1172
1173 symbol__init();
1174
692 page_size = sysconf(_SC_PAGE_SIZE); 1175 page_size = sysconf(_SC_PAGE_SIZE);
693 1176
694 argc = parse_options(argc, argv, options, top_usage, 0); 1177 argc = parse_options(argc, argv, options, top_usage, 0);
@@ -714,6 +1197,7 @@ int cmd_top(int argc, const char **argv, const char *prefix)
714 delay_secs = 1; 1197 delay_secs = 1;
715 1198
716 parse_symbols(); 1199 parse_symbols();
1200 parse_source(sym_filter_entry);
717 1201
718 /* 1202 /*
719 * Fill in the ones not specifically initialized via -c: 1203 * Fill in the ones not specifically initialized via -c:
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 4eb725933703..31982ad064b4 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)
@@ -266,7 +293,7 @@ static void handle_internal_command(int argc, const char **argv)
266 { "annotate", cmd_annotate, 0 }, 293 { "annotate", cmd_annotate, 0 },
267 { "version", cmd_version, 0 }, 294 { "version", cmd_version, 0 },
268 }; 295 };
269 int i; 296 unsigned int i;
270 static const char ext[] = STRIP_EXTENSION; 297 static const char ext[] = STRIP_EXTENSION;
271 298
272 if (sizeof(ext) > 1) { 299 if (sizeof(ext) > 1) {
@@ -349,6 +376,49 @@ static int run_argv(int *argcp, const char ***argv)
349 return done_alias; 376 return done_alias;
350} 377}
351 378
379/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
380static void get_debugfs_mntpt(void)
381{
382 FILE *file;
383 char fs_type[100];
384 char debugfs[MAXPATHLEN];
385
386 /*
387 * try the standard location
388 */
389 if (valid_debugfs_mount("/sys/kernel/debug/") == 0) {
390 strcpy(debugfs_mntpt, "/sys/kernel/debug/");
391 return;
392 }
393
394 /*
395 * try the sane location
396 */
397 if (valid_debugfs_mount("/debug/") == 0) {
398 strcpy(debugfs_mntpt, "/debug/");
399 return;
400 }
401
402 /*
403 * give up and parse /proc/mounts
404 */
405 file = fopen("/proc/mounts", "r");
406 if (file == NULL)
407 return;
408
409 while (fscanf(file, "%*s %"
410 STR(MAXPATHLEN)
411 "s %99s %*s %*d %*d\n",
412 debugfs, fs_type) == 2) {
413 if (strcmp(fs_type, "debugfs") == 0)
414 break;
415 }
416 fclose(file);
417 if (strcmp(fs_type, "debugfs") == 0) {
418 strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
419 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
420 }
421}
352 422
353int main(int argc, const char **argv) 423int main(int argc, const char **argv)
354{ 424{
@@ -357,7 +427,8 @@ int main(int argc, const char **argv)
357 cmd = perf_extract_argv0_path(argv[0]); 427 cmd = perf_extract_argv0_path(argv[0]);
358 if (!cmd) 428 if (!cmd)
359 cmd = "perf-help"; 429 cmd = "perf-help";
360 430 /* get debugfs mount point from /proc/mounts */
431 get_debugfs_mntpt();
361 /* 432 /*
362 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 433 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
363 * 434 *
@@ -380,6 +451,7 @@ int main(int argc, const char **argv)
380 argc--; 451 argc--;
381 handle_options(&argv, &argc, NULL); 452 handle_options(&argv, &argc, NULL);
382 commit_pager_choice(); 453 commit_pager_choice();
454 set_debugfs_path();
383 if (argc > 0) { 455 if (argc > 0) {
384 if (!prefixcmp(argv[0], "--")) 456 if (!prefixcmp(argv[0], "--"))
385 argv[0] += 2; 457 argv[0] += 2;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 87a1aca4a424..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");
@@ -13,12 +19,35 @@
13#define cpu_relax() asm volatile ("" ::: "memory"); 19#define cpu_relax() asm volatile ("" ::: "memory");
14#endif 20#endif
15 21
22#ifdef __s390__
23#include "../../arch/s390/include/asm/unistd.h"
24#define rmb() asm volatile("bcr 15,0" ::: "memory")
25#define cpu_relax() asm volatile("" ::: "memory");
26#endif
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
16#include <time.h> 44#include <time.h>
17#include <unistd.h> 45#include <unistd.h>
18#include <sys/types.h> 46#include <sys/types.h>
19#include <sys/syscall.h> 47#include <sys/syscall.h>
20 48
21#include "../../include/linux/perf_counter.h" 49#include "../../include/linux/perf_counter.h"
50#include "util/types.h"
22 51
23/* 52/*
24 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all 53 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
@@ -45,6 +74,8 @@ static inline unsigned long long rdclock(void)
45#define __user 74#define __user
46#define asmlinkage 75#define asmlinkage
47 76
77#define __used __attribute__((__unused__))
78
48#define unlikely(x) __builtin_expect(!!(x), 0) 79#define unlikely(x) __builtin_expect(!!(x), 0)
49#define min(x, y) ({ \ 80#define min(x, y) ({ \
50 typeof(x) _min1 = (x); \ 81 typeof(x) _min1 = (x); \
@@ -65,4 +96,9 @@ sys_perf_counter_open(struct perf_counter_attr *attr,
65#define MAX_COUNTERS 256 96#define MAX_COUNTERS 256
66#define MAX_NR_CPUS 256 97#define MAX_NR_CPUS 256
67 98
99struct ip_callchain {
100 u64 nr;
101 u64 ips[0];
102};
103
68#endif 104#endif
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..4b50c412b9c5 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 *);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
new file mode 100644
index 000000000000..011473411642
--- /dev/null
+++ b/tools/perf/util/callchain.c
@@ -0,0 +1,343 @@
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 default:
54 break;
55 }
56 }
57
58 rb_link_node(&chain->rb_node, parent, p);
59 rb_insert_color(&chain->rb_node, root);
60}
61
62static void
63__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
64 u64 min_hit)
65{
66 struct callchain_node *child;
67
68 chain_for_each_child(child, node)
69 __sort_chain_flat(rb_root, child, min_hit);
70
71 if (node->hit && node->hit >= min_hit)
72 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
73}
74
75/*
76 * Once we get every callchains from the stream, we can now
77 * sort them by hit
78 */
79static void
80sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
81 u64 min_hit, struct callchain_param *param __used)
82{
83 __sort_chain_flat(rb_root, node, min_hit);
84}
85
86static void __sort_chain_graph_abs(struct callchain_node *node,
87 u64 min_hit)
88{
89 struct callchain_node *child;
90
91 node->rb_root = RB_ROOT;
92
93 chain_for_each_child(child, node) {
94 __sort_chain_graph_abs(child, min_hit);
95 if (cumul_hits(child) >= min_hit)
96 rb_insert_callchain(&node->rb_root, child,
97 CHAIN_GRAPH_ABS);
98 }
99}
100
101static void
102sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
103 u64 min_hit, struct callchain_param *param __used)
104{
105 __sort_chain_graph_abs(chain_root, min_hit);
106 rb_root->rb_node = chain_root->rb_root.rb_node;
107}
108
109static void __sort_chain_graph_rel(struct callchain_node *node,
110 double min_percent)
111{
112 struct callchain_node *child;
113 u64 min_hit;
114
115 node->rb_root = RB_ROOT;
116 min_hit = ceil(node->children_hit * min_percent);
117
118 chain_for_each_child(child, node) {
119 __sort_chain_graph_rel(child, min_percent);
120 if (cumul_hits(child) >= min_hit)
121 rb_insert_callchain(&node->rb_root, child,
122 CHAIN_GRAPH_REL);
123 }
124}
125
126static void
127sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
128 u64 min_hit __used, struct callchain_param *param)
129{
130 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0);
131 rb_root->rb_node = chain_root->rb_root.rb_node;
132}
133
134int register_callchain_param(struct callchain_param *param)
135{
136 switch (param->mode) {
137 case CHAIN_GRAPH_ABS:
138 param->sort = sort_chain_graph_abs;
139 break;
140 case CHAIN_GRAPH_REL:
141 param->sort = sort_chain_graph_rel;
142 break;
143 case CHAIN_FLAT:
144 param->sort = sort_chain_flat;
145 break;
146 default:
147 return -1;
148 }
149 return 0;
150}
151
152/*
153 * Create a child for a parent. If inherit_children, then the new child
154 * will become the new parent of it's parent children
155 */
156static struct callchain_node *
157create_child(struct callchain_node *parent, bool inherit_children)
158{
159 struct callchain_node *new;
160
161 new = malloc(sizeof(*new));
162 if (!new) {
163 perror("not enough memory to create child for code path tree");
164 return NULL;
165 }
166 new->parent = parent;
167 INIT_LIST_HEAD(&new->children);
168 INIT_LIST_HEAD(&new->val);
169
170 if (inherit_children) {
171 struct callchain_node *next;
172
173 list_splice(&parent->children, &new->children);
174 INIT_LIST_HEAD(&parent->children);
175
176 chain_for_each_child(next, new)
177 next->parent = new;
178 }
179 list_add_tail(&new->brothers, &parent->children);
180
181 return new;
182}
183
184/*
185 * Fill the node with callchain values
186 */
187static void
188fill_node(struct callchain_node *node, struct ip_callchain *chain,
189 int start, struct symbol **syms)
190{
191 unsigned int i;
192
193 for (i = start; i < chain->nr; i++) {
194 struct callchain_list *call;
195
196 call = malloc(sizeof(*call));
197 if (!call) {
198 perror("not enough memory for the code path tree");
199 return;
200 }
201 call->ip = chain->ips[i];
202 call->sym = syms[i];
203 list_add_tail(&call->list, &node->val);
204 }
205 node->val_nr = chain->nr - start;
206 if (!node->val_nr)
207 printf("Warning: empty node in callchain tree\n");
208}
209
210static void
211add_child(struct callchain_node *parent, struct ip_callchain *chain,
212 int start, struct symbol **syms)
213{
214 struct callchain_node *new;
215
216 new = create_child(parent, false);
217 fill_node(new, chain, start, syms);
218
219 new->children_hit = 0;
220 new->hit = 1;
221}
222
223/*
224 * Split the parent in two parts (a new child is created) and
225 * give a part of its callchain to the created child.
226 * Then create another child to host the given callchain of new branch
227 */
228static void
229split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
230 struct callchain_list *to_split, int idx_parents, int idx_local,
231 struct symbol **syms)
232{
233 struct callchain_node *new;
234 struct list_head *old_tail;
235 unsigned int idx_total = idx_parents + idx_local;
236
237 /* split */
238 new = create_child(parent, true);
239
240 /* split the callchain and move a part to the new child */
241 old_tail = parent->val.prev;
242 list_del_range(&to_split->list, old_tail);
243 new->val.next = &to_split->list;
244 new->val.prev = old_tail;
245 to_split->list.prev = &new->val;
246 old_tail->next = &new->val;
247
248 /* split the hits */
249 new->hit = parent->hit;
250 new->children_hit = parent->children_hit;
251 parent->children_hit = cumul_hits(new);
252 new->val_nr = parent->val_nr - idx_local;
253 parent->val_nr = idx_local;
254
255 /* create a new child for the new branch if any */
256 if (idx_total < chain->nr) {
257 parent->hit = 0;
258 add_child(parent, chain, idx_total, syms);
259 parent->children_hit++;
260 } else {
261 parent->hit = 1;
262 }
263}
264
265static int
266__append_chain(struct callchain_node *root, struct ip_callchain *chain,
267 unsigned int start, struct symbol **syms);
268
269static void
270__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
271 struct symbol **syms, unsigned int start)
272{
273 struct callchain_node *rnode;
274
275 /* lookup in childrens */
276 chain_for_each_child(rnode, root) {
277 unsigned int ret = __append_chain(rnode, chain, start, syms);
278
279 if (!ret)
280 goto inc_children_hit;
281 }
282 /* nothing in children, add to the current node */
283 add_child(root, chain, start, syms);
284
285inc_children_hit:
286 root->children_hit++;
287}
288
289static int
290__append_chain(struct callchain_node *root, struct ip_callchain *chain,
291 unsigned int start, struct symbol **syms)
292{
293 struct callchain_list *cnode;
294 unsigned int i = start;
295 bool found = false;
296
297 /*
298 * Lookup in the current node
299 * If we have a symbol, then compare the start to match
300 * anywhere inside a function.
301 */
302 list_for_each_entry(cnode, &root->val, list) {
303 if (i == chain->nr)
304 break;
305 if (cnode->sym && syms[i]) {
306 if (cnode->sym->start != syms[i]->start)
307 break;
308 } else if (cnode->ip != chain->ips[i])
309 break;
310 if (!found)
311 found = true;
312 i++;
313 }
314
315 /* matches not, relay on the parent */
316 if (!found)
317 return -1;
318
319 /* we match only a part of the node. Split it and add the new chain */
320 if (i - start < root->val_nr) {
321 split_add_child(root, chain, cnode, start, i - start, syms);
322 return 0;
323 }
324
325 /* we match 100% of the path, increment the hit */
326 if (i - start == root->val_nr && i == chain->nr) {
327 root->hit++;
328 return 0;
329 }
330
331 /* We match the node and still have a part remaining */
332 __append_chain_children(root, chain, syms, i);
333
334 return 0;
335}
336
337void append_chain(struct callchain_node *root, struct ip_callchain *chain,
338 struct symbol **syms)
339{
340 if (!chain->nr)
341 return;
342 __append_chain_children(root, chain, syms, 0);
343}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
new file mode 100644
index 000000000000..a926ae4f5a16
--- /dev/null
+++ b/tools/perf/util/callchain.h
@@ -0,0 +1,60 @@
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 "symbol.h"
8
9enum chain_mode {
10 CHAIN_NONE,
11 CHAIN_FLAT,
12 CHAIN_GRAPH_ABS,
13 CHAIN_GRAPH_REL
14};
15
16struct callchain_node {
17 struct callchain_node *parent;
18 struct list_head brothers;
19 struct list_head children;
20 struct list_head val;
21 struct rb_node rb_node; /* to sort nodes in an rbtree */
22 struct rb_root rb_root; /* sorted tree of children */
23 unsigned int val_nr;
24 u64 hit;
25 u64 children_hit;
26};
27
28struct callchain_param;
29
30typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
31 u64, struct callchain_param *);
32
33struct callchain_param {
34 enum chain_mode mode;
35 double min_percent;
36 sort_chain_func_t sort;
37};
38
39struct callchain_list {
40 u64 ip;
41 struct symbol *sym;
42 struct list_head list;
43};
44
45static inline void callchain_init(struct callchain_node *node)
46{
47 INIT_LIST_HEAD(&node->brothers);
48 INIT_LIST_HEAD(&node->children);
49 INIT_LIST_HEAD(&node->val);
50}
51
52static inline u64 cumul_hits(struct callchain_node *node)
53{
54 return node->hit + node->children_hit;
55}
56
57int register_callchain_param(struct callchain_param *param);
58void append_chain(struct callchain_node *root, struct ip_callchain *chain,
59 struct symbol **syms);
60#endif
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 9a8c20ccc53e..90a044d1fe7d 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])
@@ -222,10 +224,12 @@ int color_fwrite_lines(FILE *fp, const char *color,
222{ 224{
223 if (!*color) 225 if (!*color)
224 return fwrite(buf, count, 1, fp) != 1; 226 return fwrite(buf, count, 1, fp) != 1;
227
225 while (count) { 228 while (count) {
226 char *p = memchr(buf, '\n', count); 229 char *p = memchr(buf, '\n', count);
230
227 if (p != buf && (fputs(color, fp) < 0 || 231 if (p != buf && (fputs(color, fp) < 0 ||
228 fwrite(buf, p ? p - buf : count, 1, fp) != 1 || 232 fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
229 fputs(PERF_COLOR_RESET, fp) < 0)) 233 fputs(PERF_COLOR_RESET, fp) < 0))
230 return -1; 234 return -1;
231 if (!p) 235 if (!p)
@@ -238,4 +242,31 @@ int color_fwrite_lines(FILE *fp, const char *color,
238 return 0; 242 return 0;
239} 243}
240 244
245char *get_percent_color(double percent)
246{
247 char *color = PERF_COLOR_NORMAL;
241 248
249 /*
250 * We color high-overhead entries in red, mid-overhead
251 * entries in green - and keep the low overhead places
252 * normal:
253 */
254 if (percent >= MIN_RED)
255 color = PERF_COLOR_RED;
256 else {
257 if (percent > MIN_GREEN)
258 color = PERF_COLOR_GREEN;
259 }
260 return color;
261}
262
263int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
264{
265 int r;
266 char *color;
267
268 color = get_percent_color(percent);
269 r = color_fprintf(fp, color, fmt, percent);
270
271 return r;
272}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 5abfd379582b..706cec50bd25 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 */
@@ -32,5 +35,7 @@ void color_parse_mem(const char *value, int len, const char *var, char *dst);
32int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); 35int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
33int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 36int 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); 37int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
38int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
39char *get_percent_color(double percent);
35 40
36#endif /* COLOR_H */ 41#endif /* COLOR_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 3dd13faa6a27..780df541006d 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') {
@@ -353,13 +355,13 @@ int perf_config_string(const char **dest, const char *var, const char *value)
353 return 0; 355 return 0;
354} 356}
355 357
356static int perf_default_core_config(const char *var, const char *value) 358static int perf_default_core_config(const char *var __used, const char *value __used)
357{ 359{
358 /* Add other config variables here and to Documentation/config.txt. */ 360 /* Add other config variables here and to Documentation/config.txt. */
359 return 0; 361 return 0;
360} 362}
361 363
362int perf_default_config(const char *var, const char *value, void *dummy) 364int perf_default_config(const char *var, const char *value, void *dummy __used)
363{ 365{
364 if (!prefixcmp(var, "core.")) 366 if (!prefixcmp(var, "core."))
365 return perf_default_core_config(var, value); 367 return perf_default_core_config(var, value);
@@ -471,10 +473,10 @@ static int matches(const char* key, const char* value)
471 !regexec(store.value_regex, value, 0, NULL, 0))); 473 !regexec(store.value_regex, value, 0, NULL, 0)));
472} 474}
473 475
474static int store_aux(const char* key, const char* value, void *cb) 476static int store_aux(const char* key, const char* value, void *cb __used)
475{ 477{
478 int section_len;
476 const char *ep; 479 const char *ep;
477 size_t section_len;
478 480
479 switch (store.state) { 481 switch (store.state) {
480 case KEY_SEEN: 482 case KEY_SEEN:
@@ -551,7 +553,7 @@ static int store_write_section(int fd, const char* key)
551 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); 553 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
552 } 554 }
553 555
554 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 556 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
555 strbuf_release(&sb); 557 strbuf_release(&sb);
556 558
557 return success; 559 return success;
@@ -599,7 +601,7 @@ static int store_write_pair(int fd, const char* key, const char* value)
599 } 601 }
600 strbuf_addf(&sb, "%s\n", quote); 602 strbuf_addf(&sb, "%s\n", quote);
601 603
602 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 604 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
603 strbuf_release(&sb); 605 strbuf_release(&sb);
604 606
605 return success; 607 return success;
@@ -741,7 +743,7 @@ int perf_config_set_multivar(const char* key, const char* value,
741 } else { 743 } else {
742 struct stat st; 744 struct stat st;
743 char* contents; 745 char* contents;
744 size_t contents_sz, copy_begin, copy_end; 746 ssize_t contents_sz, copy_begin, copy_end;
745 int i, new_line = 0; 747 int i, new_line = 0;
746 748
747 if (value_regex == NULL) 749 if (value_regex == NULL)
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index b90ec004f29c..0b791bd346bc 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -11,16 +11,21 @@ enum {
11 D = GIT_DIGIT, 11 D = GIT_DIGIT,
12 G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */ 12 G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */
13 R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */ 13 R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */
14 P = GIT_PRINT_EXTRA, /* printable - alpha - digit - glob - regex */
15
16 PS = GIT_SPACE | GIT_PRINT_EXTRA,
14}; 17};
15 18
16unsigned char sane_ctype[256] = { 19unsigned char sane_ctype[256] = {
20/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
21
17 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */ 22 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */
18 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */ 23 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */
19 S, 0, 0, 0, R, 0, 0, 0, R, R, G, R, 0, 0, R, 0, /* 32.. 47 */ 24 PS,P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */
20 D, D, D, D, D, D, D, D, D, D, 0, 0, 0, 0, 0, G, /* 48.. 63 */ 25 D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */
21 0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */ 26 P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */
22 A, A, A, A, A, A, A, A, A, A, A, G, G, 0, R, 0, /* 80.. 95 */ 27 A, A, A, A, A, A, A, A, A, A, A, G, G, P, R, P, /* 80.. 95 */
23 0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */ 28 P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */
24 A, A, A, A, A, A, A, A, A, A, A, R, R, 0, 0, 0, /* 112..127 */ 29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */
25 /* Nothing in the 128.. range */ 30 /* Nothing in the 128.. range */
26}; 31};
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index d39292263153..34a352867382 100644
--- a/tools/perf/util/exec_cmd.c
+++ b/tools/perf/util/exec_cmd.c
@@ -1,6 +1,9 @@
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; 9extern char **environ;
@@ -51,7 +54,7 @@ const char *perf_extract_argv0_path(const char *argv0)
51 slash--; 54 slash--;
52 55
53 if (slash >= argv0) { 56 if (slash >= argv0) {
54 argv0_path = strndup(argv0, slash - argv0); 57 argv0_path = xstrndup(argv0, slash - argv0);
55 return slash + 1; 58 return slash + 1;
56 } 59 }
57 60
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
new file mode 100644
index 000000000000..b92a457ca32e
--- /dev/null
+++ b/tools/perf/util/header.c
@@ -0,0 +1,245 @@
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 + self->data_size, SEEK_SET);
241
242 self->frozen = 1;
243
244 return self;
245}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
new file mode 100644
index 000000000000..bf280449fcfd
--- /dev/null
+++ b/tools/perf/util/header.h
@@ -0,0 +1,37 @@
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
34
35struct perf_header *perf_header__new(void);
36
37#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/module.c b/tools/perf/util/module.c
new file mode 100644
index 000000000000..ddabe925d65d
--- /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 *path, *name, *tmp;
440 struct module *module;
441 int line_len, 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 5a72586e1df0..4858d83b3b67 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -5,6 +5,7 @@
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#include "cache.h"
8 9
9extern char *strcasestr(const char *haystack, const char *needle); 10extern char *strcasestr(const char *haystack, const char *needle);
10 11
@@ -13,35 +14,33 @@ int nr_counters;
13struct perf_counter_attr attrs[MAX_COUNTERS]; 14struct perf_counter_attr attrs[MAX_COUNTERS];
14 15
15struct event_symbol { 16struct event_symbol {
16 __u8 type; 17 u8 type;
17 __u64 config; 18 u64 config;
18 char *symbol; 19 char *symbol;
20 char *alias;
19}; 21};
20 22
21#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y 23char debugfs_path[MAXPATHLEN];
22#define CR(x, y) .type = PERF_TYPE_##x, .config = y 24
25#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
26#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
23 27
24static struct event_symbol event_symbols[] = { 28static struct event_symbol event_symbols[] = {
25 { C(HARDWARE, HW_CPU_CYCLES), "cpu-cycles", }, 29 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
26 { C(HARDWARE, HW_CPU_CYCLES), "cycles", }, 30 { CHW(INSTRUCTIONS), "instructions", "" },
27 { C(HARDWARE, HW_INSTRUCTIONS), "instructions", }, 31 { CHW(CACHE_REFERENCES), "cache-references", "" },
28 { C(HARDWARE, HW_CACHE_REFERENCES), "cache-references", }, 32 { CHW(CACHE_MISSES), "cache-misses", "" },
29 { C(HARDWARE, HW_CACHE_MISSES), "cache-misses", }, 33 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
30 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", }, 34 { CHW(BRANCH_MISSES), "branch-misses", "" },
31 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches", }, 35 { CHW(BUS_CYCLES), "bus-cycles", "" },
32 { C(HARDWARE, HW_BRANCH_MISSES), "branch-misses", }, 36
33 { C(HARDWARE, HW_BUS_CYCLES), "bus-cycles", }, 37 { CSW(CPU_CLOCK), "cpu-clock", "" },
34 38 { CSW(TASK_CLOCK), "task-clock", "" },
35 { C(SOFTWARE, SW_CPU_CLOCK), "cpu-clock", }, 39 { CSW(PAGE_FAULTS), "page-faults", "faults" },
36 { C(SOFTWARE, SW_TASK_CLOCK), "task-clock", }, 40 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
37 { C(SOFTWARE, SW_PAGE_FAULTS), "page-faults", }, 41 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
38 { C(SOFTWARE, SW_PAGE_FAULTS), "faults", }, 42 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
39 { C(SOFTWARE, SW_PAGE_FAULTS_MIN), "minor-faults", }, 43 { 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}; 44};
46 45
47#define __PERF_COUNTER_FIELD(config, name) \ 46#define __PERF_COUNTER_FIELD(config, name) \
@@ -63,8 +62,8 @@ static char *hw_event_names[] = {
63}; 62};
64 63
65static char *sw_event_names[] = { 64static char *sw_event_names[] = {
66 "cpu-clock-ticks", 65 "cpu-clock-msecs",
67 "task-clock-ticks", 66 "task-clock-msecs",
68 "page-faults", 67 "page-faults",
69 "context-switches", 68 "context-switches",
70 "CPU-migrations", 69 "CPU-migrations",
@@ -74,33 +73,181 @@ static char *sw_event_names[] = {
74 73
75#define MAX_ALIASES 8 74#define MAX_ALIASES 8
76 75
77static char *hw_cache [][MAX_ALIASES] = { 76static char *hw_cache[][MAX_ALIASES] = {
78 { "L1-data" , "l1-d", "l1d" }, 77 { "L1-dcache", "l1-d", "l1d", "L1-data", },
79 { "L1-instruction" , "l1-i", "l1i" }, 78 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
80 { "L2" , "l2" }, 79 { "LLC", "L2" },
81 { "Data-TLB" , "dtlb", "d-tlb" }, 80 { "dTLB", "d-tlb", "Data-TLB", },
82 { "Instruction-TLB" , "itlb", "i-tlb" }, 81 { "iTLB", "i-tlb", "Instruction-TLB", },
83 { "Branch" , "bpu" , "btb", "bpc" }, 82 { "branch", "branches", "bpu", "btb", "bpc", },
83};
84
85static char *hw_cache_op[][MAX_ALIASES] = {
86 { "load", "loads", "read", },
87 { "store", "stores", "write", },
88 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
84}; 89};
85 90
86static char *hw_cache_op [][MAX_ALIASES] = { 91static char *hw_cache_result[][MAX_ALIASES] = {
87 { "Load" , "read" }, 92 { "refs", "Reference", "ops", "access", },
88 { "Store" , "write" }, 93 { "misses", "miss", },
89 { "Prefetch" , "speculative-read", "speculative-load" },
90}; 94};
91 95
92static char *hw_cache_result [][MAX_ALIASES] = { 96#define C(x) PERF_COUNT_HW_CACHE_##x
93 { "Reference" , "ops", "access" }, 97#define CACHE_READ (1 << C(OP_READ))
94 { "Miss" }, 98#define CACHE_WRITE (1 << C(OP_WRITE))
99#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
100#define COP(x) (1 << x)
101
102/*
103 * cache operartion stat
104 * L1I : Read and prefetch only
105 * ITLB and BPU : Read-only
106 */
107static unsigned long hw_cache_stat[C(MAX)] = {
108 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
109 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
110 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
111 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
112 [C(ITLB)] = (CACHE_READ),
113 [C(BPU)] = (CACHE_READ),
95}; 114};
96 115
116#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \
117 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
118 if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \
119 sys_dirent.d_name) && \
120 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
121 (strcmp(sys_dirent.d_name, ".")) && \
122 (strcmp(sys_dirent.d_name, "..")))
123
124static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
125{
126 char evt_path[MAXPATHLEN];
127 int fd;
128
129 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
130 sys_dir->d_name, evt_dir->d_name);
131 fd = open(evt_path, O_RDONLY);
132 if (fd < 0)
133 return -EINVAL;
134 close(fd);
135
136 return 0;
137}
138
139#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \
140 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
141 if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \
142 sys_dirent.d_name, evt_dirent.d_name) && \
143 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
144 (strcmp(evt_dirent.d_name, ".")) && \
145 (strcmp(evt_dirent.d_name, "..")) && \
146 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
147
148#define MAX_EVENT_LENGTH 30
149
150int valid_debugfs_mount(const char *debugfs)
151{
152 struct statfs st_fs;
153
154 if (statfs(debugfs, &st_fs) < 0)
155 return -ENOENT;
156 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
157 return -ENOENT;
158 return 0;
159}
160
161static char *tracepoint_id_to_name(u64 config)
162{
163 static char tracepoint_name[2 * MAX_EVENT_LENGTH];
164 DIR *sys_dir, *evt_dir;
165 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
166 struct stat st;
167 char id_buf[4];
168 int fd;
169 u64 id;
170 char evt_path[MAXPATHLEN];
171
172 if (valid_debugfs_mount(debugfs_path))
173 return "unkown";
174
175 sys_dir = opendir(debugfs_path);
176 if (!sys_dir)
177 goto cleanup;
178
179 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
180 evt_dir = opendir(evt_path);
181 if (!evt_dir)
182 goto cleanup;
183 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
184 evt_path, st) {
185 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
186 debugfs_path, sys_dirent.d_name,
187 evt_dirent.d_name);
188 fd = open(evt_path, O_RDONLY);
189 if (fd < 0)
190 continue;
191 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
192 close(fd);
193 continue;
194 }
195 close(fd);
196 id = atoll(id_buf);
197 if (id == config) {
198 closedir(evt_dir);
199 closedir(sys_dir);
200 snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH,
201 "%s:%s", sys_dirent.d_name,
202 evt_dirent.d_name);
203 return tracepoint_name;
204 }
205 }
206 closedir(evt_dir);
207 }
208
209cleanup:
210 closedir(sys_dir);
211 return "unkown";
212}
213
214static int is_cache_op_valid(u8 cache_type, u8 cache_op)
215{
216 if (hw_cache_stat[cache_type] & COP(cache_op))
217 return 1; /* valid */
218 else
219 return 0; /* invalid */
220}
221
222static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
223{
224 static char name[50];
225
226 if (cache_result) {
227 sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
228 hw_cache_op[cache_op][0],
229 hw_cache_result[cache_result][0]);
230 } else {
231 sprintf(name, "%s-%s", hw_cache[cache_type][0],
232 hw_cache_op[cache_op][1]);
233 }
234
235 return name;
236}
237
97char *event_name(int counter) 238char *event_name(int counter)
98{ 239{
99 __u64 config = attrs[counter].config; 240 u64 config = attrs[counter].config;
100 int type = attrs[counter].type; 241 int type = attrs[counter].type;
242
243 return __event_name(type, config);
244}
245
246char *__event_name(int type, u64 config)
247{
101 static char buf[32]; 248 static char buf[32];
102 249
103 if (attrs[counter].type == PERF_TYPE_RAW) { 250 if (type == PERF_TYPE_RAW) {
104 sprintf(buf, "raw 0x%llx", config); 251 sprintf(buf, "raw 0x%llx", config);
105 return buf; 252 return buf;
106 } 253 }
@@ -112,8 +259,7 @@ char *event_name(int counter)
112 return "unknown-hardware"; 259 return "unknown-hardware";
113 260
114 case PERF_TYPE_HW_CACHE: { 261 case PERF_TYPE_HW_CACHE: {
115 __u8 cache_type, cache_op, cache_result; 262 u8 cache_type, cache_op, cache_result;
116 static char name[100];
117 263
118 cache_type = (config >> 0) & 0xff; 264 cache_type = (config >> 0) & 0xff;
119 if (cache_type > PERF_COUNT_HW_CACHE_MAX) 265 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
@@ -127,12 +273,10 @@ char *event_name(int counter)
127 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX) 273 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
128 return "unknown-ext-hardware-cache-result"; 274 return "unknown-ext-hardware-cache-result";
129 275
130 sprintf(name, "%s-Cache-%s-%ses", 276 if (!is_cache_op_valid(cache_type, cache_op))
131 hw_cache[cache_type][0], 277 return "invalid-cache";
132 hw_cache_op[cache_op][0],
133 hw_cache_result[cache_result][0]);
134 278
135 return name; 279 return event_cache_name(cache_type, cache_op, cache_result);
136 } 280 }
137 281
138 case PERF_TYPE_SOFTWARE: 282 case PERF_TYPE_SOFTWARE:
@@ -140,6 +284,9 @@ char *event_name(int counter)
140 return sw_event_names[config]; 284 return sw_event_names[config];
141 return "unknown-software"; 285 return "unknown-software";
142 286
287 case PERF_TYPE_TRACEPOINT:
288 return tracepoint_id_to_name(config);
289
143 default: 290 default:
144 break; 291 break;
145 } 292 }
@@ -147,43 +294,74 @@ char *event_name(int counter)
147 return "unknown"; 294 return "unknown";
148} 295}
149 296
150static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) 297static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size)
151{ 298{
152 int i, j; 299 int i, j;
300 int n, longest = -1;
153 301
154 for (i = 0; i < size; i++) { 302 for (i = 0; i < size; i++) {
155 for (j = 0; j < MAX_ALIASES; j++) { 303 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
156 if (!names[i][j]) 304 n = strlen(names[i][j]);
157 break; 305 if (n > longest && !strncasecmp(*str, names[i][j], n))
158 if (strcasestr(str, names[i][j])) 306 longest = n;
159 return i; 307 }
308 if (longest > 0) {
309 *str += longest;
310 return i;
160 } 311 }
161 } 312 }
162 313
163 return -1; 314 return -1;
164} 315}
165 316
166static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) 317static int
318parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
167{ 319{
168 int cache_type = -1, cache_op = 0, cache_result = 0; 320 const char *s = *str;
321 int cache_type = -1, cache_op = -1, cache_result = -1;
169 322
170 cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); 323 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
171 /* 324 /*
172 * No fallback - if we cannot get a clear cache type 325 * No fallback - if we cannot get a clear cache type
173 * then bail out: 326 * then bail out:
174 */ 327 */
175 if (cache_type == -1) 328 if (cache_type == -1)
176 return -EINVAL; 329 return 0;
330
331 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
332 ++s;
333
334 if (cache_op == -1) {
335 cache_op = parse_aliases(&s, hw_cache_op,
336 PERF_COUNT_HW_CACHE_OP_MAX);
337 if (cache_op >= 0) {
338 if (!is_cache_op_valid(cache_type, cache_op))
339 return 0;
340 continue;
341 }
342 }
343
344 if (cache_result == -1) {
345 cache_result = parse_aliases(&s, hw_cache_result,
346 PERF_COUNT_HW_CACHE_RESULT_MAX);
347 if (cache_result >= 0)
348 continue;
349 }
350
351 /*
352 * Can't parse this as a cache op or result, so back up
353 * to the '-'.
354 */
355 --s;
356 break;
357 }
177 358
178 cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
179 /* 359 /*
180 * Fall back to reads: 360 * Fall back to reads:
181 */ 361 */
182 if (cache_op == -1) 362 if (cache_op == -1)
183 cache_op = PERF_COUNT_HW_CACHE_OP_READ; 363 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
184 364
185 cache_result = parse_aliases(str, hw_cache_result,
186 PERF_COUNT_HW_CACHE_RESULT_MAX);
187 /* 365 /*
188 * Fall back to accesses: 366 * Fall back to accesses:
189 */ 367 */
@@ -193,82 +371,202 @@ 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); 371 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
194 attr->type = PERF_TYPE_HW_CACHE; 372 attr->type = PERF_TYPE_HW_CACHE;
195 373
196 return 0; 374 *str = s;
375 return 1;
197} 376}
198 377
199/* 378static int parse_tracepoint_event(const char **strp,
200 * Each event can have multiple symbolic names. 379 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{ 380{
205 __u64 config, id; 381 const char *evt_name;
206 int type; 382 char sys_name[MAX_EVENT_LENGTH];
207 unsigned int i; 383 char id_buf[4];
208 const char *sep, *pstr; 384 int fd;
385 unsigned int sys_length, evt_length;
386 u64 id;
387 char evt_path[MAXPATHLEN];
388
389 if (valid_debugfs_mount(debugfs_path))
390 return 0;
209 391
210 if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { 392 evt_name = strchr(*strp, ':');
211 attr->type = PERF_TYPE_RAW; 393 if (!evt_name)
212 attr->config = config; 394 return 0;
213 395
396 sys_length = evt_name - *strp;
397 if (sys_length >= MAX_EVENT_LENGTH)
214 return 0; 398 return 0;
215 }
216 399
217 pstr = str; 400 strncpy(sys_name, *strp, sys_length);
218 sep = strchr(pstr, ':'); 401 sys_name[sys_length] = '\0';
219 if (sep) { 402 evt_name = evt_name + 1;
220 type = atoi(pstr); 403 evt_length = strlen(evt_name);
221 pstr = sep + 1; 404 if (evt_length >= MAX_EVENT_LENGTH)
222 id = atoi(pstr); 405 return 0;
223 sep = strchr(pstr, ':');
224 if (sep) {
225 pstr = sep + 1;
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 406
407 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
408 sys_name, evt_name);
409 fd = open(evt_path, O_RDONLY);
410 if (fd < 0)
411 return 0;
412
413 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
414 close(fd);
234 return 0; 415 return 0;
235 } 416 }
417 close(fd);
418 id = atoll(id_buf);
419 attr->config = id;
420 attr->type = PERF_TYPE_TRACEPOINT;
421 *strp = evt_name + evt_length;
422 return 1;
423}
236 424
237 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 425static int check_events(const char *str, unsigned int i)
238 if (!strncmp(str, event_symbols[i].symbol, 426{
239 strlen(event_symbols[i].symbol))) { 427 int n;
428
429 n = strlen(event_symbols[i].symbol);
430 if (!strncmp(str, event_symbols[i].symbol, n))
431 return n;
432
433 n = strlen(event_symbols[i].alias);
434 if (n)
435 if (!strncmp(str, event_symbols[i].alias, n))
436 return n;
437 return 0;
438}
439
440static int
441parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
442{
443 const char *str = *strp;
444 unsigned int i;
445 int n;
240 446
447 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
448 n = check_events(str, i);
449 if (n > 0) {
241 attr->type = event_symbols[i].type; 450 attr->type = event_symbols[i].type;
242 attr->config = event_symbols[i].config; 451 attr->config = event_symbols[i].config;
452 *strp = str + n;
453 return 1;
454 }
455 }
456 return 0;
457}
458
459static int parse_raw_event(const char **strp, struct perf_counter_attr *attr)
460{
461 const char *str = *strp;
462 u64 config;
463 int n;
464
465 if (*str != 'r')
466 return 0;
467 n = hex2u64(str + 1, &config);
468 if (n > 0) {
469 *strp = str + n + 1;
470 attr->type = PERF_TYPE_RAW;
471 attr->config = config;
472 return 1;
473 }
474 return 0;
475}
243 476
244 return 0; 477static int
478parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
479{
480 const char *str = *strp;
481 char *endp;
482 unsigned long type;
483 u64 config;
484
485 type = strtoul(str, &endp, 0);
486 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
487 str = endp + 1;
488 config = strtoul(str, &endp, 0);
489 if (endp > str) {
490 attr->type = type;
491 attr->config = config;
492 *strp = endp;
493 return 1;
245 } 494 }
246 } 495 }
496 return 0;
497}
498
499static int
500parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
501{
502 const char *str = *strp;
503 int eu = 1, ek = 1, eh = 1;
504
505 if (*str++ != ':')
506 return 0;
507 while (*str) {
508 if (*str == 'u')
509 eu = 0;
510 else if (*str == 'k')
511 ek = 0;
512 else if (*str == 'h')
513 eh = 0;
514 else
515 break;
516 ++str;
517 }
518 if (str >= *strp + 2) {
519 *strp = str;
520 attr->exclude_user = eu;
521 attr->exclude_kernel = ek;
522 attr->exclude_hv = eh;
523 return 1;
524 }
525 return 0;
526}
527
528/*
529 * Each event can have multiple symbolic names.
530 * Symbolic names are (almost) exactly matched.
531 */
532static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
533{
534 if (!(parse_tracepoint_event(str, attr) ||
535 parse_raw_event(str, attr) ||
536 parse_numeric_event(str, attr) ||
537 parse_symbolic_event(str, attr) ||
538 parse_generic_hw_event(str, attr)))
539 return 0;
247 540
248 return parse_generic_hw_symbols(str, attr); 541 parse_event_modifier(str, attr);
542
543 return 1;
249} 544}
250 545
251int parse_events(const struct option *opt, const char *str, int unset) 546int parse_events(const struct option *opt __used, const char *str, int unset __used)
252{ 547{
253 struct perf_counter_attr attr; 548 struct perf_counter_attr attr;
254 int ret;
255 549
256 memset(&attr, 0, sizeof(attr)); 550 for (;;) {
257again: 551 if (nr_counters == MAX_COUNTERS)
258 if (nr_counters == MAX_COUNTERS) 552 return -1;
259 return -1; 553
554 memset(&attr, 0, sizeof(attr));
555 if (!parse_event_symbols(&str, &attr))
556 return -1;
260 557
261 ret = parse_event_symbols(str, &attr); 558 if (!(*str == 0 || *str == ',' || isspace(*str)))
262 if (ret < 0) 559 return -1;
263 return ret;
264 560
265 attrs[nr_counters] = attr; 561 attrs[nr_counters] = attr;
266 nr_counters++; 562 nr_counters++;
267 563
268 str = strstr(str, ","); 564 if (*str == 0)
269 if (str) { 565 break;
270 str++; 566 if (*str == ',')
271 goto again; 567 ++str;
568 while (isspace(*str))
569 ++str;
272 } 570 }
273 571
274 return 0; 572 return 0;
@@ -283,34 +581,92 @@ static const char * const event_type_descriptors[] = {
283}; 581};
284 582
285/* 583/*
584 * Print the events from <debugfs_mount_point>/tracing/events
585 */
586
587static void print_tracepoint_events(void)
588{
589 DIR *sys_dir, *evt_dir;
590 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
591 struct stat st;
592 char evt_path[MAXPATHLEN];
593
594 if (valid_debugfs_mount(debugfs_path))
595 return;
596
597 sys_dir = opendir(debugfs_path);
598 if (!sys_dir)
599 goto cleanup;
600
601 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
602 evt_dir = opendir(evt_path);
603 if (!evt_dir)
604 goto cleanup;
605 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
606 evt_path, st) {
607 snprintf(evt_path, MAXPATHLEN, "%s:%s",
608 sys_dirent.d_name, evt_dirent.d_name);
609 fprintf(stderr, " %-40s [%s]\n", evt_path,
610 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
611 }
612 closedir(evt_dir);
613 }
614
615cleanup:
616 closedir(sys_dir);
617}
618
619/*
286 * Print the help text for the event symbols: 620 * Print the help text for the event symbols:
287 */ 621 */
288void print_events(void) 622void print_events(void)
289{ 623{
290 struct event_symbol *syms = event_symbols; 624 struct event_symbol *syms = event_symbols;
291 unsigned int i, type, prev_type = -1; 625 unsigned int i, type, op, prev_type = -1;
626 char name[40];
292 627
293 fprintf(stderr, "\n"); 628 fprintf(stderr, "\n");
294 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 629 fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
295 630
296 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 631 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
297 type = syms->type + 1; 632 type = syms->type + 1;
298 if (type > ARRAY_SIZE(event_type_descriptors)) 633 if (type >= ARRAY_SIZE(event_type_descriptors))
299 type = 0; 634 type = 0;
300 635
301 if (type != prev_type) 636 if (type != prev_type)
302 fprintf(stderr, "\n"); 637 fprintf(stderr, "\n");
303 638
304 fprintf(stderr, " %-30s [%s]\n", syms->symbol, 639 if (strlen(syms->alias))
640 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
641 else
642 strcpy(name, syms->symbol);
643 fprintf(stderr, " %-40s [%s]\n", name,
305 event_type_descriptors[type]); 644 event_type_descriptors[type]);
306 645
307 prev_type = type; 646 prev_type = type;
308 } 647 }
309 648
310 fprintf(stderr, "\n"); 649 fprintf(stderr, "\n");
311 fprintf(stderr, " %-30s [raw hardware event descriptor]\n", 650 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
651 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
652 /* skip invalid cache type */
653 if (!is_cache_op_valid(type, op))
654 continue;
655
656 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
657 fprintf(stderr, " %-40s [%s]\n",
658 event_cache_name(type, op, i),
659 event_type_descriptors[4]);
660 }
661 }
662 }
663
664 fprintf(stderr, "\n");
665 fprintf(stderr, " %-40s [raw hardware event descriptor]\n",
312 "rNNN"); 666 "rNNN");
313 fprintf(stderr, "\n"); 667 fprintf(stderr, "\n");
314 668
669 print_tracepoint_events();
670
315 exit(129); 671 exit(129);
316} 672}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index e3d552908e60..192a962e3a0f 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -3,11 +3,14 @@
3 * Parse symbolic events/counts passed in as options: 3 * Parse symbolic events/counts passed in as options:
4 */ 4 */
5 5
6struct option;
7
6extern int nr_counters; 8extern int nr_counters;
7 9
8extern struct perf_counter_attr attrs[MAX_COUNTERS]; 10extern struct perf_counter_attr attrs[MAX_COUNTERS];
9 11
10extern char *event_name(int ctr); 12extern char *event_name(int ctr);
13extern char *__event_name(int type, u64 config);
11 14
12extern int parse_events(const struct option *opt, const char *str, int unset); 15extern int parse_events(const struct option *opt, const char *str, int unset);
13 16
@@ -15,3 +18,6 @@ extern int parse_events(const struct option *opt, const char *str, int unset);
15 18
16extern void print_events(void); 19extern void print_events(void);
17 20
21extern char debugfs_path[];
22extern int valid_debugfs_mount(const char *debugfs);
23
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index b3affb1658d2..1bf67190c820 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--;
@@ -485,7 +486,7 @@ int parse_options_usage(const char * const *usagestr,
485} 486}
486 487
487 488
488int parse_opt_verbosity_cb(const struct option *opt, const char *arg, 489int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
489 int unset) 490 int unset)
490{ 491{
491 int *target = opt->value; 492 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/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..a3935343091a 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
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.c b/tools/perf/util/string.c
index ec33c0c7f4e2..c93eca9a7be3 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -15,7 +15,7 @@ static int hex(char ch)
15 * While we find nice hex chars, build a long_val. 15 * While we find nice hex chars, build a long_val.
16 * Return number of chars processed. 16 * Return number of chars processed.
17 */ 17 */
18int hex2u64(const char *ptr, __u64 *long_val) 18int hex2u64(const char *ptr, u64 *long_val)
19{ 19{
20 const char *p = ptr; 20 const char *p = ptr;
21 *long_val = 0; 21 *long_val = 0;
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 72812c1c9a7a..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 <linux/types.h> 4#include "types.h"
5 5
6int hex2u64(const char *ptr, __u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7
8#define _STR(x) #x
9#define STR(x) _STR(x)
7 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 49a55f813712..f1dcede14307 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -7,11 +7,36 @@
7#include <gelf.h> 7#include <gelf.h>
8#include <elf.h> 8#include <elf.h>
9 9
10#ifndef NO_DEMANGLE
11#include <bfd.h>
12#else
13static inline
14char *bfd_demangle(void __used *v, const char __used *c, int __used i)
15{
16 return NULL;
17}
18#endif
19
10const char *sym_hist_filter; 20const char *sym_hist_filter;
11 21
12static struct symbol *symbol__new(__u64 start, __u64 len, 22#ifndef DMGL_PARAMS
23#define DMGL_PARAMS (1 << 0) /* Include function args */
24#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
25#endif
26
27enum dso_origin {
28 DSO__ORIG_KERNEL = 0,
29 DSO__ORIG_JAVA_JIT,
30 DSO__ORIG_FEDORA,
31 DSO__ORIG_UBUNTU,
32 DSO__ORIG_BUILDID,
33 DSO__ORIG_DSO,
34 DSO__ORIG_NOT_FOUND,
35};
36
37static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size, 38 const char *name, unsigned int priv_size,
14 __u64 obj_start, int verbose) 39 u64 obj_start, int verbose)
15{ 40{
16 size_t namelen = strlen(name) + 1; 41 size_t namelen = strlen(name) + 1;
17 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 42 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
@@ -21,21 +46,21 @@ static struct symbol *symbol__new(__u64 start, __u64 len,
21 46
22 if (verbose >= 2) 47 if (verbose >= 2)
23 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 48 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); 49 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
25 50
26 self->obj_start= obj_start; 51 self->obj_start= obj_start;
27 self->hist = NULL; 52 self->hist = NULL;
28 self->hist_sum = 0; 53 self->hist_sum = 0;
29 54
30 if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 55 if (sym_hist_filter && !strcmp(name, sym_hist_filter))
31 self->hist = calloc(sizeof(__u64), len); 56 self->hist = calloc(sizeof(u64), len);
32 57
33 if (priv_size) { 58 if (priv_size) {
34 memset(self, 0, priv_size); 59 memset(self, 0, priv_size);
35 self = ((void *)self) + priv_size; 60 self = ((void *)self) + priv_size;
36 } 61 }
37 self->start = start; 62 self->start = start;
38 self->end = start + len - 1; 63 self->end = len ? start + len - 1 : start;
39 memcpy(self->name, name, namelen); 64 memcpy(self->name, name, namelen);
40 65
41 return self; 66 return self;
@@ -48,8 +73,12 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
48 73
49static size_t symbol__fprintf(struct symbol *self, FILE *fp) 74static size_t symbol__fprintf(struct symbol *self, FILE *fp)
50{ 75{
51 return fprintf(fp, " %llx-%llx %s\n", 76 if (!self->module)
77 return fprintf(fp, " %llx-%llx %s\n",
52 self->start, self->end, self->name); 78 self->start, self->end, self->name);
79 else
80 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
81 self->start, self->end, self->name, self->module->name);
53} 82}
54 83
55struct dso *dso__new(const char *name, unsigned int sym_priv_size) 84struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -61,6 +90,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
61 self->syms = RB_ROOT; 90 self->syms = RB_ROOT;
62 self->sym_priv_size = sym_priv_size; 91 self->sym_priv_size = sym_priv_size;
63 self->find_symbol = dso__find_symbol; 92 self->find_symbol = dso__find_symbol;
93 self->slen_calculated = 0;
94 self->origin = DSO__ORIG_NOT_FOUND;
64 } 95 }
65 96
66 return self; 97 return self;
@@ -89,7 +120,7 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
89{ 120{
90 struct rb_node **p = &self->syms.rb_node; 121 struct rb_node **p = &self->syms.rb_node;
91 struct rb_node *parent = NULL; 122 struct rb_node *parent = NULL;
92 const __u64 ip = sym->start; 123 const u64 ip = sym->start;
93 struct symbol *s; 124 struct symbol *s;
94 125
95 while (*p != NULL) { 126 while (*p != NULL) {
@@ -104,7 +135,7 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
104 rb_insert_color(&sym->rb_node, &self->syms); 135 rb_insert_color(&sym->rb_node, &self->syms);
105} 136}
106 137
107struct symbol *dso__find_symbol(struct dso *self, __u64 ip) 138struct symbol *dso__find_symbol(struct dso *self, u64 ip)
108{ 139{
109 struct rb_node *n; 140 struct rb_node *n;
110 141
@@ -146,12 +177,13 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
146 char *line = NULL; 177 char *line = NULL;
147 size_t n; 178 size_t n;
148 FILE *file = fopen("/proc/kallsyms", "r"); 179 FILE *file = fopen("/proc/kallsyms", "r");
180 int count = 0;
149 181
150 if (file == NULL) 182 if (file == NULL)
151 goto out_failure; 183 goto out_failure;
152 184
153 while (!feof(file)) { 185 while (!feof(file)) {
154 __u64 start; 186 u64 start;
155 struct symbol *sym; 187 struct symbol *sym;
156 int line_len, len; 188 int line_len, len;
157 char symbol_type; 189 char symbol_type;
@@ -188,8 +220,10 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
188 220
189 if (filter && filter(self, sym)) 221 if (filter && filter(self, sym))
190 symbol__delete(sym, self->sym_priv_size); 222 symbol__delete(sym, self->sym_priv_size);
191 else 223 else {
192 dso__insert_symbol(self, sym); 224 dso__insert_symbol(self, sym);
225 count++;
226 }
193 } 227 }
194 228
195 /* 229 /*
@@ -212,7 +246,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
212 free(line); 246 free(line);
213 fclose(file); 247 fclose(file);
214 248
215 return 0; 249 return count;
216 250
217out_delete_line: 251out_delete_line:
218 free(line); 252 free(line);
@@ -232,7 +266,7 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verb
232 goto out_failure; 266 goto out_failure;
233 267
234 while (!feof(file)) { 268 while (!feof(file)) {
235 __u64 start, size; 269 u64 start, size;
236 struct symbol *sym; 270 struct symbol *sym;
237 int line_len, len; 271 int line_len, len;
238 272
@@ -307,6 +341,26 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
307 sym->st_size != 0; 341 sym->st_size != 0;
308} 342}
309 343
344static inline int elf_sym__is_label(const GElf_Sym *sym)
345{
346 return elf_sym__type(sym) == STT_NOTYPE &&
347 sym->st_name != 0 &&
348 sym->st_shndx != SHN_UNDEF &&
349 sym->st_shndx != SHN_ABS;
350}
351
352static inline const char *elf_sec__name(const GElf_Shdr *shdr,
353 const Elf_Data *secstrs)
354{
355 return secstrs->d_buf + shdr->sh_name;
356}
357
358static inline int elf_sec__is_text(const GElf_Shdr *shdr,
359 const Elf_Data *secstrs)
360{
361 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
362}
363
310static inline const char *elf_sym__name(const GElf_Sym *sym, 364static inline const char *elf_sym__name(const GElf_Sym *sym,
311 const Elf_Data *symstrs) 365 const Elf_Data *symstrs)
312{ 366{
@@ -346,36 +400,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
346 idx < nr_entries; \ 400 idx < nr_entries; \
347 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 401 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
348 402
349static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 403/*
350 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 404 * We need to check if we have a .dynsym, so that we can handle the
351 GElf_Shdr *shdr_dynsym, 405 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
352 size_t dynsym_idx, int verbose) 406 * .dynsym or .symtab).
407 * And always look at the original dso, not at debuginfo packages, that
408 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
409 */
410static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
353{ 411{
354 uint32_t nr_rel_entries, idx; 412 uint32_t nr_rel_entries, idx;
355 GElf_Sym sym; 413 GElf_Sym sym;
356 __u64 plt_offset; 414 u64 plt_offset;
357 GElf_Shdr shdr_plt; 415 GElf_Shdr shdr_plt;
358 struct symbol *f; 416 struct symbol *f;
359 GElf_Shdr shdr_rel_plt; 417 GElf_Shdr shdr_rel_plt, shdr_dynsym;
360 Elf_Data *reldata, *syms, *symstrs; 418 Elf_Data *reldata, *syms, *symstrs;
361 Elf_Scn *scn_plt_rel, *scn_symstrs; 419 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
420 size_t dynsym_idx;
421 GElf_Ehdr ehdr;
362 char sympltname[1024]; 422 char sympltname[1024];
363 int nr = 0, symidx; 423 Elf *elf;
424 int nr = 0, symidx, fd, err = 0;
364 425
365 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 426 fd = open(self->name, O_RDONLY);
427 if (fd < 0)
428 goto out;
429
430 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
431 if (elf == NULL)
432 goto out_close;
433
434 if (gelf_getehdr(elf, &ehdr) == NULL)
435 goto out_elf_end;
436
437 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
438 ".dynsym", &dynsym_idx);
439 if (scn_dynsym == NULL)
440 goto out_elf_end;
441
442 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
366 ".rela.plt", NULL); 443 ".rela.plt", NULL);
367 if (scn_plt_rel == NULL) { 444 if (scn_plt_rel == NULL) {
368 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 445 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
369 ".rel.plt", NULL); 446 ".rel.plt", NULL);
370 if (scn_plt_rel == NULL) 447 if (scn_plt_rel == NULL)
371 return 0; 448 goto out_elf_end;
372 } 449 }
373 450
451 err = -1;
452
374 if (shdr_rel_plt.sh_link != dynsym_idx) 453 if (shdr_rel_plt.sh_link != dynsym_idx)
375 return 0; 454 goto out_elf_end;
376 455
377 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 456 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
378 return 0; 457 goto out_elf_end;
379 458
380 /* 459 /*
381 * Fetch the relocation section to find the indexes to the GOT 460 * Fetch the relocation section to find the indexes to the GOT
@@ -383,19 +462,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
383 */ 462 */
384 reldata = elf_getdata(scn_plt_rel, NULL); 463 reldata = elf_getdata(scn_plt_rel, NULL);
385 if (reldata == NULL) 464 if (reldata == NULL)
386 return -1; 465 goto out_elf_end;
387 466
388 syms = elf_getdata(scn_dynsym, NULL); 467 syms = elf_getdata(scn_dynsym, NULL);
389 if (syms == NULL) 468 if (syms == NULL)
390 return -1; 469 goto out_elf_end;
391 470
392 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 471 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
393 if (scn_symstrs == NULL) 472 if (scn_symstrs == NULL)
394 return -1; 473 goto out_elf_end;
395 474
396 symstrs = elf_getdata(scn_symstrs, NULL); 475 symstrs = elf_getdata(scn_symstrs, NULL);
397 if (symstrs == NULL) 476 if (symstrs == NULL)
398 return -1; 477 goto out_elf_end;
399 478
400 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 479 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
401 plt_offset = shdr_plt.sh_offset; 480 plt_offset = shdr_plt.sh_offset;
@@ -414,7 +493,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
414 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 493 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
415 sympltname, self->sym_priv_size, 0, verbose); 494 sympltname, self->sym_priv_size, 0, verbose);
416 if (!f) 495 if (!f)
417 return -1; 496 goto out_elf_end;
418 497
419 dso__insert_symbol(self, f); 498 dso__insert_symbol(self, f);
420 ++nr; 499 ++nr;
@@ -432,25 +511,31 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
432 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 511 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
433 sympltname, self->sym_priv_size, 0, verbose); 512 sympltname, self->sym_priv_size, 0, verbose);
434 if (!f) 513 if (!f)
435 return -1; 514 goto out_elf_end;
436 515
437 dso__insert_symbol(self, f); 516 dso__insert_symbol(self, f);
438 ++nr; 517 ++nr;
439 } 518 }
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 } 519 }
446 520
447 return nr; 521 err = 0;
522out_elf_end:
523 elf_end(elf);
524out_close:
525 close(fd);
526
527 if (err == 0)
528 return nr;
529out:
530 fprintf(stderr, "%s: problems reading %s PLT info.\n",
531 __func__, self->name);
532 return 0;
448} 533}
449 534
450static int dso__load_sym(struct dso *self, int fd, const char *name, 535static int dso__load_sym(struct dso *self, int fd, const char *name,
451 symbol_filter_t filter, int verbose) 536 symbol_filter_t filter, int verbose, struct module *mod)
452{ 537{
453 Elf_Data *symstrs; 538 Elf_Data *symstrs, *secstrs;
454 uint32_t nr_syms; 539 uint32_t nr_syms;
455 int err = -1; 540 int err = -1;
456 uint32_t index; 541 uint32_t index;
@@ -458,10 +543,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
458 GElf_Shdr shdr; 543 GElf_Shdr shdr;
459 Elf_Data *syms; 544 Elf_Data *syms;
460 GElf_Sym sym; 545 GElf_Sym sym;
461 Elf_Scn *sec, *sec_dynsym; 546 Elf_Scn *sec, *sec_strndx;
462 Elf *elf; 547 Elf *elf;
463 size_t dynsym_idx; 548 int nr = 0, kernel = !strcmp("[kernel]", self->name);
464 int nr = 0;
465 549
466 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 550 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
467 if (elf == NULL) { 551 if (elf == NULL) {
@@ -477,32 +561,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
477 goto out_elf_end; 561 goto out_elf_end;
478 } 562 }
479 563
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); 564 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
500 if (sec == NULL) { 565 if (sec == NULL) {
501 if (sec_dynsym == NULL) 566 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
567 if (sec == NULL)
502 goto out_elf_end; 568 goto out_elf_end;
503
504 sec = sec_dynsym;
505 gelf_getshdr(sec, &shdr);
506 } 569 }
507 570
508 syms = elf_getdata(sec, NULL); 571 syms = elf_getdata(sec, NULL);
@@ -517,15 +580,34 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
517 if (symstrs == NULL) 580 if (symstrs == NULL)
518 goto out_elf_end; 581 goto out_elf_end;
519 582
583 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
584 if (sec_strndx == NULL)
585 goto out_elf_end;
586
587 secstrs = elf_getdata(sec_strndx, NULL);
588 if (secstrs == NULL)
589 goto out_elf_end;
590
520 nr_syms = shdr.sh_size / shdr.sh_entsize; 591 nr_syms = shdr.sh_size / shdr.sh_entsize;
521 592
522 memset(&sym, 0, sizeof(sym)); 593 memset(&sym, 0, sizeof(sym));
594 if (!kernel) {
595 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
596 elf_section_by_name(elf, &ehdr, &shdr,
597 ".gnu.prelink_undo",
598 NULL) != NULL);
599 } else self->adjust_symbols = 0;
523 600
524 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 601 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
525 struct symbol *f; 602 struct symbol *f;
526 __u64 obj_start; 603 const char *name;
527 604 char *demangled;
528 if (!elf_sym__is_function(&sym)) 605 u64 obj_start;
606 struct section *section = NULL;
607 int is_label = elf_sym__is_label(&sym);
608 const char *section_name;
609
610 if (!is_label && !elf_sym__is_function(&sym))
529 continue; 611 continue;
530 612
531 sec = elf_getscn(elf, sym.st_shndx); 613 sec = elf_getscn(elf, sym.st_shndx);
@@ -533,19 +615,51 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
533 goto out_elf_end; 615 goto out_elf_end;
534 616
535 gelf_getshdr(sec, &shdr); 617 gelf_getshdr(sec, &shdr);
618
619 if (is_label && !elf_sec__is_text(&shdr, secstrs))
620 continue;
621
622 section_name = elf_sec__name(&shdr, secstrs);
536 obj_start = sym.st_value; 623 obj_start = sym.st_value;
537 624
538 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 625 if (self->adjust_symbols) {
626 if (verbose >= 2)
627 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
628 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
629
630 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
631 }
632
633 if (mod) {
634 section = mod->sections->find_section(mod->sections, section_name);
635 if (section)
636 sym.st_value += section->vma;
637 else {
638 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
639 mod->name, section_name);
640 goto out_elf_end;
641 }
642 }
643 /*
644 * We need to figure out if the object was created from C++ sources
645 * DWARF DW_compile_unit has this, but we don't always have access
646 * to it...
647 */
648 name = elf_sym__name(&sym, symstrs);
649 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
650 if (demangled != NULL)
651 name = demangled;
539 652
540 f = symbol__new(sym.st_value, sym.st_size, 653 f = symbol__new(sym.st_value, sym.st_size, name,
541 elf_sym__name(&sym, symstrs),
542 self->sym_priv_size, obj_start, verbose); 654 self->sym_priv_size, obj_start, verbose);
655 free(demangled);
543 if (!f) 656 if (!f)
544 goto out_elf_end; 657 goto out_elf_end;
545 658
546 if (filter && filter(self, f)) 659 if (filter && filter(self, f))
547 symbol__delete(f, self->sym_priv_size); 660 symbol__delete(f, self->sym_priv_size);
548 else { 661 else {
662 f->module = mod;
549 dso__insert_symbol(self, f); 663 dso__insert_symbol(self, f);
550 nr++; 664 nr++;
551 } 665 }
@@ -558,42 +672,135 @@ out_close:
558 return err; 672 return err;
559} 673}
560 674
675#define BUILD_ID_SIZE 128
676
677static char *dso__read_build_id(struct dso *self, int verbose)
678{
679 int i;
680 GElf_Ehdr ehdr;
681 GElf_Shdr shdr;
682 Elf_Data *build_id_data;
683 Elf_Scn *sec;
684 char *build_id = NULL, *bid;
685 unsigned char *raw;
686 Elf *elf;
687 int fd = open(self->name, O_RDONLY);
688
689 if (fd < 0)
690 goto out;
691
692 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
693 if (elf == NULL) {
694 if (verbose)
695 fprintf(stderr, "%s: cannot read %s ELF file.\n",
696 __func__, self->name);
697 goto out_close;
698 }
699
700 if (gelf_getehdr(elf, &ehdr) == NULL) {
701 if (verbose)
702 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
703 goto out_elf_end;
704 }
705
706 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
707 if (sec == NULL)
708 goto out_elf_end;
709
710 build_id_data = elf_getdata(sec, NULL);
711 if (build_id_data == NULL)
712 goto out_elf_end;
713 build_id = malloc(BUILD_ID_SIZE);
714 if (build_id == NULL)
715 goto out_elf_end;
716 raw = build_id_data->d_buf + 16;
717 bid = build_id;
718
719 for (i = 0; i < 20; ++i) {
720 sprintf(bid, "%02x", *raw);
721 ++raw;
722 bid += 2;
723 }
724 if (verbose >= 2)
725 printf("%s(%s): %s\n", __func__, self->name, build_id);
726out_elf_end:
727 elf_end(elf);
728out_close:
729 close(fd);
730out:
731 return build_id;
732}
733
734char dso__symtab_origin(const struct dso *self)
735{
736 static const char origin[] = {
737 [DSO__ORIG_KERNEL] = 'k',
738 [DSO__ORIG_JAVA_JIT] = 'j',
739 [DSO__ORIG_FEDORA] = 'f',
740 [DSO__ORIG_UBUNTU] = 'u',
741 [DSO__ORIG_BUILDID] = 'b',
742 [DSO__ORIG_DSO] = 'd',
743 };
744
745 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
746 return '!';
747 return origin[self->origin];
748}
749
561int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 750int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
562{ 751{
563 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 752 int size = PATH_MAX;
564 char *name = malloc(size); 753 char *name = malloc(size), *build_id = NULL;
565 int variant = 0;
566 int ret = -1; 754 int ret = -1;
567 int fd; 755 int fd;
568 756
569 if (!name) 757 if (!name)
570 return -1; 758 return -1;
571 759
572 if (strncmp(self->name, "/tmp/perf-", 10) == 0) 760 self->adjust_symbols = 0;
573 return dso__load_perf_map(self, filter, verbose); 761
762 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
763 ret = dso__load_perf_map(self, filter, verbose);
764 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
765 DSO__ORIG_NOT_FOUND;
766 return ret;
767 }
768
769 self->origin = DSO__ORIG_FEDORA - 1;
574 770
575more: 771more:
576 do { 772 do {
577 switch (variant) { 773 self->origin++;
578 case 0: /* Fedora */ 774 switch (self->origin) {
775 case DSO__ORIG_FEDORA:
579 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 776 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
580 break; 777 break;
581 case 1: /* Ubuntu */ 778 case DSO__ORIG_UBUNTU:
582 snprintf(name, size, "/usr/lib/debug%s", self->name); 779 snprintf(name, size, "/usr/lib/debug%s", self->name);
583 break; 780 break;
584 case 2: /* Sane people */ 781 case DSO__ORIG_BUILDID:
782 build_id = dso__read_build_id(self, verbose);
783 if (build_id != NULL) {
784 snprintf(name, size,
785 "/usr/lib/debug/.build-id/%.2s/%s.debug",
786 build_id, build_id + 2);
787 free(build_id);
788 break;
789 }
790 self->origin++;
791 /* Fall thru */
792 case DSO__ORIG_DSO:
585 snprintf(name, size, "%s", self->name); 793 snprintf(name, size, "%s", self->name);
586 break; 794 break;
587 795
588 default: 796 default:
589 goto out; 797 goto out;
590 } 798 }
591 variant++;
592 799
593 fd = open(name, O_RDONLY); 800 fd = open(name, O_RDONLY);
594 } while (fd < 0); 801 } while (fd < 0);
595 802
596 ret = dso__load_sym(self, fd, name, filter, verbose); 803 ret = dso__load_sym(self, fd, name, filter, verbose, NULL);
597 close(fd); 804 close(fd);
598 805
599 /* 806 /*
@@ -602,11 +809,96 @@ more:
602 if (!ret) 809 if (!ret)
603 goto more; 810 goto more;
604 811
812 if (ret > 0) {
813 int nr_plt = dso__synthesize_plt_symbols(self, verbose);
814 if (nr_plt > 0)
815 ret += nr_plt;
816 }
605out: 817out:
606 free(name); 818 free(name);
607 return ret; 819 return ret;
608} 820}
609 821
822static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
823 symbol_filter_t filter, int verbose)
824{
825 struct module *mod = mod_dso__find_module(mods, name);
826 int err = 0, fd;
827
828 if (mod == NULL || !mod->active)
829 return err;
830
831 fd = open(mod->path, O_RDONLY);
832
833 if (fd < 0)
834 return err;
835
836 err = dso__load_sym(self, fd, name, filter, verbose, mod);
837 close(fd);
838
839 return err;
840}
841
842int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose)
843{
844 struct mod_dso *mods = mod_dso__new_dso("modules");
845 struct module *pos;
846 struct rb_node *next;
847 int err;
848
849 err = mod_dso__load_modules(mods);
850
851 if (err <= 0)
852 return err;
853
854 /*
855 * Iterate over modules, and load active symbols.
856 */
857 next = rb_first(&mods->mods);
858 while (next) {
859 pos = rb_entry(next, struct module, rb_node);
860 err = dso__load_module(self, mods, pos->name, filter, verbose);
861
862 if (err < 0)
863 break;
864
865 next = rb_next(&pos->rb_node);
866 }
867
868 if (err < 0) {
869 mod_dso__delete_modules(mods);
870 mod_dso__delete_self(mods);
871 }
872
873 return err;
874}
875
876static inline void dso__fill_symbol_holes(struct dso *self)
877{
878 struct symbol *prev = NULL;
879 struct rb_node *nd;
880
881 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
882 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
883
884 if (prev) {
885 u64 hole = 0;
886 int alias = pos->start == prev->start;
887
888 if (!alias)
889 hole = prev->start - pos->end - 1;
890
891 if (hole || alias) {
892 if (alias)
893 pos->end = prev->end;
894 else if (hole)
895 pos->end = prev->start - 1;
896 }
897 }
898 prev = pos;
899 }
900}
901
610static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 902static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
611 symbol_filter_t filter, int verbose) 903 symbol_filter_t filter, int verbose)
612{ 904{
@@ -615,23 +907,33 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
615 if (fd < 0) 907 if (fd < 0)
616 return -1; 908 return -1;
617 909
618 err = dso__load_sym(self, fd, vmlinux, filter, verbose); 910 err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL);
911
912 if (err > 0)
913 dso__fill_symbol_holes(self);
914
619 close(fd); 915 close(fd);
620 916
621 return err; 917 return err;
622} 918}
623 919
624int dso__load_kernel(struct dso *self, const char *vmlinux, 920int dso__load_kernel(struct dso *self, const char *vmlinux,
625 symbol_filter_t filter, int verbose) 921 symbol_filter_t filter, int verbose, int modules)
626{ 922{
627 int err = -1; 923 int err = -1;
628 924
629 if (vmlinux) 925 if (vmlinux) {
630 err = dso__load_vmlinux(self, vmlinux, filter, verbose); 926 err = dso__load_vmlinux(self, vmlinux, filter, verbose);
927 if (err > 0 && modules)
928 err = dso__load_modules(self, filter, verbose);
929 }
631 930
632 if (err) 931 if (err <= 0)
633 err = dso__load_kallsyms(self, filter, verbose); 932 err = dso__load_kallsyms(self, filter, verbose);
634 933
934 if (err > 0)
935 self->origin = DSO__ORIG_KERNEL;
936
635 return err; 937 return err;
636} 938}
637 939
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 0d1292bd8270..1e003ec2f4b1 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -2,24 +2,31 @@
2#define _PERF_SYMBOL_ 1 2#define _PERF_SYMBOL_ 1
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include "list.h" 5#include "types.h"
6#include "rbtree.h" 6#include <linux/list.h>
7#include <linux/rbtree.h>
8#include "module.h"
7 9
8struct symbol { 10struct symbol {
9 struct rb_node rb_node; 11 struct rb_node rb_node;
10 __u64 start; 12 u64 start;
11 __u64 end; 13 u64 end;
12 __u64 obj_start; 14 u64 obj_start;
13 __u64 hist_sum; 15 u64 hist_sum;
14 __u64 *hist; 16 u64 *hist;
17 struct module *module;
18 void *priv;
15 char name[0]; 19 char name[0];
16}; 20};
17 21
18struct dso { 22struct dso {
19 struct list_head node; 23 struct list_head node;
20 struct rb_root syms; 24 struct rb_root syms;
25 struct symbol *(*find_symbol)(struct dso *, u64 ip);
21 unsigned int sym_priv_size; 26 unsigned int sym_priv_size;
22 struct symbol *(*find_symbol)(struct dso *, __u64 ip); 27 unsigned char adjust_symbols;
28 unsigned char slen_calculated;
29 unsigned char origin;
23 char name[0]; 30 char name[0];
24}; 31};
25 32
@@ -35,13 +42,15 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
35 return ((void *)sym) - self->sym_priv_size; 42 return ((void *)sym) - self->sym_priv_size;
36} 43}
37 44
38struct symbol *dso__find_symbol(struct dso *self, __u64 ip); 45struct symbol *dso__find_symbol(struct dso *self, u64 ip);
39 46
40int dso__load_kernel(struct dso *self, const char *vmlinux, 47int dso__load_kernel(struct dso *self, const char *vmlinux,
41 symbol_filter_t filter, int verbose); 48 symbol_filter_t filter, int verbose, int modules);
49int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
42int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 50int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
43 51
44size_t dso__fprintf(struct dso *self, FILE *fp); 52size_t dso__fprintf(struct dso *self, FILE *fp);
53char dso__symtab_origin(const struct dso *self);
45 54
46void symbol__init(void); 55void symbol__init(void);
47#endif /* _PERF_SYMBOL_ */ 56#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
new file mode 100644
index 000000000000..5e75f9005940
--- /dev/null
+++ b/tools/perf/util/types.h
@@ -0,0 +1,17 @@
1#ifndef _PERF_TYPES_H
2#define _PERF_TYPES_H
3
4/*
5 * We define u64 as unsigned long long for every architecture
6 * so that we can print it with %Lx without getting warnings.
7 */
8typedef unsigned long long u64;
9typedef signed long long s64;
10typedef unsigned int u32;
11typedef signed int s32;
12typedef unsigned short u16;
13typedef signed short s16;
14typedef unsigned char u8;
15typedef signed char s8;
16
17#endif /* _PERF_TYPES_H */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 76590a16c271..68fe157d72fb 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -50,6 +50,7 @@
50#include <unistd.h> 50#include <unistd.h>
51#include <stdio.h> 51#include <stdio.h>
52#include <sys/stat.h> 52#include <sys/stat.h>
53#include <sys/statfs.h>
53#include <fcntl.h> 54#include <fcntl.h>
54#include <stddef.h> 55#include <stddef.h>
55#include <stdlib.h> 56#include <stdlib.h>
@@ -67,7 +68,6 @@
67#include <assert.h> 68#include <assert.h>
68#include <regex.h> 69#include <regex.h>
69#include <utime.h> 70#include <utime.h>
70#ifndef __MINGW32__
71#include <sys/wait.h> 71#include <sys/wait.h>
72#include <sys/poll.h> 72#include <sys/poll.h>
73#include <sys/socket.h> 73#include <sys/socket.h>
@@ -81,30 +81,12 @@
81#include <netdb.h> 81#include <netdb.h>
82#include <pwd.h> 82#include <pwd.h>
83#include <inttypes.h> 83#include <inttypes.h>
84#if defined(__CYGWIN__) 84#include "../../../include/linux/magic.h"
85#undef _XOPEN_SOURCE
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 85
99#ifndef NO_ICONV 86#ifndef NO_ICONV
100#include <iconv.h> 87#include <iconv.h>
101#endif 88#endif
102 89
103#ifndef NO_OPENSSL
104#include <openssl/ssl.h>
105#include <openssl/err.h>
106#endif
107
108/* On most systems <limits.h> would have given us this, but 90/* On most systems <limits.h> would have given us this, but
109 * not on some systems (e.g. GNU/Hurd). 91 * not on some systems (e.g. GNU/Hurd).
110 */ 92 */
@@ -332,17 +314,20 @@ static inline int has_extension(const char *filename, const char *ext)
332#undef tolower 314#undef tolower
333#undef toupper 315#undef toupper
334extern unsigned char sane_ctype[256]; 316extern unsigned char sane_ctype[256];
335#define GIT_SPACE 0x01 317#define GIT_SPACE 0x01
336#define GIT_DIGIT 0x02 318#define GIT_DIGIT 0x02
337#define GIT_ALPHA 0x04 319#define GIT_ALPHA 0x04
338#define GIT_GLOB_SPECIAL 0x08 320#define GIT_GLOB_SPECIAL 0x08
339#define GIT_REGEX_SPECIAL 0x10 321#define GIT_REGEX_SPECIAL 0x10
322#define GIT_PRINT_EXTRA 0x20
323#define GIT_PRINT 0x3E
340#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0) 324#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
341#define isascii(x) (((x) & ~0x7f) == 0) 325#define isascii(x) (((x) & ~0x7f) == 0)
342#define isspace(x) sane_istest(x,GIT_SPACE) 326#define isspace(x) sane_istest(x,GIT_SPACE)
343#define isdigit(x) sane_istest(x,GIT_DIGIT) 327#define isdigit(x) sane_istest(x,GIT_DIGIT)
344#define isalpha(x) sane_istest(x,GIT_ALPHA) 328#define isalpha(x) sane_istest(x,GIT_ALPHA)
345#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 329#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
330#define isprint(x) sane_istest(x,GIT_PRINT)
346#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL) 331#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
347#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL) 332#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
348#define tolower(x) sane_case((unsigned char)(x), 0x20) 333#define tolower(x) sane_case((unsigned char)(x), 0x20)
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)