aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/Makefile2
-rw-r--r--tools/perf/Documentation/examples.txt225
-rw-r--r--tools/perf/Documentation/perf-record.txt60
-rw-r--r--tools/perf/Documentation/perf-report.txt15
-rw-r--r--tools/perf/Documentation/perf-stat.txt2
-rw-r--r--tools/perf/Documentation/perf-top.txt112
-rw-r--r--tools/perf/Makefile40
-rw-r--r--tools/perf/builtin-annotate.c38
-rw-r--r--tools/perf/builtin-list.c3
-rw-r--r--tools/perf/builtin-record.c121
-rw-r--r--tools/perf/builtin-report.c399
-rw-r--r--tools/perf/builtin-stat.c5
-rw-r--r--tools/perf/builtin-top.c559
-rw-r--r--tools/perf/perf.c77
-rw-r--r--tools/perf/perf.h8
-rw-r--r--tools/perf/util/cache.h1
-rw-r--r--tools/perf/util/callchain.c32
-rw-r--r--tools/perf/util/callchain.h8
-rw-r--r--tools/perf/util/header.c5
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/include/linux/kernel.h8
-rw-r--r--tools/perf/util/parse-events.c216
-rw-r--r--tools/perf/util/parse-events.h6
-rw-r--r--tools/perf/util/quote.c2
-rw-r--r--tools/perf/util/string.h3
-rw-r--r--tools/perf/util/strlist.c20
-rw-r--r--tools/perf/util/strlist.h11
-rw-r--r--tools/perf/util/symbol.c268
-rw-r--r--tools/perf/util/symbol.h27
-rw-r--r--tools/perf/util/util.h2
30 files changed, 1955 insertions, 322 deletions
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index 5457192e1b41..bdd3b7ecad0a 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -35,7 +35,7 @@ man7dir=$(mandir)/man7
35# DESTDIR= 35# DESTDIR=
36 36
37ASCIIDOC=asciidoc 37ASCIIDOC=asciidoc
38ASCIIDOC_EXTRA = 38ASCIIDOC_EXTRA = --unsafe
39MANPAGE_XSL = manpage-normal.xsl 39MANPAGE_XSL = manpage-normal.xsl
40XMLTO_EXTRA = 40XMLTO_EXTRA =
41INSTALL?=install 41INSTALL?=install
diff --git a/tools/perf/Documentation/examples.txt b/tools/perf/Documentation/examples.txt
new file mode 100644
index 000000000000..8eb6c489fb15
--- /dev/null
+++ b/tools/perf/Documentation/examples.txt
@@ -0,0 +1,225 @@
1
2 ------------------------------
3 ****** perf by examples ******
4 ------------------------------
5
6[ From an e-mail by Ingo Molnar, http://lkml.org/lkml/2009/8/4/346 ]
7
8
9First, discovery/enumeration of available counters can be done via
10'perf list':
11
12titan:~> perf list
13 [...]
14 kmem:kmalloc [Tracepoint event]
15 kmem:kmem_cache_alloc [Tracepoint event]
16 kmem:kmalloc_node [Tracepoint event]
17 kmem:kmem_cache_alloc_node [Tracepoint event]
18 kmem:kfree [Tracepoint event]
19 kmem:kmem_cache_free [Tracepoint event]
20 kmem:mm_page_free_direct [Tracepoint event]
21 kmem:mm_pagevec_free [Tracepoint event]
22 kmem:mm_page_alloc [Tracepoint event]
23 kmem:mm_page_alloc_zone_locked [Tracepoint event]
24 kmem:mm_page_pcpu_drain [Tracepoint event]
25 kmem:mm_page_alloc_extfrag [Tracepoint event]
26
27Then any (or all) of the above event sources can be activated and
28measured. For example the page alloc/free properties of a 'hackbench
29run' are:
30
31 titan:~> perf stat -e kmem:mm_page_pcpu_drain -e kmem:mm_page_alloc
32 -e kmem:mm_pagevec_free -e kmem:mm_page_free_direct ./hackbench 10
33 Time: 0.575
34
35 Performance counter stats for './hackbench 10':
36
37 13857 kmem:mm_page_pcpu_drain
38 27576 kmem:mm_page_alloc
39 6025 kmem:mm_pagevec_free
40 20934 kmem:mm_page_free_direct
41
42 0.613972165 seconds time elapsed
43
44You can observe the statistical properties as well, by using the
45'repeat the workload N times' feature of perf stat:
46
47 titan:~> perf stat --repeat 5 -e kmem:mm_page_pcpu_drain -e
48 kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
49 kmem:mm_page_free_direct ./hackbench 10
50 Time: 0.627
51 Time: 0.644
52 Time: 0.564
53 Time: 0.559
54 Time: 0.626
55
56 Performance counter stats for './hackbench 10' (5 runs):
57
58 12920 kmem:mm_page_pcpu_drain ( +- 3.359% )
59 25035 kmem:mm_page_alloc ( +- 3.783% )
60 6104 kmem:mm_pagevec_free ( +- 0.934% )
61 18376 kmem:mm_page_free_direct ( +- 4.941% )
62
63 0.643954516 seconds time elapsed ( +- 2.363% )
64
65Furthermore, these tracepoints can be used to sample the workload as
66well. For example the page allocations done by a 'git gc' can be
67captured the following way:
68
69 titan:~/git> perf record -f -e kmem:mm_page_alloc -c 1 ./git gc
70 Counting objects: 1148, done.
71 Delta compression using up to 2 threads.
72 Compressing objects: 100% (450/450), done.
73 Writing objects: 100% (1148/1148), done.
74 Total 1148 (delta 690), reused 1148 (delta 690)
75 [ perf record: Captured and wrote 0.267 MB perf.data (~11679 samples) ]
76
77To check which functions generated page allocations:
78
79 titan:~/git> perf report
80 # Samples: 10646
81 #
82 # Overhead Command Shared Object
83 # ........ ............... ..........................
84 #
85 23.57% git-repack /lib64/libc-2.5.so
86 21.81% git /lib64/libc-2.5.so
87 14.59% git ./git
88 11.79% git-repack ./git
89 7.12% git /lib64/ld-2.5.so
90 3.16% git-repack /lib64/libpthread-2.5.so
91 2.09% git-repack /bin/bash
92 1.97% rm /lib64/libc-2.5.so
93 1.39% mv /lib64/ld-2.5.so
94 1.37% mv /lib64/libc-2.5.so
95 1.12% git-repack /lib64/ld-2.5.so
96 0.95% rm /lib64/ld-2.5.so
97 0.90% git-update-serv /lib64/libc-2.5.so
98 0.73% git-update-serv /lib64/ld-2.5.so
99 0.68% perf /lib64/libpthread-2.5.so
100 0.64% git-repack /usr/lib64/libz.so.1.2.3
101
102Or to see it on a more finegrained level:
103
104titan:~/git> perf report --sort comm,dso,symbol
105# Samples: 10646
106#
107# Overhead Command Shared Object Symbol
108# ........ ............... .......................... ......
109#
110 9.35% git-repack ./git [.] insert_obj_hash
111 9.12% git ./git [.] insert_obj_hash
112 7.31% git /lib64/libc-2.5.so [.] memcpy
113 6.34% git-repack /lib64/libc-2.5.so [.] _int_malloc
114 6.24% git-repack /lib64/libc-2.5.so [.] memcpy
115 5.82% git-repack /lib64/libc-2.5.so [.] __GI___fork
116 5.47% git /lib64/libc-2.5.so [.] _int_malloc
117 2.99% git /lib64/libc-2.5.so [.] memset
118
119Furthermore, call-graph sampling can be done too, of page
120allocations - to see precisely what kind of page allocations there
121are:
122
123 titan:~/git> perf record -f -g -e kmem:mm_page_alloc -c 1 ./git gc
124 Counting objects: 1148, done.
125 Delta compression using up to 2 threads.
126 Compressing objects: 100% (450/450), done.
127 Writing objects: 100% (1148/1148), done.
128 Total 1148 (delta 690), reused 1148 (delta 690)
129 [ perf record: Captured and wrote 0.963 MB perf.data (~42069 samples) ]
130
131 titan:~/git> perf report -g
132 # Samples: 10686
133 #
134 # Overhead Command Shared Object
135 # ........ ............... ..........................
136 #
137 23.25% git-repack /lib64/libc-2.5.so
138 |
139 |--50.00%-- _int_free
140 |
141 |--37.50%-- __GI___fork
142 | make_child
143 |
144 |--12.50%-- ptmalloc_unlock_all2
145 | make_child
146 |
147 --6.25%-- __GI_strcpy
148 21.61% git /lib64/libc-2.5.so
149 |
150 |--30.00%-- __GI_read
151 | |
152 | --83.33%-- git_config_from_file
153 | git_config
154 | |
155 [...]
156
157Or you can observe the whole system's page allocations for 10
158seconds:
159
160titan:~/git> perf stat -a -e kmem:mm_page_pcpu_drain -e
161kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
162kmem:mm_page_free_direct sleep 10
163
164 Performance counter stats for 'sleep 10':
165
166 171585 kmem:mm_page_pcpu_drain
167 322114 kmem:mm_page_alloc
168 73623 kmem:mm_pagevec_free
169 254115 kmem:mm_page_free_direct
170
171 10.000591410 seconds time elapsed
172
173Or observe how fluctuating the page allocations are, via statistical
174analysis done over ten 1-second intervals:
175
176 titan:~/git> perf stat --repeat 10 -a -e kmem:mm_page_pcpu_drain -e
177 kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
178 kmem:mm_page_free_direct sleep 1
179
180 Performance counter stats for 'sleep 1' (10 runs):
181
182 17254 kmem:mm_page_pcpu_drain ( +- 3.709% )
183 34394 kmem:mm_page_alloc ( +- 4.617% )
184 7509 kmem:mm_pagevec_free ( +- 4.820% )
185 25653 kmem:mm_page_free_direct ( +- 3.672% )
186
187 1.058135029 seconds time elapsed ( +- 3.089% )
188
189Or you can annotate the recorded 'git gc' run on a per symbol basis
190and check which instructions/source-code generated page allocations:
191
192 titan:~/git> perf annotate __GI___fork
193 ------------------------------------------------
194 Percent | Source code & Disassembly of libc-2.5.so
195 ------------------------------------------------
196 :
197 :
198 : Disassembly of section .plt:
199 : Disassembly of section .text:
200 :
201 : 00000031a2e95560 <__fork>:
202 [...]
203 0.00 : 31a2e95602: b8 38 00 00 00 mov $0x38,%eax
204 0.00 : 31a2e95607: 0f 05 syscall
205 83.42 : 31a2e95609: 48 3d 00 f0 ff ff cmp $0xfffffffffffff000,%rax
206 0.00 : 31a2e9560f: 0f 87 4d 01 00 00 ja 31a2e95762 <__fork+0x202>
207 0.00 : 31a2e95615: 85 c0 test %eax,%eax
208
209( this shows that 83.42% of __GI___fork's page allocations come from
210 the 0x38 system call it performs. )
211
212etc. etc. - a lot more is possible. I could list a dozen of
213other different usecases straight away - neither of which is
214possible via /proc/vmstat.
215
216/proc/vmstat is not in the same league really, in terms of
217expressive power of system analysis and performance
218analysis.
219
220All that the above results needed were those new tracepoints
221in include/tracing/events/kmem.h.
222
223 Ingo
224
225
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 1dbc1eeb4c01..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 8aa3f8c88707..e72e93110782 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -24,6 +24,9 @@ OPTIONS
24--dsos=:: 24--dsos=::
25 Only consider symbols in these dsos. CSV that understands 25 Only consider symbols in these dsos. CSV that understands
26 file://filename entries. 26 file://filename entries.
27-n
28--show-nr-samples
29 Show the number of samples for each symbol
27-C:: 30-C::
28--comms=:: 31--comms=::
29 Only consider symbols in these comms. CSV that understands 32 Only consider symbols in these comms. CSV that understands
@@ -33,6 +36,18 @@ OPTIONS
33 Only consider these symbols. CSV that understands 36 Only consider these symbols. CSV that understands
34 file://filename entries. 37 file://filename entries.
35 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.
50
36SEE ALSO 51SEE ALSO
37-------- 52--------
38linkperf:perf-stat[1] 53linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 0d74346d21ab..484080dd5b6f 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -40,7 +40,7 @@ OPTIONS
40-a:: 40-a::
41 system-wide collection 41 system-wide collection
42 42
43-S:: 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 7822b3d6baca..c045b4271e57 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -158,8 +158,10 @@ uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
158uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') 158uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
159 159
160# If we're on a 64-bit kernel, use -m64 160# If we're on a 64-bit kernel, use -m64
161ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) 161ifndef NO_64BIT
162 M64 := -m64 162 ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
163 M64 := -m64
164 endif
163endif 165endif
164 166
165# CFLAGS and LDFLAGS are for the users to override from the command line. 167# CFLAGS and LDFLAGS are for the users to override from the command line.
@@ -345,7 +347,6 @@ BUILTIN_OBJS += builtin-stat.o
345BUILTIN_OBJS += builtin-top.o 347BUILTIN_OBJS += builtin-top.o
346 348
347PERFLIBS = $(LIB_FILE) 349PERFLIBS = $(LIB_FILE)
348EXTLIBS =
349 350
350# 351#
351# Platform specific tweaks 352# Platform specific tweaks
@@ -374,6 +375,39 @@ ifeq ($(uname_S),Darwin)
374 PTHREAD_LIBS = 375 PTHREAD_LIBS =
375endif 376endif
376 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 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")
386
387 ifeq ($(has_bfd),y)
388 EXTLIBS += -lbfd
389 else
390 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")
391 ifeq ($(has_bfd_iberty),y)
392 EXTLIBS += -lbfd -liberty
393 else
394 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")
395 ifeq ($(has_bfd_iberty_z),y)
396 EXTLIBS += -lbfd -liberty -lz
397 else
398 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -liberty > /dev/null 2>&1 && echo y")
399 ifeq ($(has_cplus_demangle),y)
400 EXTLIBS += -liberty
401 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
402 else
403 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling)
404 BASIC_CFLAGS += -DNO_DEMANGLE
405 endif
406 endif
407 endif
408 endif
409endif
410
377ifndef CC_LD_DYNPATH 411ifndef CC_LD_DYNPATH
378 ifdef NO_R_TO_GCC_LINKER 412 ifdef NO_R_TO_GCC_LINKER
379 # Some gcc does not accept and pass -R to the linker to specify 413 # Some gcc does not accept and pass -R to the linker to specify
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 5f9eefecc574..5e17de984dc8 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -31,6 +31,7 @@ static char *vmlinux = "vmlinux";
31static char default_sort_order[] = "comm,symbol"; 31static char default_sort_order[] = "comm,symbol";
32static char *sort_order = default_sort_order; 32static char *sort_order = default_sort_order;
33 33
34static int force;
34static int input; 35static int input;
35static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 36static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
36 37
@@ -74,20 +75,12 @@ struct fork_event {
74 u32 pid, ppid; 75 u32 pid, ppid;
75}; 76};
76 77
77struct period_event {
78 struct perf_event_header header;
79 u64 time;
80 u64 id;
81 u64 sample_period;
82};
83
84typedef union event_union { 78typedef union event_union {
85 struct perf_event_header header; 79 struct perf_event_header header;
86 struct ip_event ip; 80 struct ip_event ip;
87 struct mmap_event mmap; 81 struct mmap_event mmap;
88 struct comm_event comm; 82 struct comm_event comm;
89 struct fork_event fork; 83 struct fork_event fork;
90 struct period_event period;
91} event_t; 84} event_t;
92 85
93 86
@@ -988,6 +981,13 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
988 (void *)(long)(event->header.size), 981 (void *)(long)(event->header.size),
989 event->fork.pid, event->fork.ppid); 982 event->fork.pid, event->fork.ppid);
990 983
984 /*
985 * A thread clone will have the same PID for both
986 * parent and child.
987 */
988 if (thread == parent)
989 return 0;
990
991 if (!thread || !parent || thread__fork(thread, parent)) { 991 if (!thread || !parent || thread__fork(thread, parent)) {
992 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 992 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
993 return -1; 993 return -1;
@@ -998,19 +998,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
998} 998}
999 999
1000static int 1000static int
1001process_period_event(event_t *event, unsigned long offset, unsigned long head)
1002{
1003 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
1004 (void *)(offset + head),
1005 (void *)(long)(event->header.size),
1006 event->period.time,
1007 event->period.id,
1008 event->period.sample_period);
1009
1010 return 0;
1011}
1012
1013static int
1014process_event(event_t *event, unsigned long offset, unsigned long head) 1001process_event(event_t *event, unsigned long offset, unsigned long head)
1015{ 1002{
1016 switch (event->header.type) { 1003 switch (event->header.type) {
@@ -1025,9 +1012,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1025 1012
1026 case PERF_EVENT_FORK: 1013 case PERF_EVENT_FORK:
1027 return process_fork_event(event, offset, head); 1014 return process_fork_event(event, offset, head);
1028
1029 case PERF_EVENT_PERIOD:
1030 return process_period_event(event, offset, head);
1031 /* 1015 /*
1032 * We dont process them right now but they are fine: 1016 * We dont process them right now but they are fine:
1033 */ 1017 */
@@ -1351,6 +1335,11 @@ static int __cmd_annotate(void)
1351 exit(-1); 1335 exit(-1);
1352 } 1336 }
1353 1337
1338 if (!force && (stat.st_uid != geteuid())) {
1339 fprintf(stderr, "file: %s not owned by current user\n", input_name);
1340 exit(-1);
1341 }
1342
1354 if (!stat.st_size) { 1343 if (!stat.st_size) {
1355 fprintf(stderr, "zero-sized file, nothing to do!\n"); 1344 fprintf(stderr, "zero-sized file, nothing to do!\n");
1356 exit(0); 1345 exit(0);
@@ -1456,6 +1445,7 @@ static const struct option options[] = {
1456 "input file name"), 1445 "input file name"),
1457 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", 1446 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
1458 "symbol to annotate"), 1447 "symbol to annotate"),
1448 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1459 OPT_BOOLEAN('v', "verbose", &verbose, 1449 OPT_BOOLEAN('v', "verbose", &verbose,
1460 "be more verbose (show symbol address, etc)"), 1450 "be more verbose (show symbol address, etc)"),
1461 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1451 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index f990fa8a35c9..d88c6961274c 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -10,11 +10,12 @@
10 10
11#include "perf.h" 11#include "perf.h"
12 12
13#include "util/parse-options.h"
14#include "util/parse-events.h" 13#include "util/parse-events.h"
14#include "util/cache.h"
15 15
16int cmd_list(int argc __used, const char **argv __used, const char *prefix __used) 16int cmd_list(int argc __used, const char **argv __used, const char *prefix __used)
17{ 17{
18 setup_pager();
18 print_events(); 19 print_events();
19 return 0; 20 return 0;
20} 21}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4ef78a5e6f32..89a5ddcd1ded 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -34,7 +34,9 @@ static int output;
34static const char *output_name = "perf.data"; 34static const char *output_name = "perf.data";
35static int group = 0; 35static int group = 0;
36static unsigned int realtime_prio = 0; 36static unsigned int realtime_prio = 0;
37static int raw_samples = 0;
37static int system_wide = 0; 38static int system_wide = 0;
39static int profile_cpu = -1;
38static pid_t target_pid = -1; 40static pid_t target_pid = -1;
39static int inherit = 1; 41static int inherit = 1;
40static int force = 0; 42static int force = 0;
@@ -43,6 +45,7 @@ static int call_graph = 0;
43static int verbose = 0; 45static int verbose = 0;
44static int inherit_stat = 0; 46static int inherit_stat = 0;
45static int no_samples = 0; 47static int no_samples = 0;
48static int sample_address = 0;
46 49
47static long samples; 50static long samples;
48static struct timeval last_read; 51static struct timeval last_read;
@@ -202,46 +205,48 @@ static void sig_atexit(void)
202 kill(getpid(), signr); 205 kill(getpid(), signr);
203} 206}
204 207
205static void pid_synthesize_comm_event(pid_t pid, int full) 208static pid_t pid_synthesize_comm_event(pid_t pid, int full)
206{ 209{
207 struct comm_event comm_ev; 210 struct comm_event comm_ev;
208 char filename[PATH_MAX]; 211 char filename[PATH_MAX];
209 char bf[BUFSIZ]; 212 char bf[BUFSIZ];
210 int fd; 213 FILE *fp;
211 size_t size; 214 size_t size = 0;
212 char *field, *sep;
213 DIR *tasks; 215 DIR *tasks;
214 struct dirent dirent, *next; 216 struct dirent dirent, *next;
217 pid_t tgid = 0;
215 218
216 snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); 219 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
217 220
218 fd = open(filename, O_RDONLY); 221 fp = fopen(filename, "r");
219 if (fd < 0) { 222 if (fp == NULL) {
220 /* 223 /*
221 * We raced with a task exiting - just return: 224 * We raced with a task exiting - just return:
222 */ 225 */
223 if (verbose) 226 if (verbose)
224 fprintf(stderr, "couldn't open %s\n", filename); 227 fprintf(stderr, "couldn't open %s\n", filename);
225 return; 228 return 0;
226 }
227 if (read(fd, bf, sizeof(bf)) < 0) {
228 fprintf(stderr, "couldn't read %s\n", filename);
229 exit(EXIT_FAILURE);
230 } 229 }
231 close(fd);
232 230
233 /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */
234 memset(&comm_ev, 0, sizeof(comm_ev)); 231 memset(&comm_ev, 0, sizeof(comm_ev));
235 field = strchr(bf, '('); 232 while (!comm_ev.comm[0] || !comm_ev.pid) {
236 if (field == NULL) 233 if (fgets(bf, sizeof(bf), fp) == NULL)
237 goto out_failure; 234 goto out_failure;
238 sep = strchr(++field, ')'); 235
239 if (sep == NULL) 236 if (memcmp(bf, "Name:", 5) == 0) {
240 goto out_failure; 237 char *name = bf + 5;
241 size = sep - field; 238 while (*name && isspace(*name))
242 memcpy(comm_ev.comm, field, size++); 239 ++name;
243 240 size = strlen(name) - 1;
244 comm_ev.pid = pid; 241 memcpy(comm_ev.comm, name, size++);
242 } else if (memcmp(bf, "Tgid:", 5) == 0) {
243 char *tgids = bf + 5;
244 while (*tgids && isspace(*tgids))
245 ++tgids;
246 tgid = comm_ev.pid = atoi(tgids);
247 }
248 }
249
245 comm_ev.header.type = PERF_EVENT_COMM; 250 comm_ev.header.type = PERF_EVENT_COMM;
246 size = ALIGN(size, sizeof(u64)); 251 size = ALIGN(size, sizeof(u64));
247 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); 252 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
@@ -250,7 +255,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
250 comm_ev.tid = pid; 255 comm_ev.tid = pid;
251 256
252 write_output(&comm_ev, comm_ev.header.size); 257 write_output(&comm_ev, comm_ev.header.size);
253 return; 258 goto out_fclose;
254 } 259 }
255 260
256 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 261 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
@@ -267,7 +272,10 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
267 write_output(&comm_ev, comm_ev.header.size); 272 write_output(&comm_ev, comm_ev.header.size);
268 } 273 }
269 closedir(tasks); 274 closedir(tasks);
270 return; 275
276out_fclose:
277 fclose(fp);
278 return tgid;
271 279
272out_failure: 280out_failure:
273 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", 281 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
@@ -275,7 +283,7 @@ out_failure:
275 exit(EXIT_FAILURE); 283 exit(EXIT_FAILURE);
276} 284}
277 285
278static void pid_synthesize_mmap_samples(pid_t pid) 286static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
279{ 287{
280 char filename[PATH_MAX]; 288 char filename[PATH_MAX];
281 FILE *fp; 289 FILE *fp;
@@ -313,6 +321,10 @@ static void pid_synthesize_mmap_samples(pid_t pid)
313 if (*pbf == 'x') { /* vm_exec */ 321 if (*pbf == 'x') { /* vm_exec */
314 char *execname = strchr(bf, '/'); 322 char *execname = strchr(bf, '/');
315 323
324 /* Catch VDSO */
325 if (execname == NULL)
326 execname = strstr(bf, "[vdso]");
327
316 if (execname == NULL) 328 if (execname == NULL)
317 continue; 329 continue;
318 330
@@ -323,7 +335,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
323 mmap_ev.len -= mmap_ev.start; 335 mmap_ev.len -= mmap_ev.start;
324 mmap_ev.header.size = (sizeof(mmap_ev) - 336 mmap_ev.header.size = (sizeof(mmap_ev) -
325 (sizeof(mmap_ev.filename) - size)); 337 (sizeof(mmap_ev.filename) - size));
326 mmap_ev.pid = pid; 338 mmap_ev.pid = tgid;
327 mmap_ev.tid = pid; 339 mmap_ev.tid = pid;
328 340
329 write_output(&mmap_ev, mmap_ev.header.size); 341 write_output(&mmap_ev, mmap_ev.header.size);
@@ -342,14 +354,14 @@ static void synthesize_all(void)
342 354
343 while (!readdir_r(proc, &dirent, &next) && next) { 355 while (!readdir_r(proc, &dirent, &next) && next) {
344 char *end; 356 char *end;
345 pid_t pid; 357 pid_t pid, tgid;
346 358
347 pid = strtol(dirent.d_name, &end, 10); 359 pid = strtol(dirent.d_name, &end, 10);
348 if (*end) /* only interested in proper numerical dirents */ 360 if (*end) /* only interested in proper numerical dirents */
349 continue; 361 continue;
350 362
351 pid_synthesize_comm_event(pid, 1); 363 tgid = pid_synthesize_comm_event(pid, 1);
352 pid_synthesize_mmap_samples(pid); 364 pid_synthesize_mmap_samples(pid, tgid);
353 } 365 }
354 366
355 closedir(proc); 367 closedir(proc);
@@ -387,7 +399,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
387 PERF_FORMAT_TOTAL_TIME_RUNNING | 399 PERF_FORMAT_TOTAL_TIME_RUNNING |
388 PERF_FORMAT_ID; 400 PERF_FORMAT_ID;
389 401
390 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 402 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
391 403
392 if (freq) { 404 if (freq) {
393 attr->sample_type |= PERF_SAMPLE_PERIOD; 405 attr->sample_type |= PERF_SAMPLE_PERIOD;
@@ -401,9 +413,15 @@ static void create_counter(int counter, int cpu, pid_t pid)
401 if (inherit_stat) 413 if (inherit_stat)
402 attr->inherit_stat = 1; 414 attr->inherit_stat = 1;
403 415
416 if (sample_address)
417 attr->sample_type |= PERF_SAMPLE_ADDR;
418
404 if (call_graph) 419 if (call_graph)
405 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 420 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
406 421
422 if (raw_samples)
423 attr->sample_type |= PERF_SAMPLE_RAW;
424
407 attr->mmap = track; 425 attr->mmap = track;
408 attr->comm = track; 426 attr->comm = track;
409 attr->inherit = (cpu < 0) && inherit; 427 attr->inherit = (cpu < 0) && inherit;
@@ -417,6 +435,8 @@ try_again:
417 435
418 if (err == EPERM) 436 if (err == EPERM)
419 die("Permission error - are you root?\n"); 437 die("Permission error - are you root?\n");
438 else if (err == ENODEV && profile_cpu != -1)
439 die("No such device - did you specify an out-of-range profile CPU?\n");
420 440
421 /* 441 /*
422 * If it's cycles then fall back to hrtimer 442 * If it's cycles then fall back to hrtimer
@@ -516,10 +536,14 @@ static int __cmd_record(int argc, const char **argv)
516 signal(SIGCHLD, sig_handler); 536 signal(SIGCHLD, sig_handler);
517 signal(SIGINT, sig_handler); 537 signal(SIGINT, sig_handler);
518 538
519 if (!stat(output_name, &st) && !force && !append_file) { 539 if (!stat(output_name, &st) && st.st_size) {
520 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 540 if (!force && !append_file) {
521 output_name); 541 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
522 exit(-1); 542 output_name);
543 exit(-1);
544 }
545 } else {
546 append_file = 0;
523 } 547 }
524 548
525 flags = O_CREAT|O_RDWR; 549 flags = O_CREAT|O_RDWR;
@@ -546,16 +570,22 @@ static int __cmd_record(int argc, const char **argv)
546 if (pid == -1) 570 if (pid == -1)
547 pid = getpid(); 571 pid = getpid();
548 572
549 open_counters(-1, pid); 573 open_counters(profile_cpu, pid);
550 } else for (i = 0; i < nr_cpus; i++) 574 } else {
551 open_counters(i, target_pid); 575 if (profile_cpu != -1) {
576 open_counters(profile_cpu, target_pid);
577 } else {
578 for (i = 0; i < nr_cpus; i++)
579 open_counters(i, target_pid);
580 }
581 }
552 582
553 if (file_new) 583 if (file_new)
554 perf_header__write(header, output); 584 perf_header__write(header, output);
555 585
556 if (!system_wide) { 586 if (!system_wide) {
557 pid_synthesize_comm_event(pid, 0); 587 pid_t tgid = pid_synthesize_comm_event(pid, 0);
558 pid_synthesize_mmap_samples(pid); 588 pid_synthesize_mmap_samples(pid, tgid);
559 } else 589 } else
560 synthesize_all(); 590 synthesize_all();
561 591
@@ -623,10 +653,14 @@ static const struct option options[] = {
623 "record events on existing pid"), 653 "record events on existing pid"),
624 OPT_INTEGER('r', "realtime", &realtime_prio, 654 OPT_INTEGER('r', "realtime", &realtime_prio,
625 "collect data with this RT SCHED_FIFO priority"), 655 "collect data with this RT SCHED_FIFO priority"),
656 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
657 "collect raw sample records from all opened counters"),
626 OPT_BOOLEAN('a', "all-cpus", &system_wide, 658 OPT_BOOLEAN('a', "all-cpus", &system_wide,
627 "system-wide collection from all CPUs"), 659 "system-wide collection from all CPUs"),
628 OPT_BOOLEAN('A', "append", &append_file, 660 OPT_BOOLEAN('A', "append", &append_file,
629 "append to the output file to do incremental profiling"), 661 "append to the output file to do incremental profiling"),
662 OPT_INTEGER('C', "profile_cpu", &profile_cpu,
663 "CPU to profile on"),
630 OPT_BOOLEAN('f', "force", &force, 664 OPT_BOOLEAN('f', "force", &force,
631 "overwrite existing data file"), 665 "overwrite existing data file"),
632 OPT_LONG('c', "count", &default_interval, 666 OPT_LONG('c', "count", &default_interval,
@@ -645,6 +679,8 @@ static const struct option options[] = {
645 "be more verbose (show counter open errors, etc)"), 679 "be more verbose (show counter open errors, etc)"),
646 OPT_BOOLEAN('s', "stat", &inherit_stat, 680 OPT_BOOLEAN('s', "stat", &inherit_stat,
647 "per thread counts"), 681 "per thread counts"),
682 OPT_BOOLEAN('d', "data", &sample_address,
683 "Sample addresses"),
648 OPT_BOOLEAN('n', "no-samples", &no_samples, 684 OPT_BOOLEAN('n', "no-samples", &no_samples,
649 "don't sample"), 685 "don't sample"),
650 OPT_END() 686 OPT_END()
@@ -654,7 +690,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
654{ 690{
655 int counter; 691 int counter;
656 692
657 argc = parse_options(argc, argv, options, record_usage, 0); 693 argc = parse_options(argc, argv, options, record_usage,
694 PARSE_OPT_STOP_AT_NON_OPTION);
658 if (!argc && target_pid == -1 && !system_wide) 695 if (!argc && target_pid == -1 && !system_wide)
659 usage_with_options(record_usage, options); 696 usage_with_options(record_usage, options);
660 697
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4e5cc266311e..8b2ec882e6e0 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -31,11 +31,14 @@
31static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
32static char *vmlinux = NULL; 32static char *vmlinux = NULL;
33 33
34static char default_sort_order[] = "comm,dso"; 34static char default_sort_order[] = "comm,dso,symbol";
35static char *sort_order = default_sort_order; 35static char *sort_order = default_sort_order;
36static char *dso_list_str, *comm_list_str, *sym_list_str; 36static char *dso_list_str, *comm_list_str, *sym_list_str,
37 *col_width_list_str;
37static struct strlist *dso_list, *comm_list, *sym_list; 38static struct strlist *dso_list, *comm_list, *sym_list;
39static char *field_sep;
38 40
41static int force;
39static int input; 42static int input;
40static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 43static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
41 44
@@ -49,6 +52,7 @@ static int verbose;
49static int modules; 52static int modules;
50 53
51static int full_paths; 54static int full_paths;
55static int show_nr_samples;
52 56
53static unsigned long page_size; 57static unsigned long page_size;
54static unsigned long mmap_window = 32; 58static unsigned long mmap_window = 32;
@@ -65,7 +69,7 @@ static int callchain;
65 69
66static 70static
67struct callchain_param callchain_param = { 71struct callchain_param callchain_param = {
68 .mode = CHAIN_GRAPH_ABS, 72 .mode = CHAIN_GRAPH_REL,
69 .min_percent = 0.5 73 .min_percent = 0.5
70}; 74};
71 75
@@ -96,13 +100,7 @@ struct comm_event {
96struct fork_event { 100struct fork_event {
97 struct perf_event_header header; 101 struct perf_event_header header;
98 u32 pid, ppid; 102 u32 pid, ppid;
99}; 103 u32 tid, ptid;
100
101struct period_event {
102 struct perf_event_header header;
103 u64 time;
104 u64 id;
105 u64 sample_period;
106}; 104};
107 105
108struct lost_event { 106struct lost_event {
@@ -115,7 +113,9 @@ struct read_event {
115 struct perf_event_header header; 113 struct perf_event_header header;
116 u32 pid,tid; 114 u32 pid,tid;
117 u64 value; 115 u64 value;
118 u64 format[3]; 116 u64 time_enabled;
117 u64 time_running;
118 u64 id;
119}; 119};
120 120
121typedef union event_union { 121typedef union event_union {
@@ -124,11 +124,37 @@ typedef union event_union {
124 struct mmap_event mmap; 124 struct mmap_event mmap;
125 struct comm_event comm; 125 struct comm_event comm;
126 struct fork_event fork; 126 struct fork_event fork;
127 struct period_event period;
128 struct lost_event lost; 127 struct lost_event lost;
129 struct read_event read; 128 struct read_event read;
130} event_t; 129} event_t;
131 130
131static int repsep_fprintf(FILE *fp, const char *fmt, ...)
132{
133 int n;
134 va_list ap;
135
136 va_start(ap, fmt);
137 if (!field_sep)
138 n = vfprintf(fp, fmt, ap);
139 else {
140 char *bf = NULL;
141 n = vasprintf(&bf, fmt, ap);
142 if (n > 0) {
143 char *sep = bf;
144 while (1) {
145 sep = strchr(sep, *field_sep);
146 if (sep == NULL)
147 break;
148 *sep = '.';
149 }
150 }
151 fputs(bf, fp);
152 free(bf);
153 }
154 va_end(ap);
155 return n;
156}
157
132static LIST_HEAD(dsos); 158static LIST_HEAD(dsos);
133static struct dso *kernel_dso; 159static struct dso *kernel_dso;
134static struct dso *vdso; 160static struct dso *vdso;
@@ -230,7 +256,7 @@ static int strcommon(const char *pathname)
230{ 256{
231 int n = 0; 257 int n = 0;
232 258
233 while (pathname[n] == cwd[n] && n < cwdlen) 259 while (n < cwdlen && pathname[n] == cwd[n])
234 ++n; 260 ++n;
235 261
236 return n; 262 return n;
@@ -360,12 +386,28 @@ static struct thread *thread__new(pid_t pid)
360 return self; 386 return self;
361} 387}
362 388
389static unsigned int dsos__col_width,
390 comms__col_width,
391 threads__col_width;
392
363static int thread__set_comm(struct thread *self, const char *comm) 393static int thread__set_comm(struct thread *self, const char *comm)
364{ 394{
365 if (self->comm) 395 if (self->comm)
366 free(self->comm); 396 free(self->comm);
367 self->comm = strdup(comm); 397 self->comm = strdup(comm);
368 return self->comm ? 0 : -ENOMEM; 398 if (!self->comm)
399 return -ENOMEM;
400
401 if (!col_width_list_str && !field_sep &&
402 (!comm_list || strlist__has_entry(comm_list, comm))) {
403 unsigned int slen = strlen(comm);
404 if (slen > comms__col_width) {
405 comms__col_width = slen;
406 threads__col_width = slen + 6;
407 }
408 }
409
410 return 0;
369} 411}
370 412
371static size_t thread__fprintf(struct thread *self, FILE *fp) 413static size_t thread__fprintf(struct thread *self, FILE *fp)
@@ -536,7 +578,9 @@ struct sort_entry {
536 578
537 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 579 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
538 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 580 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
539 size_t (*print)(FILE *fp, struct hist_entry *); 581 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
582 unsigned int *width;
583 bool elide;
540}; 584};
541 585
542static int64_t cmp_null(void *l, void *r) 586static int64_t cmp_null(void *l, void *r)
@@ -558,15 +602,17 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
558} 602}
559 603
560static size_t 604static size_t
561sort__thread_print(FILE *fp, struct hist_entry *self) 605sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
562{ 606{
563 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); 607 return repsep_fprintf(fp, "%*s:%5d", width - 6,
608 self->thread->comm ?: "", self->thread->pid);
564} 609}
565 610
566static struct sort_entry sort_thread = { 611static struct sort_entry sort_thread = {
567 .header = " Command: Pid", 612 .header = "Command: Pid",
568 .cmp = sort__thread_cmp, 613 .cmp = sort__thread_cmp,
569 .print = sort__thread_print, 614 .print = sort__thread_print,
615 .width = &threads__col_width,
570}; 616};
571 617
572/* --sort comm */ 618/* --sort comm */
@@ -590,16 +636,17 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
590} 636}
591 637
592static size_t 638static size_t
593sort__comm_print(FILE *fp, struct hist_entry *self) 639sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
594{ 640{
595 return fprintf(fp, "%16s", self->thread->comm); 641 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
596} 642}
597 643
598static struct sort_entry sort_comm = { 644static struct sort_entry sort_comm = {
599 .header = " Command", 645 .header = "Command",
600 .cmp = sort__comm_cmp, 646 .cmp = sort__comm_cmp,
601 .collapse = sort__comm_collapse, 647 .collapse = sort__comm_collapse,
602 .print = sort__comm_print, 648 .print = sort__comm_print,
649 .width = &comms__col_width,
603}; 650};
604 651
605/* --sort dso */ 652/* --sort dso */
@@ -617,18 +664,19 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
617} 664}
618 665
619static size_t 666static size_t
620sort__dso_print(FILE *fp, struct hist_entry *self) 667sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
621{ 668{
622 if (self->dso) 669 if (self->dso)
623 return fprintf(fp, "%-25s", self->dso->name); 670 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
624 671
625 return fprintf(fp, "%016llx ", (u64)self->ip); 672 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
626} 673}
627 674
628static struct sort_entry sort_dso = { 675static struct sort_entry sort_dso = {
629 .header = "Shared Object ", 676 .header = "Shared Object",
630 .cmp = sort__dso_cmp, 677 .cmp = sort__dso_cmp,
631 .print = sort__dso_print, 678 .print = sort__dso_print,
679 .width = &dsos__col_width,
632}; 680};
633 681
634/* --sort symbol */ 682/* --sort symbol */
@@ -648,22 +696,23 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
648} 696}
649 697
650static size_t 698static size_t
651sort__sym_print(FILE *fp, struct hist_entry *self) 699sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
652{ 700{
653 size_t ret = 0; 701 size_t ret = 0;
654 702
655 if (verbose) 703 if (verbose)
656 ret += fprintf(fp, "%#018llx ", (u64)self->ip); 704 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
705 dso__symtab_origin(self->dso));
657 706
707 ret += repsep_fprintf(fp, "[%c] ", self->level);
658 if (self->sym) { 708 if (self->sym) {
659 ret += fprintf(fp, "[%c] %s", 709 ret += repsep_fprintf(fp, "%s", self->sym->name);
660 self->dso == kernel_dso ? 'k' :
661 self->dso == hypervisor_dso ? 'h' : '.', self->sym->name);
662 710
663 if (self->sym->module) 711 if (self->sym->module)
664 ret += fprintf(fp, "\t[%s]", self->sym->module->name); 712 ret += repsep_fprintf(fp, "\t[%s]",
713 self->sym->module->name);
665 } else { 714 } else {
666 ret += fprintf(fp, "%#016llx", (u64)self->ip); 715 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
667 } 716 }
668 717
669 return ret; 718 return ret;
@@ -690,19 +739,19 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
690} 739}
691 740
692static size_t 741static size_t
693sort__parent_print(FILE *fp, struct hist_entry *self) 742sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
694{ 743{
695 size_t ret = 0; 744 return repsep_fprintf(fp, "%-*s", width,
696 745 self->parent ? self->parent->name : "[other]");
697 ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]");
698
699 return ret;
700} 746}
701 747
748static unsigned int parent_symbol__col_width;
749
702static struct sort_entry sort_parent = { 750static struct sort_entry sort_parent = {
703 .header = "Parent symbol ", 751 .header = "Parent symbol",
704 .cmp = sort__parent_cmp, 752 .cmp = sort__parent_cmp,
705 .print = sort__parent_print, 753 .print = sort__parent_print,
754 .width = &parent_symbol__col_width,
706}; 755};
707 756
708static int sort__need_collapse = 0; 757static int sort__need_collapse = 0;
@@ -843,6 +892,21 @@ ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
843 return ret; 892 return ret;
844} 893}
845 894
895static struct symbol *rem_sq_bracket;
896static struct callchain_list rem_hits;
897
898static void init_rem_hits(void)
899{
900 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
901 if (!rem_sq_bracket) {
902 fprintf(stderr, "Not enough memory to display remaining hits\n");
903 return;
904 }
905
906 strcpy(rem_sq_bracket->name, "[...]");
907 rem_hits.sym = rem_sq_bracket;
908}
909
846static size_t 910static size_t
847callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 911callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
848 u64 total_samples, int depth, int depth_mask) 912 u64 total_samples, int depth, int depth_mask)
@@ -852,25 +916,34 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
852 struct callchain_list *chain; 916 struct callchain_list *chain;
853 int new_depth_mask = depth_mask; 917 int new_depth_mask = depth_mask;
854 u64 new_total; 918 u64 new_total;
919 u64 remaining;
855 size_t ret = 0; 920 size_t ret = 0;
856 int i; 921 int i;
857 922
858 if (callchain_param.mode == CHAIN_GRAPH_REL) 923 if (callchain_param.mode == CHAIN_GRAPH_REL)
859 new_total = self->cumul_hit; 924 new_total = self->children_hit;
860 else 925 else
861 new_total = total_samples; 926 new_total = total_samples;
862 927
928 remaining = new_total;
929
863 node = rb_first(&self->rb_root); 930 node = rb_first(&self->rb_root);
864 while (node) { 931 while (node) {
932 u64 cumul;
933
865 child = rb_entry(node, struct callchain_node, rb_node); 934 child = rb_entry(node, struct callchain_node, rb_node);
935 cumul = cumul_hits(child);
936 remaining -= cumul;
866 937
867 /* 938 /*
868 * The depth mask manages the output of pipes that show 939 * The depth mask manages the output of pipes that show
869 * the depth. We don't want to keep the pipes of the current 940 * the depth. We don't want to keep the pipes of the current
870 * level for the last child of this depth 941 * level for the last child of this depth.
942 * Except if we have remaining filtered hits. They will
943 * supersede the last child
871 */ 944 */
872 next = rb_next(node); 945 next = rb_next(node);
873 if (!next) 946 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
874 new_depth_mask &= ~(1 << (depth - 1)); 947 new_depth_mask &= ~(1 << (depth - 1));
875 948
876 /* 949 /*
@@ -885,7 +958,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
885 ret += ipchain__fprintf_graph(fp, chain, depth, 958 ret += ipchain__fprintf_graph(fp, chain, depth,
886 new_depth_mask, i++, 959 new_depth_mask, i++,
887 new_total, 960 new_total,
888 child->cumul_hit); 961 cumul);
889 } 962 }
890 ret += callchain__fprintf_graph(fp, child, new_total, 963 ret += callchain__fprintf_graph(fp, child, new_total,
891 depth + 1, 964 depth + 1,
@@ -893,6 +966,19 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
893 node = next; 966 node = next;
894 } 967 }
895 968
969 if (callchain_param.mode == CHAIN_GRAPH_REL &&
970 remaining && remaining != new_total) {
971
972 if (!rem_sq_bracket)
973 return ret;
974
975 new_depth_mask &= ~(1 << (depth - 1));
976
977 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
978 new_depth_mask, 0, new_total,
979 remaining);
980 }
981
896 return ret; 982 return ret;
897} 983}
898 984
@@ -967,17 +1053,25 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
967 return 0; 1053 return 0;
968 1054
969 if (total_samples) 1055 if (total_samples)
970 ret = percent_color_fprintf(fp, " %6.2f%%", 1056 ret = percent_color_fprintf(fp,
971 (self->count * 100.0) / total_samples); 1057 field_sep ? "%.2f" : " %6.2f%%",
1058 (self->count * 100.0) / total_samples);
972 else 1059 else
973 ret = fprintf(fp, "%12Ld ", self->count); 1060 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
1061
1062 if (show_nr_samples) {
1063 if (field_sep)
1064 fprintf(fp, "%c%lld", *field_sep, self->count);
1065 else
1066 fprintf(fp, "%11lld", self->count);
1067 }
974 1068
975 list_for_each_entry(se, &hist_entry__sort_list, list) { 1069 list_for_each_entry(se, &hist_entry__sort_list, list) {
976 if (exclude_other && (se == &sort_parent)) 1070 if (se->elide)
977 continue; 1071 continue;
978 1072
979 fprintf(fp, " "); 1073 fprintf(fp, "%s", field_sep ?: " ");
980 ret += se->print(fp, self); 1074 ret += se->print(fp, self, se->width ? *se->width : 0);
981 } 1075 }
982 1076
983 ret += fprintf(fp, "\n"); 1077 ret += fprintf(fp, "\n");
@@ -992,6 +1086,18 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
992 * 1086 *
993 */ 1087 */
994 1088
1089static void dso__calc_col_width(struct dso *self)
1090{
1091 if (!col_width_list_str && !field_sep &&
1092 (!dso_list || strlist__has_entry(dso_list, self->name))) {
1093 unsigned int slen = strlen(self->name);
1094 if (slen > dsos__col_width)
1095 dsos__col_width = slen;
1096 }
1097
1098 self->slen_calculated = 1;
1099}
1100
995static struct symbol * 1101static struct symbol *
996resolve_symbol(struct thread *thread, struct map **mapp, 1102resolve_symbol(struct thread *thread, struct map **mapp,
997 struct dso **dsop, u64 *ipp) 1103 struct dso **dsop, u64 *ipp)
@@ -1011,6 +1117,14 @@ resolve_symbol(struct thread *thread, struct map **mapp,
1011 1117
1012 map = thread__find_map(thread, ip); 1118 map = thread__find_map(thread, ip);
1013 if (map != NULL) { 1119 if (map != NULL) {
1120 /*
1121 * We have to do this here as we may have a dso
1122 * with no symbol hit that has a name longer than
1123 * the ones with symbols sampled.
1124 */
1125 if (!sort_dso.elide && !map->dso->slen_calculated)
1126 dso__calc_col_width(map->dso);
1127
1014 if (mapp) 1128 if (mapp)
1015 *mapp = map; 1129 *mapp = map;
1016got_map: 1130got_map:
@@ -1282,35 +1396,69 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1282 struct sort_entry *se; 1396 struct sort_entry *se;
1283 struct rb_node *nd; 1397 struct rb_node *nd;
1284 size_t ret = 0; 1398 size_t ret = 0;
1399 unsigned int width;
1400 char *col_width = col_width_list_str;
1285 1401
1286 fprintf(fp, "\n"); 1402 init_rem_hits();
1287 fprintf(fp, "#\n"); 1403
1288 fprintf(fp, "# (%Ld samples)\n", (u64)total_samples); 1404 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1289 fprintf(fp, "#\n"); 1405 fprintf(fp, "#\n");
1290 1406
1291 fprintf(fp, "# Overhead"); 1407 fprintf(fp, "# Overhead");
1408 if (show_nr_samples) {
1409 if (field_sep)
1410 fprintf(fp, "%cSamples", *field_sep);
1411 else
1412 fputs(" Samples ", fp);
1413 }
1292 list_for_each_entry(se, &hist_entry__sort_list, list) { 1414 list_for_each_entry(se, &hist_entry__sort_list, list) {
1293 if (exclude_other && (se == &sort_parent)) 1415 if (se->elide)
1294 continue; 1416 continue;
1295 fprintf(fp, " %s", se->header); 1417 if (field_sep) {
1418 fprintf(fp, "%c%s", *field_sep, se->header);
1419 continue;
1420 }
1421 width = strlen(se->header);
1422 if (se->width) {
1423 if (col_width_list_str) {
1424 if (col_width) {
1425 *se->width = atoi(col_width);
1426 col_width = strchr(col_width, ',');
1427 if (col_width)
1428 ++col_width;
1429 }
1430 }
1431 width = *se->width = max(*se->width, width);
1432 }
1433 fprintf(fp, " %*s", width, se->header);
1296 } 1434 }
1297 fprintf(fp, "\n"); 1435 fprintf(fp, "\n");
1298 1436
1437 if (field_sep)
1438 goto print_entries;
1439
1299 fprintf(fp, "# ........"); 1440 fprintf(fp, "# ........");
1441 if (show_nr_samples)
1442 fprintf(fp, " ..........");
1300 list_for_each_entry(se, &hist_entry__sort_list, list) { 1443 list_for_each_entry(se, &hist_entry__sort_list, list) {
1301 unsigned int i; 1444 unsigned int i;
1302 1445
1303 if (exclude_other && (se == &sort_parent)) 1446 if (se->elide)
1304 continue; 1447 continue;
1305 1448
1306 fprintf(fp, " "); 1449 fprintf(fp, " ");
1307 for (i = 0; i < strlen(se->header); i++) 1450 if (se->width)
1451 width = *se->width;
1452 else
1453 width = strlen(se->header);
1454 for (i = 0; i < width; i++)
1308 fprintf(fp, "."); 1455 fprintf(fp, ".");
1309 } 1456 }
1310 fprintf(fp, "\n"); 1457 fprintf(fp, "\n");
1311 1458
1312 fprintf(fp, "#\n"); 1459 fprintf(fp, "#\n");
1313 1460
1461print_entries:
1314 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 1462 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1315 pos = rb_entry(nd, struct hist_entry, rb_node); 1463 pos = rb_entry(nd, struct hist_entry, rb_node);
1316 ret += hist_entry__fprintf(fp, pos, total_samples); 1464 ret += hist_entry__fprintf(fp, pos, total_samples);
@@ -1319,11 +1467,13 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1319 if (sort_order == default_sort_order && 1467 if (sort_order == default_sort_order &&
1320 parent_pattern == default_parent_pattern) { 1468 parent_pattern == default_parent_pattern) {
1321 fprintf(fp, "#\n"); 1469 fprintf(fp, "#\n");
1322 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); 1470 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1323 fprintf(fp, "#\n"); 1471 fprintf(fp, "#\n");
1324 } 1472 }
1325 fprintf(fp, "\n"); 1473 fprintf(fp, "\n");
1326 1474
1475 free(rem_sq_bracket);
1476
1327 return ret; 1477 return ret;
1328} 1478}
1329 1479
@@ -1377,11 +1527,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1377 more_data += sizeof(u64); 1527 more_data += sizeof(u64);
1378 } 1528 }
1379 1529
1380 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n", 1530 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1381 (void *)(offset + head), 1531 (void *)(offset + head),
1382 (void *)(long)(event->header.size), 1532 (void *)(long)(event->header.size),
1383 event->header.misc, 1533 event->header.misc,
1384 event->ip.pid, 1534 event->ip.pid, event->ip.tid,
1385 (void *)(long)ip, 1535 (void *)(long)ip,
1386 (long long)period); 1536 (long long)period);
1387 1537
@@ -1441,10 +1591,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1441 if (show & show_mask) { 1591 if (show & show_mask) {
1442 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 1592 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1443 1593
1444 if (dso_list && dso && dso->name && !strlist__has_entry(dso_list, dso->name)) 1594 if (dso_list && (!dso || !dso->name ||
1595 !strlist__has_entry(dso_list, dso->name)))
1445 return 0; 1596 return 0;
1446 1597
1447 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) 1598 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1448 return 0; 1599 return 0;
1449 1600
1450 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { 1601 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
@@ -1463,10 +1614,11 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1463 struct thread *thread = threads__findnew(event->mmap.pid); 1614 struct thread *thread = threads__findnew(event->mmap.pid);
1464 struct map *map = map__new(&event->mmap); 1615 struct map *map = map__new(&event->mmap);
1465 1616
1466 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", 1617 dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1467 (void *)(offset + head), 1618 (void *)(offset + head),
1468 (void *)(long)(event->header.size), 1619 (void *)(long)(event->header.size),
1469 event->mmap.pid, 1620 event->mmap.pid,
1621 event->mmap.tid,
1470 (void *)(long)event->mmap.start, 1622 (void *)(long)event->mmap.start,
1471 (void *)(long)event->mmap.len, 1623 (void *)(long)event->mmap.len,
1472 (void *)(long)event->mmap.pgoff, 1624 (void *)(long)event->mmap.pgoff,
@@ -1504,15 +1656,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1504} 1656}
1505 1657
1506static int 1658static int
1507process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1659process_task_event(event_t *event, unsigned long offset, unsigned long head)
1508{ 1660{
1509 struct thread *thread = threads__findnew(event->fork.pid); 1661 struct thread *thread = threads__findnew(event->fork.pid);
1510 struct thread *parent = threads__findnew(event->fork.ppid); 1662 struct thread *parent = threads__findnew(event->fork.ppid);
1511 1663
1512 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1664 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1513 (void *)(offset + head), 1665 (void *)(offset + head),
1514 (void *)(long)(event->header.size), 1666 (void *)(long)(event->header.size),
1515 event->fork.pid, event->fork.ppid); 1667 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1668 event->fork.pid, event->fork.tid,
1669 event->fork.ppid, event->fork.ptid);
1670
1671 /*
1672 * A thread clone will have the same PID for both
1673 * parent and child.
1674 */
1675 if (thread == parent)
1676 return 0;
1677
1678 if (event->header.type == PERF_EVENT_EXIT)
1679 return 0;
1516 1680
1517 if (!thread || !parent || thread__fork(thread, parent)) { 1681 if (!thread || !parent || thread__fork(thread, parent)) {
1518 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1682 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
@@ -1524,19 +1688,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1524} 1688}
1525 1689
1526static int 1690static int
1527process_period_event(event_t *event, unsigned long offset, unsigned long head)
1528{
1529 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
1530 (void *)(offset + head),
1531 (void *)(long)(event->header.size),
1532 event->period.time,
1533 event->period.id,
1534 event->period.sample_period);
1535
1536 return 0;
1537}
1538
1539static int
1540process_lost_event(event_t *event, unsigned long offset, unsigned long head) 1691process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1541{ 1692{
1542 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", 1693 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
@@ -1586,14 +1737,37 @@ static void trace_event(event_t *event)
1586 dprintf(".\n"); 1737 dprintf(".\n");
1587} 1738}
1588 1739
1740static struct perf_header *header;
1741
1742static struct perf_counter_attr *perf_header__find_attr(u64 id)
1743{
1744 int i;
1745
1746 for (i = 0; i < header->attrs; i++) {
1747 struct perf_header_attr *attr = header->attr[i];
1748 int j;
1749
1750 for (j = 0; j < attr->ids; j++) {
1751 if (attr->id[j] == id)
1752 return &attr->attr;
1753 }
1754 }
1755
1756 return NULL;
1757}
1758
1589static int 1759static int
1590process_read_event(event_t *event, unsigned long offset, unsigned long head) 1760process_read_event(event_t *event, unsigned long offset, unsigned long head)
1591{ 1761{
1592 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n", 1762 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1763
1764 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
1593 (void *)(offset + head), 1765 (void *)(offset + head),
1594 (void *)(long)(event->header.size), 1766 (void *)(long)(event->header.size),
1595 event->read.pid, 1767 event->read.pid,
1596 event->read.tid, 1768 event->read.tid,
1769 attr ? __event_name(attr->type, attr->config)
1770 : "FAIL",
1597 event->read.value); 1771 event->read.value);
1598 1772
1599 return 0; 1773 return 0;
@@ -1615,10 +1789,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1615 return process_comm_event(event, offset, head); 1789 return process_comm_event(event, offset, head);
1616 1790
1617 case PERF_EVENT_FORK: 1791 case PERF_EVENT_FORK:
1618 return process_fork_event(event, offset, head); 1792 case PERF_EVENT_EXIT:
1619 1793 return process_task_event(event, offset, head);
1620 case PERF_EVENT_PERIOD:
1621 return process_period_event(event, offset, head);
1622 1794
1623 case PERF_EVENT_LOST: 1795 case PERF_EVENT_LOST:
1624 return process_lost_event(event, offset, head); 1796 return process_lost_event(event, offset, head);
@@ -1641,8 +1813,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1641 return 0; 1813 return 0;
1642} 1814}
1643 1815
1644static struct perf_header *header;
1645
1646static u64 perf_header__sample_type(void) 1816static u64 perf_header__sample_type(void)
1647{ 1817{
1648 u64 sample_type = 0; 1818 u64 sample_type = 0;
@@ -1687,6 +1857,11 @@ static int __cmd_report(void)
1687 exit(-1); 1857 exit(-1);
1688 } 1858 }
1689 1859
1860 if (!force && (stat.st_uid != geteuid())) {
1861 fprintf(stderr, "file: %s not owned by current user\n", input_name);
1862 exit(-1);
1863 }
1864
1690 if (!stat.st_size) { 1865 if (!stat.st_size) {
1691 fprintf(stderr, "zero-sized file, nothing to do!\n"); 1866 fprintf(stderr, "zero-sized file, nothing to do!\n");
1692 exit(0); 1867 exit(0);
@@ -1710,6 +1885,13 @@ static int __cmd_report(void)
1710 " -g?\n"); 1885 " -g?\n");
1711 exit(-1); 1886 exit(-1);
1712 } 1887 }
1888 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1889 callchain = 1;
1890 if (register_callchain_param(&callchain_param) < 0) {
1891 fprintf(stderr, "Can't register callchain"
1892 " params\n");
1893 exit(-1);
1894 }
1713 } 1895 }
1714 1896
1715 if (load_kernel() < 0) { 1897 if (load_kernel() < 0) {
@@ -1848,6 +2030,13 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1848 else if (!strncmp(tok, "fractal", strlen(arg))) 2030 else if (!strncmp(tok, "fractal", strlen(arg)))
1849 callchain_param.mode = CHAIN_GRAPH_REL; 2031 callchain_param.mode = CHAIN_GRAPH_REL;
1850 2032
2033 else if (!strncmp(tok, "none", strlen(arg))) {
2034 callchain_param.mode = CHAIN_NONE;
2035 callchain = 0;
2036
2037 return 0;
2038 }
2039
1851 else 2040 else
1852 return -1; 2041 return -1;
1853 2042
@@ -1881,8 +2070,11 @@ static const struct option options[] = {
1881 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 2070 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1882 "dump raw trace in ASCII"), 2071 "dump raw trace in ASCII"),
1883 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 2072 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
2073 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1884 OPT_BOOLEAN('m', "modules", &modules, 2074 OPT_BOOLEAN('m', "modules", &modules,
1885 "load module symbols - WARNING: use only with -k and LIVE kernel"), 2075 "load module symbols - WARNING: use only with -k and LIVE kernel"),
2076 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2077 "Show a column with the number of samples"),
1886 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 2078 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1887 "sort by key(s): pid, comm, dso, symbol, parent"), 2079 "sort by key(s): pid, comm, dso, symbol, parent"),
1888 OPT_BOOLEAN('P', "full-paths", &full_paths, 2080 OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1891,15 +2083,21 @@ static const struct option options[] = {
1891 "regex filter to identify parent, see: '--sort parent'"), 2083 "regex filter to identify parent, see: '--sort parent'"),
1892 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 2084 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1893 "Only display entries with parent-match"), 2085 "Only display entries with parent-match"),
1894 OPT_CALLBACK_DEFAULT('c', "callchain", NULL, "output_type,min_percent", 2086 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1895 "Display callchains using output_type and min percent threshold. " 2087 "Display callchains using output_type and min percent threshold. "
1896 "Default: flat,0", &parse_callchain_opt, callchain_default_opt), 2088 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1897 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 2089 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1898 "only consider symbols in these dsos"), 2090 "only consider symbols in these dsos"),
1899 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 2091 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1900 "only consider symbols in these comms"), 2092 "only consider symbols in these comms"),
1901 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 2093 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1902 "only consider these symbols"), 2094 "only consider these symbols"),
2095 OPT_STRING('w', "column-widths", &col_width_list_str,
2096 "width[,width...]",
2097 "don't try to adjust column width, use these fixed values"),
2098 OPT_STRING('t', "field-separator", &field_sep, "separator",
2099 "separator for columns, no spaces will be added between "
2100 "columns '.' is reserved."),
1903 OPT_END() 2101 OPT_END()
1904}; 2102};
1905 2103
@@ -1919,7 +2117,8 @@ static void setup_sorting(void)
1919} 2117}
1920 2118
1921static void setup_list(struct strlist **list, const char *list_str, 2119static void setup_list(struct strlist **list, const char *list_str,
1922 const char *list_name) 2120 struct sort_entry *se, const char *list_name,
2121 FILE *fp)
1923{ 2122{
1924 if (list_str) { 2123 if (list_str) {
1925 *list = strlist__new(true, list_str); 2124 *list = strlist__new(true, list_str);
@@ -1928,6 +2127,11 @@ static void setup_list(struct strlist **list, const char *list_str,
1928 list_name); 2127 list_name);
1929 exit(129); 2128 exit(129);
1930 } 2129 }
2130 if (strlist__nr_entries(*list) == 1) {
2131 fprintf(fp, "# %s: %s\n", list_name,
2132 strlist__entry(*list, 0)->s);
2133 se->elide = true;
2134 }
1931 } 2135 }
1932} 2136}
1933 2137
@@ -1941,9 +2145,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1941 2145
1942 setup_sorting(); 2146 setup_sorting();
1943 2147
1944 if (parent_pattern != default_parent_pattern) 2148 if (parent_pattern != default_parent_pattern) {
1945 sort_dimension__add("parent"); 2149 sort_dimension__add("parent");
1946 else 2150 sort_parent.elide = 1;
2151 } else
1947 exclude_other = 0; 2152 exclude_other = 0;
1948 2153
1949 /* 2154 /*
@@ -1952,11 +2157,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1952 if (argc) 2157 if (argc)
1953 usage_with_options(report_usage, options); 2158 usage_with_options(report_usage, options);
1954 2159
1955 setup_list(&dso_list, dso_list_str, "dso");
1956 setup_list(&comm_list, comm_list_str, "comm");
1957 setup_list(&sym_list, sym_list_str, "symbol");
1958
1959 setup_pager(); 2160 setup_pager();
1960 2161
2162 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2163 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2164 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
2165
2166 if (field_sep && *field_sep == '.') {
2167 fputs("'.' is the only non valid --field-separator argument\n",
2168 stderr);
2169 exit(129);
2170 }
2171
1961 return __cmd_report(); 2172 return __cmd_report();
1962} 2173}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 27921a8ce1a9..b4b06c7903e1 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -496,7 +496,7 @@ static const struct option options[] = {
496 "stat events on existing pid"), 496 "stat events on existing pid"),
497 OPT_BOOLEAN('a', "all-cpus", &system_wide, 497 OPT_BOOLEAN('a', "all-cpus", &system_wide,
498 "system-wide collection from all CPUs"), 498 "system-wide collection from all CPUs"),
499 OPT_BOOLEAN('S', "scale", &scale, 499 OPT_BOOLEAN('c', "scale", &scale,
500 "scale/normalize counters"), 500 "scale/normalize counters"),
501 OPT_BOOLEAN('v', "verbose", &verbose, 501 OPT_BOOLEAN('v', "verbose", &verbose,
502 "be more verbose (show counter open errors, etc)"), 502 "be more verbose (show counter open errors, etc)"),
@@ -511,7 +511,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
511{ 511{
512 int status; 512 int status;
513 513
514 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);
515 if (!argc) 516 if (!argc)
516 usage_with_options(stat_usage, options); 517 usage_with_options(stat_usage, options);
517 if (run_count <= 0 || run_count > MAX_RUN) 518 if (run_count <= 0 || run_count > MAX_RUN)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 95d5c0ae375a..7de28ce9ca26 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -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;
@@ -68,15 +71,28 @@ static int freq = 0;
68static int verbose = 0; 71static int verbose = 0;
69static char *vmlinux = NULL; 72static char *vmlinux = NULL;
70 73
71static char *sym_filter;
72static unsigned long filter_start;
73static unsigned long filter_end;
74
75static int delay_secs = 2; 74static int delay_secs = 2;
76static int zero; 75static int zero;
77static int dump_symtab; 76static int dump_symtab;
78 77
79/* 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/*
80 * Symbols 96 * Symbols
81 */ 97 */
82 98
@@ -90,9 +106,237 @@ struct sym_entry {
90 unsigned long snap_count; 106 unsigned long snap_count;
91 double weight; 107 double weight;
92 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;
93}; 113};
94 114
95struct 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}
96 340
97struct dso *kernel_dso; 341struct dso *kernel_dso;
98 342
@@ -111,6 +355,9 @@ static double sym_weight(const struct sym_entry *sym)
111 double weight = sym->snap_count; 355 double weight = sym->snap_count;
112 int counter; 356 int counter;
113 357
358 if (!display_weighted)
359 return weight;
360
114 for (counter = 1; counter < nr_counters-1; counter++) 361 for (counter = 1; counter < nr_counters-1; counter++)
115 weight *= sym->count[counter]; 362 weight *= sym->count[counter];
116 363
@@ -158,7 +405,7 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
158static void print_sym_table(void) 405static void print_sym_table(void)
159{ 406{
160 int printed = 0, j; 407 int printed = 0, j;
161 int counter; 408 int counter, snap = !display_weighted ? sym_counter : 0;
162 float samples_per_sec = samples/delay_secs; 409 float samples_per_sec = samples/delay_secs;
163 float ksamples_per_sec = (samples-userspace_samples)/delay_secs; 410 float ksamples_per_sec = (samples-userspace_samples)/delay_secs;
164 float sum_ksamples = 0.0; 411 float sum_ksamples = 0.0;
@@ -174,7 +421,7 @@ static void print_sym_table(void)
174 pthread_mutex_unlock(&active_symbols_lock); 421 pthread_mutex_unlock(&active_symbols_lock);
175 422
176 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 423 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
177 syme->snap_count = syme->count[0]; 424 syme->snap_count = syme->count[snap];
178 if (syme->snap_count != 0) { 425 if (syme->snap_count != 0) {
179 syme->weight = sym_weight(syme); 426 syme->weight = sym_weight(syme);
180 rb_insert_active_sym(&tmp, syme); 427 rb_insert_active_sym(&tmp, syme);
@@ -194,7 +441,7 @@ static void print_sym_table(void)
194 samples_per_sec, 441 samples_per_sec,
195 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)));
196 443
197 if (nr_counters == 1) { 444 if (nr_counters == 1 || !display_weighted) {
198 printf("%Ld", (u64)attrs[0].sample_period); 445 printf("%Ld", (u64)attrs[0].sample_period);
199 if (freq) 446 if (freq)
200 printf("Hz "); 447 printf("Hz ");
@@ -202,7 +449,9 @@ static void print_sym_table(void)
202 printf(" "); 449 printf(" ");
203 } 450 }
204 451
205 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++) {
206 if (counter) 455 if (counter)
207 printf("/"); 456 printf("/");
208 457
@@ -227,6 +476,11 @@ static void print_sym_table(void)
227 476
228 printf("------------------------------------------------------------------------------\n\n"); 477 printf("------------------------------------------------------------------------------\n\n");
229 478
479 if (sym_filter_entry) {
480 show_details(sym_filter_entry);
481 return;
482 }
483
230 if (nr_counters == 1) 484 if (nr_counters == 1)
231 printf(" samples pcnt"); 485 printf(" samples pcnt");
232 else 486 else
@@ -241,13 +495,13 @@ static void print_sym_table(void)
241 struct symbol *sym = (struct symbol *)(syme + 1); 495 struct symbol *sym = (struct symbol *)(syme + 1);
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 if (nr_counters == 1) 504 if (nr_counters == 1 || !display_weighted)
251 printf("%20.2f - ", syme->weight); 505 printf("%20.2f - ", syme->weight);
252 else 506 else
253 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 507 printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
@@ -260,19 +514,250 @@ static void print_sym_table(void)
260 } 514 }
261} 515}
262 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 }
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);
596}
597
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
263static void *display_thread(void *arg __used) 734static void *display_thread(void *arg __used)
264{ 735{
265 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 736 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
266 int delay_msecs = delay_secs * 1000; 737 struct termios tc, save;
738 int delay_msecs, c;
739
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;
267 745
268 printf("PerfTop refresh period: %d seconds\n", delay_secs); 746repeat:
747 delay_msecs = delay_secs * 1000;
748 tcsetattr(0, TCSANOW, &tc);
749 /* trash return*/
750 getc(stdin);
269 751
270 do { 752 do {
271 print_sym_table(); 753 print_sym_table();
272 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 754 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
273 755
274 printf("key pressed - exiting.\n"); 756 c = getc(stdin);
275 exit(0); 757 tcsetattr(0, TCSAFLUSH, &save);
758
759 handle_keypress(c);
760 goto repeat;
276 761
277 return NULL; 762 return NULL;
278} 763}
@@ -284,6 +769,7 @@ static const char *skip_symbols[] = {
284 "enter_idle", 769 "enter_idle",
285 "exit_idle", 770 "exit_idle",
286 "mwait_idle", 771 "mwait_idle",
772 "mwait_idle_with_hints",
287 "ppc64_runlatch_off", 773 "ppc64_runlatch_off",
288 "pseries_dedicated_idle_sleep", 774 "pseries_dedicated_idle_sleep",
289 NULL 775 NULL
@@ -291,7 +777,6 @@ static const char *skip_symbols[] = {
291 777
292static int symbol_filter(struct dso *self, struct symbol *sym) 778static int symbol_filter(struct dso *self, struct symbol *sym)
293{ 779{
294 static int filter_match;
295 struct sym_entry *syme; 780 struct sym_entry *syme;
296 const char *name = sym->name; 781 const char *name = sym->name;
297 int i; 782 int i;
@@ -313,6 +798,10 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
313 return 1; 798 return 1;
314 799
315 syme = dso__sym_priv(self, sym); 800 syme = dso__sym_priv(self, sym);
801 pthread_mutex_init(&syme->source_lock, NULL);
802 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
803 sym_filter_entry = syme;
804
316 for (i = 0; skip_symbols[i]; i++) { 805 for (i = 0; skip_symbols[i]; i++) {
317 if (!strcmp(skip_symbols[i], name)) { 806 if (!strcmp(skip_symbols[i], name)) {
318 syme->skip = 1; 807 syme->skip = 1;
@@ -320,29 +809,6 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
320 } 809 }
321 } 810 }
322 811
323 if (filter_match == 1) {
324 filter_end = sym->start;
325 filter_match = -1;
326 if (filter_end - filter_start > 10000) {
327 fprintf(stderr,
328 "hm, too large filter symbol <%s> - skipping.\n",
329 sym_filter);
330 fprintf(stderr, "symbol filter start: %016lx\n",
331 filter_start);
332 fprintf(stderr, " end: %016lx\n",
333 filter_end);
334 filter_end = filter_start = 0;
335 sym_filter = NULL;
336 sleep(1);
337 }
338 }
339
340 if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) {
341 filter_match = 1;
342 filter_start = sym->start;
343 }
344
345
346 return 0; 812 return 0;
347} 813}
348 814
@@ -378,8 +844,6 @@ out_delete_dso:
378 return -1; 844 return -1;
379} 845}
380 846
381#define TRACE_COUNT 3
382
383/* 847/*
384 * Binary search in the histogram table and record the hit: 848 * Binary search in the histogram table and record the hit:
385 */ 849 */
@@ -392,6 +856,7 @@ static void record_ip(u64 ip, int counter)
392 856
393 if (!syme->skip) { 857 if (!syme->skip) {
394 syme->count[counter]++; 858 syme->count[counter]++;
859 record_precise_ip(syme, counter, ip);
395 pthread_mutex_lock(&active_symbols_lock); 860 pthread_mutex_lock(&active_symbols_lock);
396 if (list_empty(&syme->node) || !syme->node.next) 861 if (list_empty(&syme->node) || !syme->node.next)
397 __list_insert_active_sym(syme); 862 __list_insert_active_sym(syme);
@@ -549,7 +1014,7 @@ int group_fd;
549static void start_counter(int i, int counter) 1014static void start_counter(int i, int counter)
550{ 1015{
551 struct perf_counter_attr *attr; 1016 struct perf_counter_attr *attr;
552 unsigned int cpu; 1017 int cpu;
553 1018
554 cpu = profile_cpu; 1019 cpu = profile_cpu;
555 if (target_pid == -1 && profile_cpu == -1) 1020 if (target_pid == -1 && profile_cpu == -1)
@@ -559,6 +1024,7 @@ static void start_counter(int i, int counter)
559 1024
560 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1025 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
561 attr->freq = freq; 1026 attr->freq = freq;
1027 attr->inherit = (cpu < 0) && inherit;
562 1028
563try_again: 1029try_again:
564 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);
@@ -685,8 +1151,10 @@ static const struct option options[] = {
685 "only display functions with more events than this"), 1151 "only display functions with more events than this"),
686 OPT_BOOLEAN('g', "group", &group, 1152 OPT_BOOLEAN('g', "group", &group,
687 "put the counters into a counter group"), 1153 "put the counters into a counter group"),
688 OPT_STRING('s', "sym-filter", &sym_filter, "pattern", 1154 OPT_BOOLEAN('i', "inherit", &inherit,
689 "only display symbols matchig this pattern"), 1155 "child tasks inherit counters"),
1156 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1157 "symbol to annotate - requires -k option"),
690 OPT_BOOLEAN('z', "zero", &zero, 1158 OPT_BOOLEAN('z', "zero", &zero,
691 "zero history across updates"), 1159 "zero history across updates"),
692 OPT_INTEGER('F', "freq", &freq, 1160 OPT_INTEGER('F', "freq", &freq,
@@ -729,6 +1197,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
729 delay_secs = 1; 1197 delay_secs = 1;
730 1198
731 parse_symbols(); 1199 parse_symbols();
1200 parse_source(sym_filter_entry);
732 1201
733 /* 1202 /*
734 * 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 c5656784c61d..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,6 +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();
260 set_debugfs_path();
231 261
232 status = p->fn(argc, argv, prefix); 262 status = p->fn(argc, argv, prefix);
233 if (status) 263 if (status)
@@ -346,6 +376,49 @@ static int run_argv(int *argcp, const char ***argv)
346 return done_alias; 376 return done_alias;
347} 377}
348 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}
349 422
350int main(int argc, const char **argv) 423int main(int argc, const char **argv)
351{ 424{
@@ -354,7 +427,8 @@ int main(int argc, const char **argv)
354 cmd = perf_extract_argv0_path(argv[0]); 427 cmd = perf_extract_argv0_path(argv[0]);
355 if (!cmd) 428 if (!cmd)
356 cmd = "perf-help"; 429 cmd = "perf-help";
357 430 /* get debugfs mount point from /proc/mounts */
431 get_debugfs_mntpt();
358 /* 432 /*
359 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 433 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
360 * 434 *
@@ -377,6 +451,7 @@ int main(int argc, const char **argv)
377 argc--; 451 argc--;
378 handle_options(&argv, &argc, NULL); 452 handle_options(&argv, &argc, NULL);
379 commit_pager_choice(); 453 commit_pager_choice();
454 set_debugfs_path();
380 if (argc > 0) { 455 if (argc > 0) {
381 if (!prefixcmp(argv[0], "--")) 456 if (!prefixcmp(argv[0], "--"))
382 argv[0] += 2; 457 argv[0] += 2;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 63e67cc5487b..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");
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 161d5f413e28..4b50c412b9c5 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -18,6 +18,7 @@
18#define PERFATTRIBUTES_FILE ".perfattributes" 18#define PERFATTRIBUTES_FILE ".perfattributes"
19#define INFOATTRIBUTES_FILE "info/attributes" 19#define INFOATTRIBUTES_FILE "info/attributes"
20#define ATTRIBUTE_MACRO_PREFIX "[attr]" 20#define ATTRIBUTE_MACRO_PREFIX "[attr]"
21#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
21 22
22typedef int (*config_fn_t)(const char *, const char *, void *); 23typedef int (*config_fn_t)(const char *, const char *, void *);
23extern 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
index 9d3c8141b8c1..011473411642 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -13,6 +13,7 @@
13#include <stdio.h> 13#include <stdio.h>
14#include <stdbool.h> 14#include <stdbool.h>
15#include <errno.h> 15#include <errno.h>
16#include <math.h>
16 17
17#include "callchain.h" 18#include "callchain.h"
18 19
@@ -26,10 +27,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
26 struct rb_node **p = &root->rb_node; 27 struct rb_node **p = &root->rb_node;
27 struct rb_node *parent = NULL; 28 struct rb_node *parent = NULL;
28 struct callchain_node *rnode; 29 struct callchain_node *rnode;
30 u64 chain_cumul = cumul_hits(chain);
29 31
30 while (*p) { 32 while (*p) {
33 u64 rnode_cumul;
34
31 parent = *p; 35 parent = *p;
32 rnode = rb_entry(parent, struct callchain_node, rb_node); 36 rnode = rb_entry(parent, struct callchain_node, rb_node);
37 rnode_cumul = cumul_hits(rnode);
33 38
34 switch (mode) { 39 switch (mode) {
35 case CHAIN_FLAT: 40 case CHAIN_FLAT:
@@ -40,7 +45,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
40 break; 45 break;
41 case CHAIN_GRAPH_ABS: /* Falldown */ 46 case CHAIN_GRAPH_ABS: /* Falldown */
42 case CHAIN_GRAPH_REL: 47 case CHAIN_GRAPH_REL:
43 if (rnode->cumul_hit < chain->cumul_hit) 48 if (rnode_cumul < chain_cumul)
44 p = &(*p)->rb_left; 49 p = &(*p)->rb_left;
45 else 50 else
46 p = &(*p)->rb_right; 51 p = &(*p)->rb_right;
@@ -87,7 +92,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
87 92
88 chain_for_each_child(child, node) { 93 chain_for_each_child(child, node) {
89 __sort_chain_graph_abs(child, min_hit); 94 __sort_chain_graph_abs(child, min_hit);
90 if (child->cumul_hit >= min_hit) 95 if (cumul_hits(child) >= min_hit)
91 rb_insert_callchain(&node->rb_root, child, 96 rb_insert_callchain(&node->rb_root, child,
92 CHAIN_GRAPH_ABS); 97 CHAIN_GRAPH_ABS);
93 } 98 }
@@ -108,11 +113,11 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
108 u64 min_hit; 113 u64 min_hit;
109 114
110 node->rb_root = RB_ROOT; 115 node->rb_root = RB_ROOT;
111 min_hit = node->cumul_hit * min_percent / 100.0; 116 min_hit = ceil(node->children_hit * min_percent);
112 117
113 chain_for_each_child(child, node) { 118 chain_for_each_child(child, node) {
114 __sort_chain_graph_rel(child, min_percent); 119 __sort_chain_graph_rel(child, min_percent);
115 if (child->cumul_hit >= min_hit) 120 if (cumul_hits(child) >= min_hit)
116 rb_insert_callchain(&node->rb_root, child, 121 rb_insert_callchain(&node->rb_root, child,
117 CHAIN_GRAPH_REL); 122 CHAIN_GRAPH_REL);
118 } 123 }
@@ -122,7 +127,7 @@ static void
122sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root, 127sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
123 u64 min_hit __used, struct callchain_param *param) 128 u64 min_hit __used, struct callchain_param *param)
124{ 129{
125 __sort_chain_graph_rel(chain_root, param->min_percent); 130 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0);
126 rb_root->rb_node = chain_root->rb_root.rb_node; 131 rb_root->rb_node = chain_root->rb_root.rb_node;
127} 132}
128 133
@@ -211,7 +216,8 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,
211 new = create_child(parent, false); 216 new = create_child(parent, false);
212 fill_node(new, chain, start, syms); 217 fill_node(new, chain, start, syms);
213 218
214 new->cumul_hit = new->hit = 1; 219 new->children_hit = 0;
220 new->hit = 1;
215} 221}
216 222
217/* 223/*
@@ -241,7 +247,8 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
241 247
242 /* split the hits */ 248 /* split the hits */
243 new->hit = parent->hit; 249 new->hit = parent->hit;
244 new->cumul_hit = parent->cumul_hit; 250 new->children_hit = parent->children_hit;
251 parent->children_hit = cumul_hits(new);
245 new->val_nr = parent->val_nr - idx_local; 252 new->val_nr = parent->val_nr - idx_local;
246 parent->val_nr = idx_local; 253 parent->val_nr = idx_local;
247 254
@@ -249,6 +256,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
249 if (idx_total < chain->nr) { 256 if (idx_total < chain->nr) {
250 parent->hit = 0; 257 parent->hit = 0;
251 add_child(parent, chain, idx_total, syms); 258 add_child(parent, chain, idx_total, syms);
259 parent->children_hit++;
252 } else { 260 } else {
253 parent->hit = 1; 261 parent->hit = 1;
254 } 262 }
@@ -269,13 +277,13 @@ __append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
269 unsigned int ret = __append_chain(rnode, chain, start, syms); 277 unsigned int ret = __append_chain(rnode, chain, start, syms);
270 278
271 if (!ret) 279 if (!ret)
272 goto cumul; 280 goto inc_children_hit;
273 } 281 }
274 /* nothing in children, add to the current node */ 282 /* nothing in children, add to the current node */
275 add_child(root, chain, start, syms); 283 add_child(root, chain, start, syms);
276 284
277cumul: 285inc_children_hit:
278 root->cumul_hit++; 286 root->children_hit++;
279} 287}
280 288
281static int 289static int
@@ -317,8 +325,6 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
317 /* we match 100% of the path, increment the hit */ 325 /* we match 100% of the path, increment the hit */
318 if (i - start == root->val_nr && i == chain->nr) { 326 if (i - start == root->val_nr && i == chain->nr) {
319 root->hit++; 327 root->hit++;
320 root->cumul_hit++;
321
322 return 0; 328 return 0;
323 } 329 }
324 330
@@ -331,5 +337,7 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
331void append_chain(struct callchain_node *root, struct ip_callchain *chain, 337void append_chain(struct callchain_node *root, struct ip_callchain *chain,
332 struct symbol **syms) 338 struct symbol **syms)
333{ 339{
340 if (!chain->nr)
341 return;
334 __append_chain_children(root, chain, syms, 0); 342 __append_chain_children(root, chain, syms, 0);
335} 343}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 7812122bea1d..a926ae4f5a16 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -7,6 +7,7 @@
7#include "symbol.h" 7#include "symbol.h"
8 8
9enum chain_mode { 9enum chain_mode {
10 CHAIN_NONE,
10 CHAIN_FLAT, 11 CHAIN_FLAT,
11 CHAIN_GRAPH_ABS, 12 CHAIN_GRAPH_ABS,
12 CHAIN_GRAPH_REL 13 CHAIN_GRAPH_REL
@@ -21,7 +22,7 @@ struct callchain_node {
21 struct rb_root rb_root; /* sorted tree of children */ 22 struct rb_root rb_root; /* sorted tree of children */
22 unsigned int val_nr; 23 unsigned int val_nr;
23 u64 hit; 24 u64 hit;
24 u64 cumul_hit; /* hit + hits of children */ 25 u64 children_hit;
25}; 26};
26 27
27struct callchain_param; 28struct callchain_param;
@@ -48,6 +49,11 @@ static inline void callchain_init(struct callchain_node *node)
48 INIT_LIST_HEAD(&node->val); 49 INIT_LIST_HEAD(&node->val);
49} 50}
50 51
52static inline u64 cumul_hits(struct callchain_node *node)
53{
54 return node->hit + node->children_hit;
55}
56
51int register_callchain_param(struct callchain_param *param); 57int register_callchain_param(struct callchain_param *param);
52void append_chain(struct callchain_node *root, struct ip_callchain *chain, 58void append_chain(struct callchain_node *root, struct ip_callchain *chain,
53 struct symbol **syms); 59 struct symbol **syms);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 450384b3bbe5..b92a457ca32e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -185,6 +185,8 @@ static void do_read(int fd, void *buf, size_t size)
185 185
186 if (ret < 0) 186 if (ret < 0)
187 die("failed to read"); 187 die("failed to read");
188 if (ret == 0)
189 die("failed to read: missing data");
188 190
189 size -= ret; 191 size -= ret;
190 buf += ret; 192 buf += ret;
@@ -213,9 +215,10 @@ struct perf_header *perf_header__read(int fd)
213 215
214 for (i = 0; i < nr_attrs; i++) { 216 for (i = 0; i < nr_attrs; i++) {
215 struct perf_header_attr *attr; 217 struct perf_header_attr *attr;
216 off_t tmp = lseek(fd, 0, SEEK_CUR); 218 off_t tmp;
217 219
218 do_read(fd, &f_attr, sizeof(f_attr)); 220 do_read(fd, &f_attr, sizeof(f_attr));
221 tmp = lseek(fd, 0, SEEK_CUR);
219 222
220 attr = perf_header_attr__new(&f_attr.attr); 223 attr = perf_header_attr__new(&f_attr.attr);
221 224
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index b5ef53ad4c7a..bf280449fcfd 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -16,7 +16,7 @@ struct perf_header {
16 int frozen; 16 int frozen;
17 int attrs, size; 17 int attrs, size;
18 struct perf_header_attr **attr; 18 struct perf_header_attr **attr;
19 off_t attr_offset; 19 s64 attr_offset;
20 u64 data_offset; 20 u64 data_offset;
21 u64 data_size; 21 u64 data_size;
22}; 22};
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index 99c1b3d1edd9..a6b87390cb52 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -18,4 +18,12 @@
18 (type *)((char *)__mptr - offsetof(type, member)); }) 18 (type *)((char *)__mptr - offsetof(type, member)); })
19#endif 19#endif
20 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
21#endif 29#endif
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5184959e0615..044178408783 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
@@ -19,6 +20,8 @@ struct event_symbol {
19 char *alias; 20 char *alias;
20}; 21};
21 22
23char debugfs_path[MAXPATHLEN];
24
22#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 25#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
23#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 26#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
24 27
@@ -71,8 +74,8 @@ static char *sw_event_names[] = {
71#define MAX_ALIASES 8 74#define MAX_ALIASES 8
72 75
73static char *hw_cache[][MAX_ALIASES] = { 76static char *hw_cache[][MAX_ALIASES] = {
74 { "L1-d$", "l1-d", "l1d", "L1-data", }, 77 { "L1-dcache", "l1-d", "l1d", "L1-data", },
75 { "L1-i$", "l1-i", "l1i", "L1-instruction", }, 78 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
76 { "LLC", "L2" }, 79 { "LLC", "L2" },
77 { "dTLB", "d-tlb", "Data-TLB", }, 80 { "dTLB", "d-tlb", "Data-TLB", },
78 { "iTLB", "i-tlb", "Instruction-TLB", }, 81 { "iTLB", "i-tlb", "Instruction-TLB", },
@@ -110,6 +113,104 @@ static unsigned long hw_cache_stat[C(MAX)] = {
110 [C(BPU)] = (CACHE_READ), 113 [C(BPU)] = (CACHE_READ),
111}; 114};
112 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
113static int is_cache_op_valid(u8 cache_type, u8 cache_op) 214static int is_cache_op_valid(u8 cache_type, u8 cache_op)
114{ 215{
115 if (hw_cache_stat[cache_type] & COP(cache_op)) 216 if (hw_cache_stat[cache_type] & COP(cache_op))
@@ -138,9 +239,15 @@ char *event_name(int counter)
138{ 239{
139 u64 config = attrs[counter].config; 240 u64 config = attrs[counter].config;
140 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{
141 static char buf[32]; 248 static char buf[32];
142 249
143 if (attrs[counter].type == PERF_TYPE_RAW) { 250 if (type == PERF_TYPE_RAW) {
144 sprintf(buf, "raw 0x%llx", config); 251 sprintf(buf, "raw 0x%llx", config);
145 return buf; 252 return buf;
146 } 253 }
@@ -177,6 +284,9 @@ char *event_name(int counter)
177 return sw_event_names[config]; 284 return sw_event_names[config];
178 return "unknown-software"; 285 return "unknown-software";
179 286
287 case PERF_TYPE_TRACEPOINT:
288 return tracepoint_id_to_name(config);
289
180 default: 290 default:
181 break; 291 break;
182 } 292 }
@@ -265,6 +375,63 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
265 return 1; 375 return 1;
266} 376}
267 377
378static int parse_tracepoint_event(const char **strp,
379 struct perf_counter_attr *attr)
380{
381 const char *evt_name;
382 char *flags;
383 char sys_name[MAX_EVENT_LENGTH];
384 char id_buf[4];
385 int fd;
386 unsigned int sys_length, evt_length;
387 u64 id;
388 char evt_path[MAXPATHLEN];
389
390 if (valid_debugfs_mount(debugfs_path))
391 return 0;
392
393 evt_name = strchr(*strp, ':');
394 if (!evt_name)
395 return 0;
396
397 sys_length = evt_name - *strp;
398 if (sys_length >= MAX_EVENT_LENGTH)
399 return 0;
400
401 strncpy(sys_name, *strp, sys_length);
402 sys_name[sys_length] = '\0';
403 evt_name = evt_name + 1;
404
405 flags = strchr(evt_name, ':');
406 if (flags) {
407 *flags = '\0';
408 flags++;
409 if (!strncmp(flags, "record", strlen(flags)))
410 attr->sample_type |= PERF_SAMPLE_RAW;
411 }
412
413 evt_length = strlen(evt_name);
414 if (evt_length >= MAX_EVENT_LENGTH)
415 return 0;
416
417 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
418 sys_name, evt_name);
419 fd = open(evt_path, O_RDONLY);
420 if (fd < 0)
421 return 0;
422
423 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
424 close(fd);
425 return 0;
426 }
427 close(fd);
428 id = atoll(id_buf);
429 attr->config = id;
430 attr->type = PERF_TYPE_TRACEPOINT;
431 *strp = evt_name + evt_length;
432 return 1;
433}
434
268static int check_events(const char *str, unsigned int i) 435static int check_events(const char *str, unsigned int i)
269{ 436{
270 int n; 437 int n;
@@ -374,7 +541,8 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
374 */ 541 */
375static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) 542static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
376{ 543{
377 if (!(parse_raw_event(str, attr) || 544 if (!(parse_tracepoint_event(str, attr) ||
545 parse_raw_event(str, attr) ||
378 parse_numeric_event(str, attr) || 546 parse_numeric_event(str, attr) ||
379 parse_symbolic_event(str, attr) || 547 parse_symbolic_event(str, attr) ||
380 parse_generic_hw_event(str, attr))) 548 parse_generic_hw_event(str, attr)))
@@ -423,6 +591,42 @@ static const char * const event_type_descriptors[] = {
423}; 591};
424 592
425/* 593/*
594 * Print the events from <debugfs_mount_point>/tracing/events
595 */
596
597static void print_tracepoint_events(void)
598{
599 DIR *sys_dir, *evt_dir;
600 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
601 struct stat st;
602 char evt_path[MAXPATHLEN];
603
604 if (valid_debugfs_mount(debugfs_path))
605 return;
606
607 sys_dir = opendir(debugfs_path);
608 if (!sys_dir)
609 goto cleanup;
610
611 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
612 evt_dir = opendir(evt_path);
613 if (!evt_dir)
614 goto cleanup;
615 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
616 evt_path, st) {
617 snprintf(evt_path, MAXPATHLEN, "%s:%s",
618 sys_dirent.d_name, evt_dirent.d_name);
619 fprintf(stderr, " %-40s [%s]\n", evt_path,
620 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
621 }
622 closedir(evt_dir);
623 }
624
625cleanup:
626 closedir(sys_dir);
627}
628
629/*
426 * Print the help text for the event symbols: 630 * Print the help text for the event symbols:
427 */ 631 */
428void print_events(void) 632void print_events(void)
@@ -436,7 +640,7 @@ void print_events(void)
436 640
437 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 641 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
438 type = syms->type + 1; 642 type = syms->type + 1;
439 if (type > ARRAY_SIZE(event_type_descriptors)) 643 if (type >= ARRAY_SIZE(event_type_descriptors))
440 type = 0; 644 type = 0;
441 645
442 if (type != prev_type) 646 if (type != prev_type)
@@ -472,5 +676,7 @@ void print_events(void)
472 "rNNN"); 676 "rNNN");
473 fprintf(stderr, "\n"); 677 fprintf(stderr, "\n");
474 678
679 print_tracepoint_events();
680
475 exit(129); 681 exit(129);
476} 682}
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/quote.c b/tools/perf/util/quote.c
index c6e5dc0dc82f..2726fe40eb5d 100644
--- a/tools/perf/util/quote.c
+++ b/tools/perf/util/quote.c
@@ -318,7 +318,7 @@ char *quote_path_relative(const char *in, int len,
318 strbuf_addch(out, '"'); 318 strbuf_addch(out, '"');
319 if (prefix) { 319 if (prefix) {
320 int off = 0; 320 int off = 0;
321 while (prefix[off] && off < len && prefix[off] == in[off]) 321 while (off < len && prefix[off] && prefix[off] == in[off])
322 if (prefix[off] == '/') { 322 if (prefix[off] == '/') {
323 prefix += off + 1; 323 prefix += off + 1;
324 in += off + 1; 324 in += off + 1;
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 3dca2f654cd0..bf39dfadfd24 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -5,4 +5,7 @@
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7 7
8#define _STR(x) #x
9#define STR(x) _STR(x)
10
8#endif 11#endif
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 025a78edfffe..7ad38171dc2b 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -64,6 +64,7 @@ int strlist__add(struct strlist *self, const char *new_entry)
64 64
65 rb_link_node(&sn->rb_node, parent, p); 65 rb_link_node(&sn->rb_node, parent, p);
66 rb_insert_color(&sn->rb_node, &self->entries); 66 rb_insert_color(&sn->rb_node, &self->entries);
67 ++self->nr_entries;
67 68
68 return 0; 69 return 0;
69} 70}
@@ -155,8 +156,9 @@ struct strlist *strlist__new(bool dupstr, const char *slist)
155 struct strlist *self = malloc(sizeof(*self)); 156 struct strlist *self = malloc(sizeof(*self));
156 157
157 if (self != NULL) { 158 if (self != NULL) {
158 self->entries = RB_ROOT; 159 self->entries = RB_ROOT;
159 self->dupstr = dupstr; 160 self->dupstr = dupstr;
161 self->nr_entries = 0;
160 if (slist && strlist__parse_list(self, slist) != 0) 162 if (slist && strlist__parse_list(self, slist) != 0)
161 goto out_error; 163 goto out_error;
162 } 164 }
@@ -182,3 +184,17 @@ void strlist__delete(struct strlist *self)
182 free(self); 184 free(self);
183 } 185 }
184} 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
index 2fdcfee87586..921818e44a54 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -11,7 +11,8 @@ struct str_node {
11 11
12struct strlist { 12struct strlist {
13 struct rb_root entries; 13 struct rb_root entries;
14 bool dupstr; 14 unsigned int nr_entries;
15 bool dupstr;
15}; 16};
16 17
17struct strlist *strlist__new(bool dupstr, const char *slist); 18struct strlist *strlist__new(bool dupstr, const char *slist);
@@ -21,11 +22,17 @@ void strlist__remove(struct strlist *self, struct str_node *sn);
21int strlist__load(struct strlist *self, const char *filename); 22int strlist__load(struct strlist *self, const char *filename);
22int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
23 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
24bool strlist__has_entry(struct strlist *self, const char *entry); 26bool strlist__has_entry(struct strlist *self, const char *entry);
25 27
26static inline bool strlist__empty(const struct strlist *self) 28static inline bool strlist__empty(const struct strlist *self)
27{ 29{
28 return rb_first(&self->entries) == NULL; 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;
29} 36}
30 37
31int strlist__parse_list(struct strlist *self, const char *s); 38int strlist__parse_list(struct strlist *self, const char *s);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 4683b67b5ee4..5c0f42e6b33b 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -9,6 +9,16 @@
9 9
10const char *sym_hist_filter; 10const char *sym_hist_filter;
11 11
12enum dso_origin {
13 DSO__ORIG_KERNEL = 0,
14 DSO__ORIG_JAVA_JIT,
15 DSO__ORIG_FEDORA,
16 DSO__ORIG_UBUNTU,
17 DSO__ORIG_BUILDID,
18 DSO__ORIG_DSO,
19 DSO__ORIG_NOT_FOUND,
20};
21
12static struct symbol *symbol__new(u64 start, u64 len, 22static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size, 23 const char *name, unsigned int priv_size,
14 u64 obj_start, int verbose) 24 u64 obj_start, int verbose)
@@ -65,6 +75,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
65 self->syms = RB_ROOT; 75 self->syms = RB_ROOT;
66 self->sym_priv_size = sym_priv_size; 76 self->sym_priv_size = sym_priv_size;
67 self->find_symbol = dso__find_symbol; 77 self->find_symbol = dso__find_symbol;
78 self->slen_calculated = 0;
79 self->origin = DSO__ORIG_NOT_FOUND;
68 } 80 }
69 81
70 return self; 82 return self;
@@ -373,36 +385,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
373 idx < nr_entries; \ 385 idx < nr_entries; \
374 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 386 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
375 387
376static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 388/*
377 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 389 * We need to check if we have a .dynsym, so that we can handle the
378 GElf_Shdr *shdr_dynsym, 390 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
379 size_t dynsym_idx, int verbose) 391 * .dynsym or .symtab).
392 * And always look at the original dso, not at debuginfo packages, that
393 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
394 */
395static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
380{ 396{
381 uint32_t nr_rel_entries, idx; 397 uint32_t nr_rel_entries, idx;
382 GElf_Sym sym; 398 GElf_Sym sym;
383 u64 plt_offset; 399 u64 plt_offset;
384 GElf_Shdr shdr_plt; 400 GElf_Shdr shdr_plt;
385 struct symbol *f; 401 struct symbol *f;
386 GElf_Shdr shdr_rel_plt; 402 GElf_Shdr shdr_rel_plt, shdr_dynsym;
387 Elf_Data *reldata, *syms, *symstrs; 403 Elf_Data *reldata, *syms, *symstrs;
388 Elf_Scn *scn_plt_rel, *scn_symstrs; 404 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
405 size_t dynsym_idx;
406 GElf_Ehdr ehdr;
389 char sympltname[1024]; 407 char sympltname[1024];
390 int nr = 0, symidx; 408 Elf *elf;
409 int nr = 0, symidx, fd, err = 0;
410
411 fd = open(self->name, O_RDONLY);
412 if (fd < 0)
413 goto out;
391 414
392 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 415 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
416 if (elf == NULL)
417 goto out_close;
418
419 if (gelf_getehdr(elf, &ehdr) == NULL)
420 goto out_elf_end;
421
422 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
423 ".dynsym", &dynsym_idx);
424 if (scn_dynsym == NULL)
425 goto out_elf_end;
426
427 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
393 ".rela.plt", NULL); 428 ".rela.plt", NULL);
394 if (scn_plt_rel == NULL) { 429 if (scn_plt_rel == NULL) {
395 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 430 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
396 ".rel.plt", NULL); 431 ".rel.plt", NULL);
397 if (scn_plt_rel == NULL) 432 if (scn_plt_rel == NULL)
398 return 0; 433 goto out_elf_end;
399 } 434 }
400 435
436 err = -1;
437
401 if (shdr_rel_plt.sh_link != dynsym_idx) 438 if (shdr_rel_plt.sh_link != dynsym_idx)
402 return 0; 439 goto out_elf_end;
403 440
404 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 441 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
405 return 0; 442 goto out_elf_end;
406 443
407 /* 444 /*
408 * Fetch the relocation section to find the indexes to the GOT 445 * Fetch the relocation section to find the indexes to the GOT
@@ -410,19 +447,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
410 */ 447 */
411 reldata = elf_getdata(scn_plt_rel, NULL); 448 reldata = elf_getdata(scn_plt_rel, NULL);
412 if (reldata == NULL) 449 if (reldata == NULL)
413 return -1; 450 goto out_elf_end;
414 451
415 syms = elf_getdata(scn_dynsym, NULL); 452 syms = elf_getdata(scn_dynsym, NULL);
416 if (syms == NULL) 453 if (syms == NULL)
417 return -1; 454 goto out_elf_end;
418 455
419 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 456 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
420 if (scn_symstrs == NULL) 457 if (scn_symstrs == NULL)
421 return -1; 458 goto out_elf_end;
422 459
423 symstrs = elf_getdata(scn_symstrs, NULL); 460 symstrs = elf_getdata(scn_symstrs, NULL);
424 if (symstrs == NULL) 461 if (symstrs == NULL)
425 return -1; 462 goto out_elf_end;
426 463
427 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 464 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
428 plt_offset = shdr_plt.sh_offset; 465 plt_offset = shdr_plt.sh_offset;
@@ -441,7 +478,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
441 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 478 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
442 sympltname, self->sym_priv_size, 0, verbose); 479 sympltname, self->sym_priv_size, 0, verbose);
443 if (!f) 480 if (!f)
444 return -1; 481 goto out_elf_end;
445 482
446 dso__insert_symbol(self, f); 483 dso__insert_symbol(self, f);
447 ++nr; 484 ++nr;
@@ -459,19 +496,25 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
459 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 496 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
460 sympltname, self->sym_priv_size, 0, verbose); 497 sympltname, self->sym_priv_size, 0, verbose);
461 if (!f) 498 if (!f)
462 return -1; 499 goto out_elf_end;
463 500
464 dso__insert_symbol(self, f); 501 dso__insert_symbol(self, f);
465 ++nr; 502 ++nr;
466 } 503 }
467 } else {
468 /*
469 * TODO: There are still one more shdr_rel_plt.sh_type
470 * I have to investigate, but probably should be ignored.
471 */
472 } 504 }
473 505
474 return nr; 506 err = 0;
507out_elf_end:
508 elf_end(elf);
509out_close:
510 close(fd);
511
512 if (err == 0)
513 return nr;
514out:
515 fprintf(stderr, "%s: problems reading %s PLT info.\n",
516 __func__, self->name);
517 return 0;
475} 518}
476 519
477static int dso__load_sym(struct dso *self, int fd, const char *name, 520static int dso__load_sym(struct dso *self, int fd, const char *name,
@@ -485,10 +528,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
485 GElf_Shdr shdr; 528 GElf_Shdr shdr;
486 Elf_Data *syms; 529 Elf_Data *syms;
487 GElf_Sym sym; 530 GElf_Sym sym;
488 Elf_Scn *sec, *sec_dynsym, *sec_strndx; 531 Elf_Scn *sec, *sec_strndx;
489 Elf *elf; 532 Elf *elf;
490 size_t dynsym_idx; 533 int nr = 0, kernel = !strcmp("[kernel]", self->name);
491 int nr = 0;
492 534
493 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 535 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
494 if (elf == NULL) { 536 if (elf == NULL) {
@@ -504,32 +546,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
504 goto out_elf_end; 546 goto out_elf_end;
505 } 547 }
506 548
507 /*
508 * We need to check if we have a .dynsym, so that we can handle the
509 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
510 * .dynsym or .symtab)
511 */
512 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
513 ".dynsym", &dynsym_idx);
514 if (sec_dynsym != NULL) {
515 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
516 sec_dynsym, &shdr,
517 dynsym_idx, verbose);
518 if (nr < 0)
519 goto out_elf_end;
520 }
521
522 /*
523 * But if we have a full .symtab (that is a superset of .dynsym) we
524 * should add the symbols not in the .dynsyn
525 */
526 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 549 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
527 if (sec == NULL) { 550 if (sec == NULL) {
528 if (sec_dynsym == NULL) 551 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
552 if (sec == NULL)
529 goto out_elf_end; 553 goto out_elf_end;
530
531 sec = sec_dynsym;
532 gelf_getshdr(sec, &shdr);
533 } 554 }
534 555
535 syms = elf_getdata(sec, NULL); 556 syms = elf_getdata(sec, NULL);
@@ -549,18 +570,23 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
549 goto out_elf_end; 570 goto out_elf_end;
550 571
551 secstrs = elf_getdata(sec_strndx, NULL); 572 secstrs = elf_getdata(sec_strndx, NULL);
552 if (symstrs == NULL) 573 if (secstrs == NULL)
553 goto out_elf_end; 574 goto out_elf_end;
554 575
555 nr_syms = shdr.sh_size / shdr.sh_entsize; 576 nr_syms = shdr.sh_size / shdr.sh_entsize;
556 577
557 memset(&sym, 0, sizeof(sym)); 578 memset(&sym, 0, sizeof(sym));
558 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 579 if (!kernel) {
580 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
559 elf_section_by_name(elf, &ehdr, &shdr, 581 elf_section_by_name(elf, &ehdr, &shdr,
560 ".gnu.prelink_undo", 582 ".gnu.prelink_undo",
561 NULL) != NULL); 583 NULL) != NULL);
584 } else self->adjust_symbols = 0;
585
562 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 586 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
563 struct symbol *f; 587 struct symbol *f;
588 const char *name;
589 char *demangled;
564 u64 obj_start; 590 u64 obj_start;
565 struct section *section = NULL; 591 struct section *section = NULL;
566 int is_label = elf_sym__is_label(&sym); 592 int is_label = elf_sym__is_label(&sym);
@@ -599,10 +625,19 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
599 goto out_elf_end; 625 goto out_elf_end;
600 } 626 }
601 } 627 }
628 /*
629 * We need to figure out if the object was created from C++ sources
630 * DWARF DW_compile_unit has this, but we don't always have access
631 * to it...
632 */
633 name = elf_sym__name(&sym, symstrs);
634 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
635 if (demangled != NULL)
636 name = demangled;
602 637
603 f = symbol__new(sym.st_value, sym.st_size, 638 f = symbol__new(sym.st_value, sym.st_size, name,
604 elf_sym__name(&sym, symstrs),
605 self->sym_priv_size, obj_start, verbose); 639 self->sym_priv_size, obj_start, verbose);
640 free(demangled);
606 if (!f) 641 if (!f)
607 goto out_elf_end; 642 goto out_elf_end;
608 643
@@ -622,11 +657,85 @@ out_close:
622 return err; 657 return err;
623} 658}
624 659
660#define BUILD_ID_SIZE 128
661
662static char *dso__read_build_id(struct dso *self, int verbose)
663{
664 int i;
665 GElf_Ehdr ehdr;
666 GElf_Shdr shdr;
667 Elf_Data *build_id_data;
668 Elf_Scn *sec;
669 char *build_id = NULL, *bid;
670 unsigned char *raw;
671 Elf *elf;
672 int fd = open(self->name, O_RDONLY);
673
674 if (fd < 0)
675 goto out;
676
677 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
678 if (elf == NULL) {
679 if (verbose)
680 fprintf(stderr, "%s: cannot read %s ELF file.\n",
681 __func__, self->name);
682 goto out_close;
683 }
684
685 if (gelf_getehdr(elf, &ehdr) == NULL) {
686 if (verbose)
687 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
688 goto out_elf_end;
689 }
690
691 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
692 if (sec == NULL)
693 goto out_elf_end;
694
695 build_id_data = elf_getdata(sec, NULL);
696 if (build_id_data == NULL)
697 goto out_elf_end;
698 build_id = malloc(BUILD_ID_SIZE);
699 if (build_id == NULL)
700 goto out_elf_end;
701 raw = build_id_data->d_buf + 16;
702 bid = build_id;
703
704 for (i = 0; i < 20; ++i) {
705 sprintf(bid, "%02x", *raw);
706 ++raw;
707 bid += 2;
708 }
709 if (verbose >= 2)
710 printf("%s(%s): %s\n", __func__, self->name, build_id);
711out_elf_end:
712 elf_end(elf);
713out_close:
714 close(fd);
715out:
716 return build_id;
717}
718
719char dso__symtab_origin(const struct dso *self)
720{
721 static const char origin[] = {
722 [DSO__ORIG_KERNEL] = 'k',
723 [DSO__ORIG_JAVA_JIT] = 'j',
724 [DSO__ORIG_FEDORA] = 'f',
725 [DSO__ORIG_UBUNTU] = 'u',
726 [DSO__ORIG_BUILDID] = 'b',
727 [DSO__ORIG_DSO] = 'd',
728 };
729
730 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
731 return '!';
732 return origin[self->origin];
733}
734
625int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 735int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
626{ 736{
627 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 737 int size = PATH_MAX;
628 char *name = malloc(size); 738 char *name = malloc(size), *build_id = NULL;
629 int variant = 0;
630 int ret = -1; 739 int ret = -1;
631 int fd; 740 int fd;
632 741
@@ -635,26 +744,43 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
635 744
636 self->adjust_symbols = 0; 745 self->adjust_symbols = 0;
637 746
638 if (strncmp(self->name, "/tmp/perf-", 10) == 0) 747 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
639 return dso__load_perf_map(self, filter, verbose); 748 ret = dso__load_perf_map(self, filter, verbose);
749 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
750 DSO__ORIG_NOT_FOUND;
751 return ret;
752 }
753
754 self->origin = DSO__ORIG_FEDORA - 1;
640 755
641more: 756more:
642 do { 757 do {
643 switch (variant) { 758 self->origin++;
644 case 0: /* Fedora */ 759 switch (self->origin) {
760 case DSO__ORIG_FEDORA:
645 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 761 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
646 break; 762 break;
647 case 1: /* Ubuntu */ 763 case DSO__ORIG_UBUNTU:
648 snprintf(name, size, "/usr/lib/debug%s", self->name); 764 snprintf(name, size, "/usr/lib/debug%s", self->name);
649 break; 765 break;
650 case 2: /* Sane people */ 766 case DSO__ORIG_BUILDID:
767 build_id = dso__read_build_id(self, verbose);
768 if (build_id != NULL) {
769 snprintf(name, size,
770 "/usr/lib/debug/.build-id/%.2s/%s.debug",
771 build_id, build_id + 2);
772 free(build_id);
773 break;
774 }
775 self->origin++;
776 /* Fall thru */
777 case DSO__ORIG_DSO:
651 snprintf(name, size, "%s", self->name); 778 snprintf(name, size, "%s", self->name);
652 break; 779 break;
653 780
654 default: 781 default:
655 goto out; 782 goto out;
656 } 783 }
657 variant++;
658 784
659 fd = open(name, O_RDONLY); 785 fd = open(name, O_RDONLY);
660 } while (fd < 0); 786 } while (fd < 0);
@@ -668,8 +794,15 @@ more:
668 if (!ret) 794 if (!ret)
669 goto more; 795 goto more;
670 796
797 if (ret > 0) {
798 int nr_plt = dso__synthesize_plt_symbols(self, verbose);
799 if (nr_plt > 0)
800 ret += nr_plt;
801 }
671out: 802out:
672 free(name); 803 free(name);
804 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
805 return 0;
673 return ret; 806 return ret;
674} 807}
675 808
@@ -785,6 +918,9 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
785 if (err <= 0) 918 if (err <= 0)
786 err = dso__load_kallsyms(self, filter, verbose); 919 err = dso__load_kallsyms(self, filter, verbose);
787 920
921 if (err > 0)
922 self->origin = DSO__ORIG_KERNEL;
923
788 return err; 924 return err;
789} 925}
790 926
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 7918cffb23cd..b53bf0125c1b 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -7,6 +7,30 @@
7#include <linux/rbtree.h> 7#include <linux/rbtree.h>
8#include "module.h" 8#include "module.h"
9 9
10#ifdef HAVE_CPLUS_DEMANGLE
11extern char *cplus_demangle(const char *, int);
12
13static inline char *bfd_demangle(void __used *v, const char *c, int i)
14{
15 return cplus_demangle(c, i);
16}
17#else
18#ifdef NO_DEMANGLE
19static inline char *bfd_demangle(void __used *v, const char __used *c,
20 int __used i)
21{
22 return NULL;
23}
24#else
25#include <bfd.h>
26#endif
27#endif
28
29#ifndef DMGL_PARAMS
30#define DMGL_PARAMS (1 << 0) /* Include function args */
31#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
32#endif
33
10struct symbol { 34struct symbol {
11 struct rb_node rb_node; 35 struct rb_node rb_node;
12 u64 start; 36 u64 start;
@@ -25,6 +49,8 @@ struct dso {
25 struct symbol *(*find_symbol)(struct dso *, u64 ip); 49 struct symbol *(*find_symbol)(struct dso *, u64 ip);
26 unsigned int sym_priv_size; 50 unsigned int sym_priv_size;
27 unsigned char adjust_symbols; 51 unsigned char adjust_symbols;
52 unsigned char slen_calculated;
53 unsigned char origin;
28 char name[0]; 54 char name[0];
29}; 55};
30 56
@@ -48,6 +74,7 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
48int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 74int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
49 75
50size_t dso__fprintf(struct dso *self, FILE *fp); 76size_t dso__fprintf(struct dso *self, FILE *fp);
77char dso__symtab_origin(const struct dso *self);
51 78
52void symbol__init(void); 79void symbol__init(void);
53#endif /* _PERF_SYMBOL_ */ 80#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b4be6071c105..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>
@@ -80,6 +81,7 @@
80#include <netdb.h> 81#include <netdb.h>
81#include <pwd.h> 82#include <pwd.h>
82#include <inttypes.h> 83#include <inttypes.h>
84#include "../../../include/linux/magic.h"
83 85
84#ifndef NO_ICONV 86#ifndef NO_ICONV
85#include <iconv.h> 87#include <iconv.h>