aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-11-17 04:16:43 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-17 04:17:47 -0500
commita7b63425a41cd6a8d50f76fef0660c5110f97e91 (patch)
treebe17ee121f1c8814d8d39c9f3e0205d9397fab54 /tools
parent35039eb6b199749943547c8572be6604edf00229 (diff)
parent3726cc75e581c157202da93bb2333cce25c15c98 (diff)
Merge branch 'perf/core' into perf/probes
Resolved merge conflict in tools/perf/Makefile Merge reason: we want to queue up a dependent patch. Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-bench.txt120
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt34
-rw-r--r--tools/perf/Documentation/perf-report.txt8
-rw-r--r--tools/perf/Makefile27
-rw-r--r--tools/perf/bench/bench.h16
-rw-r--r--tools/perf/bench/sched-messaging.c336
-rw-r--r--tools/perf/bench/sched-pipe.c124
-rw-r--r--tools/perf/builtin-annotate.c23
-rw-r--r--tools/perf/builtin-bench.c183
-rw-r--r--tools/perf/builtin-buildid-list.c116
-rw-r--r--tools/perf/builtin-help.c12
-rw-r--r--tools/perf/builtin-record.c235
-rw-r--r--tools/perf/builtin-report.c6
-rw-r--r--tools/perf/builtin-sched.c2
-rw-r--r--tools/perf/builtin-stat.c5
-rw-r--r--tools/perf/builtin-timechart.c2
-rw-r--r--tools/perf/builtin-top.c230
-rw-r--r--tools/perf/builtin-trace.c2
-rw-r--r--tools/perf/builtin.h2
-rw-r--r--tools/perf/command-list.txt2
-rw-r--r--tools/perf/design.txt2
-rw-r--r--tools/perf/perf.c46
-rw-r--r--tools/perf/perf.h6
-rw-r--r--tools/perf/util/data_map.c31
-rw-r--r--tools/perf/util/data_map.h1
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/debugfs.c241
-rw-r--r--tools/perf/util/debugfs.h25
-rw-r--r--tools/perf/util/event.c177
-rw-r--r--tools/perf/util/event.h23
-rw-r--r--tools/perf/util/header.c342
-rw-r--r--tools/perf/util/header.h46
-rw-r--r--tools/perf/util/include/linux/bitmap.h1
-rw-r--r--tools/perf/util/include/linux/ctype.h2
-rw-r--r--tools/perf/util/map.c84
-rw-r--r--tools/perf/util/parse-events.c43
-rw-r--r--tools/perf/util/string.c84
-rw-r--r--tools/perf/util/string.h1
-rw-r--r--tools/perf/util/symbol.c286
-rw-r--r--tools/perf/util/symbol.h49
-rw-r--r--tools/perf/util/util.h3
41 files changed, 2413 insertions, 567 deletions
diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt
new file mode 100644
index 000000000000..ae525ac5a2ce
--- /dev/null
+++ b/tools/perf/Documentation/perf-bench.txt
@@ -0,0 +1,120 @@
1perf-bench(1)
2============
3
4NAME
5----
6perf-bench - General framework for benchmark suites
7
8SYNOPSIS
9--------
10[verse]
11'perf bench' [<common options>] <subsystem> <suite> [<options>]
12
13DESCRIPTION
14-----------
15This 'perf bench' command is general framework for benchmark suites.
16
17COMMON OPTIONS
18--------------
19-f::
20--format=::
21Specify format style.
22Current available format styles are,
23
24'default'::
25Default style. This is mainly for human reading.
26---------------------
27% perf bench sched pipe # with no style specify
28(executing 1000000 pipe operations between two tasks)
29 Total time:5.855 sec
30 5.855061 usecs/op
31 170792 ops/sec
32---------------------
33
34'simple'::
35This simple style is friendly for automated
36processing by scripts.
37---------------------
38% perf bench --format=simple sched pipe # specified simple
395.988
40---------------------
41
42SUBSYSTEM
43---------
44
45'sched'::
46 Scheduler and IPC mechanisms.
47
48SUITES FOR 'sched'
49~~~~~~~~~~~~~~~~~~
50*messaging*::
51Suite for evaluating performance of scheduler and IPC mechanisms.
52Based on hackbench by Rusty Russell.
53
54Options of *pipe*
55^^^^^^^^^^^^^^^^^
56-p::
57--pipe::
58Use pipe() instead of socketpair()
59
60-t::
61--thread::
62Be multi thread instead of multi process
63
64-g::
65--group=::
66Specify number of groups
67
68-l::
69--loop=::
70Specify number of loops
71
72Example of *messaging*
73^^^^^^^^^^^^^^^^^^^^^^
74
75---------------------
76% perf bench sched messaging # run with default
77options (20 sender and receiver processes per group)
78(10 groups == 400 processes run)
79
80 Total time:0.308 sec
81
82% perf bench sched messaging -t -g 20 # be multi-thread,with 20 groups
83(20 sender and receiver threads per group)
84(20 groups == 800 threads run)
85
86 Total time:0.582 sec
87---------------------
88
89*pipe*::
90Suite for pipe() system call.
91Based on pipe-test-1m.c by Ingo Molnar.
92
93Options of *pipe*
94^^^^^^^^^^^^^^^^^
95-l::
96--loop=::
97Specify number of loops.
98
99Example of *pipe*
100^^^^^^^^^^^^^^^^^
101
102---------------------
103% perf bench sched pipe
104(executing 1000000 pipe operations between two tasks)
105
106 Total time:8.091 sec
107 8.091833 usecs/op
108 123581 ops/sec
109
110% perf bench sched pipe -l 1000 # loop 1000
111(executing 1000 pipe operations between two tasks)
112
113 Total time:0.016 sec
114 16.948000 usecs/op
115 59004 ops/sec
116---------------------
117
118SEE ALSO
119--------
120linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
new file mode 100644
index 000000000000..01b642c0bf8f
--- /dev/null
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -0,0 +1,34 @@
1perf-buildid-list(1)
2====================
3
4NAME
5----
6perf-buildid-list - List the buildids in a perf.data file
7
8SYNOPSIS
9--------
10[verse]
11'perf buildid-list <options>'
12
13DESCRIPTION
14-----------
15This command displays the buildids found in a perf.data file, so that other
16tools can be used to fetch packages with matching symbol tables for use by
17perf report.
18
19OPTIONS
20-------
21-i::
22--input=::
23 Input file name. (default: perf.data)
24-f::
25--force::
26 Don't do ownership validation.
27-v::
28--verbose::
29 Be more verbose.
30
31SEE ALSO
32--------
33linkperf:perf-record[1], linkperf:perf-top[1],
34linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 59f0b846cd71..9dccb180b7af 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -24,11 +24,11 @@ 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 27-n::
28--show-nr-samples 28--show-nr-samples::
29 Show the number of samples for each symbol 29 Show the number of samples for each symbol
30-T 30-T::
31--threads 31--threads::
32 Show per-thread event counters 32 Show per-thread event counters
33-C:: 33-C::
34--comms=:: 34--comms=::
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 147e3cf035d3..3dbb5c5bb8c6 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -177,8 +177,7 @@ endif
177# Include saner warnings here, which can catch bugs: 177# Include saner warnings here, which can catch bugs:
178# 178#
179 179
180EXTRA_WARNINGS := -Wcast-align 180EXTRA_WARNINGS := -Wformat
181EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat
182EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security 181EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
183EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k 182EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
184EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow 183EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
@@ -208,7 +207,7 @@ ifndef PERF_DEBUG
208 CFLAGS_OPTIMIZE = -O6 207 CFLAGS_OPTIMIZE = -O6
209endif 208endif
210 209
211CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) 210CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
212LDFLAGS = -lpthread -lrt -lelf -lm 211LDFLAGS = -lpthread -lrt -lelf -lm
213ALL_CFLAGS = $(CFLAGS) 212ALL_CFLAGS = $(CFLAGS)
214ALL_LDFLAGS = $(LDFLAGS) 213ALL_LDFLAGS = $(LDFLAGS)
@@ -260,6 +259,9 @@ PTHREAD_LIBS = -lpthread
260# explicitly what architecture to check for. Fix this up for yours.. 259# explicitly what architecture to check for. Fix this up for yours..
261SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 260SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
262 261
262ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o /dev/null >/dev/null 2>&1 && echo y"), y)
263 CFLAGS := $(CFLAGS) -fstack-protector-all
264endif
263 265
264 266
265### --- END CONFIGURATION SECTION --- 267### --- END CONFIGURATION SECTION ---
@@ -355,6 +357,7 @@ LIB_H += util/include/asm/swab.h
355LIB_H += util/include/asm/system.h 357LIB_H += util/include/asm/system.h
356LIB_H += util/include/asm/uaccess.h 358LIB_H += util/include/asm/uaccess.h
357LIB_H += perf.h 359LIB_H += perf.h
360LIB_H += util/debugfs.h
358LIB_H += util/event.h 361LIB_H += util/event.h
359LIB_H += util/types.h 362LIB_H += util/types.h
360LIB_H += util/levenshtein.h 363LIB_H += util/levenshtein.h
@@ -380,7 +383,9 @@ LIB_OBJS += util/abspath.o
380LIB_OBJS += util/alias.o 383LIB_OBJS += util/alias.o
381LIB_OBJS += util/config.o 384LIB_OBJS += util/config.o
382LIB_OBJS += util/ctype.o 385LIB_OBJS += util/ctype.o
386LIB_OBJS += util/debugfs.o
383LIB_OBJS += util/environment.o 387LIB_OBJS += util/environment.o
388LIB_OBJS += util/event.o
384LIB_OBJS += util/exec_cmd.o 389LIB_OBJS += util/exec_cmd.o
385LIB_OBJS += util/help.o 390LIB_OBJS += util/help.o
386LIB_OBJS += util/levenshtein.o 391LIB_OBJS += util/levenshtein.o
@@ -417,8 +422,16 @@ LIB_OBJS += util/hist.o
417LIB_OBJS += util/data_map.o 422LIB_OBJS += util/data_map.o
418 423
419BUILTIN_OBJS += builtin-annotate.o 424BUILTIN_OBJS += builtin-annotate.o
425
426BUILTIN_OBJS += builtin-bench.o
427
428# Benchmark modules
429BUILTIN_OBJS += bench/sched-messaging.o
430BUILTIN_OBJS += bench/sched-pipe.o
431
420BUILTIN_OBJS += builtin-help.o 432BUILTIN_OBJS += builtin-help.o
421BUILTIN_OBJS += builtin-sched.o 433BUILTIN_OBJS += builtin-sched.o
434BUILTIN_OBJS += builtin-buildid-list.o
422BUILTIN_OBJS += builtin-list.o 435BUILTIN_OBJS += builtin-list.o
423BUILTIN_OBJS += builtin-record.o 436BUILTIN_OBJS += builtin-record.o
424BUILTIN_OBJS += builtin-report.o 437BUILTIN_OBJS += builtin-report.o
@@ -457,12 +470,16 @@ ifeq ($(uname_S),Darwin)
457 PTHREAD_LIBS = 470 PTHREAD_LIBS =
458endif 471endif
459 472
473ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 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)
460ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(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) 474ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(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)
461 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]); 475 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]);
462endif 476endif
463 477
464ifneq ($(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) 478 ifneq ($(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)
465 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel); 479 BASIC_CFLAGS += -DLIBELF_NO_MMAP
480 endif
481else
482 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
466endif 483endif
467 484
468ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y) 485ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
new file mode 100644
index 000000000000..9fbd8d745fa1
--- /dev/null
+++ b/tools/perf/bench/bench.h
@@ -0,0 +1,16 @@
1#ifndef BENCH_H
2#define BENCH_H
3
4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
6
7#define BENCH_FORMAT_DEFAULT_STR "default"
8#define BENCH_FORMAT_DEFAULT 0
9#define BENCH_FORMAT_SIMPLE_STR "simple"
10#define BENCH_FORMAT_SIMPLE 1
11
12#define BENCH_FORMAT_UNKNOWN -1
13
14extern int bench_format;
15
16#endif
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
new file mode 100644
index 000000000000..605a2a959aa8
--- /dev/null
+++ b/tools/perf/bench/sched-messaging.c
@@ -0,0 +1,336 @@
1/*
2 *
3 * builtin-bench-messaging.c
4 *
5 * messaging: Benchmark for scheduler and IPC mechanisms
6 *
7 * Based on hackbench by Rusty Russell <rusty@rustcorp.com.au>
8 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
9 *
10 */
11
12#include "../perf.h"
13#include "../util/util.h"
14#include "../util/parse-options.h"
15#include "../builtin.h"
16#include "bench.h"
17
18/* Test groups of 20 processes spraying to 20 receivers */
19#include <pthread.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/wait.h>
28#include <sys/time.h>
29#include <sys/poll.h>
30#include <limits.h>
31
32#define DATASIZE 100
33
34static int use_pipes = 0;
35static unsigned int loops = 100;
36static unsigned int thread_mode = 0;
37static unsigned int num_groups = 10;
38
39struct sender_context {
40 unsigned int num_fds;
41 int ready_out;
42 int wakefd;
43 int out_fds[0];
44};
45
46struct receiver_context {
47 unsigned int num_packets;
48 int in_fds[2];
49 int ready_out;
50 int wakefd;
51};
52
53static void barf(const char *msg)
54{
55 fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno));
56 exit(1);
57}
58
59static void fdpair(int fds[2])
60{
61 if (use_pipes) {
62 if (pipe(fds) == 0)
63 return;
64 } else {
65 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0)
66 return;
67 }
68
69 barf(use_pipes ? "pipe()" : "socketpair()");
70}
71
72/* Block until we're ready to go */
73static void ready(int ready_out, int wakefd)
74{
75 char dummy;
76 struct pollfd pollfd = { .fd = wakefd, .events = POLLIN };
77
78 /* Tell them we're ready. */
79 if (write(ready_out, &dummy, 1) != 1)
80 barf("CLIENT: ready write");
81
82 /* Wait for "GO" signal */
83 if (poll(&pollfd, 1, -1) != 1)
84 barf("poll");
85}
86
87/* Sender sprays loops messages down each file descriptor */
88static void *sender(struct sender_context *ctx)
89{
90 char data[DATASIZE];
91 unsigned int i, j;
92
93 ready(ctx->ready_out, ctx->wakefd);
94
95 /* Now pump to every receiver. */
96 for (i = 0; i < loops; i++) {
97 for (j = 0; j < ctx->num_fds; j++) {
98 int ret, done = 0;
99
100again:
101 ret = write(ctx->out_fds[j], data + done,
102 sizeof(data)-done);
103 if (ret < 0)
104 barf("SENDER: write");
105 done += ret;
106 if (done < DATASIZE)
107 goto again;
108 }
109 }
110
111 return NULL;
112}
113
114
115/* One receiver per fd */
116static void *receiver(struct receiver_context* ctx)
117{
118 unsigned int i;
119
120 if (!thread_mode)
121 close(ctx->in_fds[1]);
122
123 /* Wait for start... */
124 ready(ctx->ready_out, ctx->wakefd);
125
126 /* Receive them all */
127 for (i = 0; i < ctx->num_packets; i++) {
128 char data[DATASIZE];
129 int ret, done = 0;
130
131again:
132 ret = read(ctx->in_fds[0], data + done, DATASIZE - done);
133 if (ret < 0)
134 barf("SERVER: read");
135 done += ret;
136 if (done < DATASIZE)
137 goto again;
138 }
139
140 return NULL;
141}
142
143static pthread_t create_worker(void *ctx, void *(*func)(void *))
144{
145 pthread_attr_t attr;
146 pthread_t childid;
147 int err;
148
149 if (!thread_mode) {
150 /* process mode */
151 /* Fork the receiver. */
152 switch (fork()) {
153 case -1:
154 barf("fork()");
155 break;
156 case 0:
157 (*func) (ctx);
158 exit(0);
159 break;
160 default:
161 break;
162 }
163
164 return (pthread_t)0;
165 }
166
167 if (pthread_attr_init(&attr) != 0)
168 barf("pthread_attr_init:");
169
170#ifndef __ia64__
171 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)
172 barf("pthread_attr_setstacksize");
173#endif
174
175 err = pthread_create(&childid, &attr, func, ctx);
176 if (err != 0) {
177 fprintf(stderr, "pthread_create failed: %s (%d)\n",
178 strerror(err), err);
179 exit(-1);
180 }
181 return childid;
182}
183
184static void reap_worker(pthread_t id)
185{
186 int proc_status;
187 void *thread_status;
188
189 if (!thread_mode) {
190 /* process mode */
191 wait(&proc_status);
192 if (!WIFEXITED(proc_status))
193 exit(1);
194 } else {
195 pthread_join(id, &thread_status);
196 }
197}
198
199/* One group of senders and receivers */
200static unsigned int group(pthread_t *pth,
201 unsigned int num_fds,
202 int ready_out,
203 int wakefd)
204{
205 unsigned int i;
206 struct sender_context *snd_ctx = malloc(sizeof(struct sender_context)
207 + num_fds * sizeof(int));
208
209 if (!snd_ctx)
210 barf("malloc()");
211
212 for (i = 0; i < num_fds; i++) {
213 int fds[2];
214 struct receiver_context *ctx = malloc(sizeof(*ctx));
215
216 if (!ctx)
217 barf("malloc()");
218
219
220 /* Create the pipe between client and server */
221 fdpair(fds);
222
223 ctx->num_packets = num_fds * loops;
224 ctx->in_fds[0] = fds[0];
225 ctx->in_fds[1] = fds[1];
226 ctx->ready_out = ready_out;
227 ctx->wakefd = wakefd;
228
229 pth[i] = create_worker(ctx, (void *)receiver);
230
231 snd_ctx->out_fds[i] = fds[1];
232 if (!thread_mode)
233 close(fds[0]);
234 }
235
236 /* Now we have all the fds, fork the senders */
237 for (i = 0; i < num_fds; i++) {
238 snd_ctx->ready_out = ready_out;
239 snd_ctx->wakefd = wakefd;
240 snd_ctx->num_fds = num_fds;
241
242 pth[num_fds+i] = create_worker(snd_ctx, (void *)sender);
243 }
244
245 /* Close the fds we have left */
246 if (!thread_mode)
247 for (i = 0; i < num_fds; i++)
248 close(snd_ctx->out_fds[i]);
249
250 /* Return number of children to reap */
251 return num_fds * 2;
252}
253
254static const struct option options[] = {
255 OPT_BOOLEAN('p', "pipe", &use_pipes,
256 "Use pipe() instead of socketpair()"),
257 OPT_BOOLEAN('t', "thread", &thread_mode,
258 "Be multi thread instead of multi process"),
259 OPT_INTEGER('g', "group", &num_groups,
260 "Specify number of groups"),
261 OPT_INTEGER('l', "loop", &loops,
262 "Specify number of loops"),
263 OPT_END()
264};
265
266static const char * const bench_sched_message_usage[] = {
267 "perf bench sched messaging <options>",
268 NULL
269};
270
271int bench_sched_messaging(int argc, const char **argv,
272 const char *prefix __used)
273{
274 unsigned int i, total_children;
275 struct timeval start, stop, diff;
276 unsigned int num_fds = 20;
277 int readyfds[2], wakefds[2];
278 char dummy;
279 pthread_t *pth_tab;
280
281 argc = parse_options(argc, argv, options,
282 bench_sched_message_usage, 0);
283
284 pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t));
285 if (!pth_tab)
286 barf("main:malloc()");
287
288 fdpair(readyfds);
289 fdpair(wakefds);
290
291 total_children = 0;
292 for (i = 0; i < num_groups; i++)
293 total_children += group(pth_tab+total_children, num_fds,
294 readyfds[1], wakefds[0]);
295
296 /* Wait for everyone to be ready */
297 for (i = 0; i < total_children; i++)
298 if (read(readyfds[0], &dummy, 1) != 1)
299 barf("Reading for readyfds");
300
301 gettimeofday(&start, NULL);
302
303 /* Kick them off */
304 if (write(wakefds[1], &dummy, 1) != 1)
305 barf("Writing to start them");
306
307 /* Reap them all */
308 for (i = 0; i < total_children; i++)
309 reap_worker(pth_tab[i]);
310
311 gettimeofday(&stop, NULL);
312
313 timersub(&stop, &start, &diff);
314
315 switch (bench_format) {
316 case BENCH_FORMAT_DEFAULT:
317 printf("# %d sender and receiver %s per group\n",
318 num_fds, thread_mode ? "threads" : "processes");
319 printf("# %d groups == %d %s run\n\n",
320 num_groups, num_groups * 2 * num_fds,
321 thread_mode ? "threads" : "processes");
322 printf(" %14s: %lu.%03lu [sec]\n", "Total time",
323 diff.tv_sec, diff.tv_usec/1000);
324 break;
325 case BENCH_FORMAT_SIMPLE:
326 printf("%lu.%03lu\n", diff.tv_sec, diff.tv_usec/1000);
327 break;
328 default:
329 /* reaching here is something disaster */
330 fprintf(stderr, "Unknown format:%d\n", bench_format);
331 exit(1);
332 break;
333 }
334
335 return 0;
336}
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
new file mode 100644
index 000000000000..238185f97977
--- /dev/null
+++ b/tools/perf/bench/sched-pipe.c
@@ -0,0 +1,124 @@
1/*
2 *
3 * builtin-bench-pipe.c
4 *
5 * pipe: Benchmark for pipe()
6 *
7 * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
8 * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
9 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
10 *
11 */
12
13#include "../perf.h"
14#include "../util/util.h"
15#include "../util/parse-options.h"
16#include "../builtin.h"
17#include "bench.h"
18
19#include <unistd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <signal.h>
23#include <sys/wait.h>
24#include <linux/unistd.h>
25#include <string.h>
26#include <errno.h>
27#include <assert.h>
28#include <sys/time.h>
29#include <sys/types.h>
30
31#define LOOPS_DEFAULT 1000000
32static int loops = LOOPS_DEFAULT;
33
34static const struct option options[] = {
35 OPT_INTEGER('l', "loop", &loops,
36 "Specify number of loops"),
37 OPT_END()
38};
39
40static const char * const bench_sched_pipe_usage[] = {
41 "perf bench sched pipe <options>",
42 NULL
43};
44
45int bench_sched_pipe(int argc, const char **argv,
46 const char *prefix __used)
47{
48 int pipe_1[2], pipe_2[2];
49 int m = 0, i;
50 struct timeval start, stop, diff;
51 unsigned long long result_usec = 0;
52
53 /*
54 * why does "ret" exist?
55 * discarding returned value of read(), write()
56 * causes error in building environment for perf
57 */
58 int ret, wait_stat;
59 pid_t pid, retpid;
60
61 argc = parse_options(argc, argv, options,
62 bench_sched_pipe_usage, 0);
63
64 assert(!pipe(pipe_1));
65 assert(!pipe(pipe_2));
66
67 pid = fork();
68 assert(pid >= 0);
69
70 gettimeofday(&start, NULL);
71
72 if (!pid) {
73 for (i = 0; i < loops; i++) {
74 ret = read(pipe_1[0], &m, sizeof(int));
75 ret = write(pipe_2[1], &m, sizeof(int));
76 }
77 } else {
78 for (i = 0; i < loops; i++) {
79 ret = write(pipe_1[1], &m, sizeof(int));
80 ret = read(pipe_2[0], &m, sizeof(int));
81 }
82 }
83
84 gettimeofday(&stop, NULL);
85 timersub(&stop, &start, &diff);
86
87 if (pid) {
88 retpid = waitpid(pid, &wait_stat, 0);
89 assert((retpid == pid) && WIFEXITED(wait_stat));
90 return 0;
91 }
92
93 switch (bench_format) {
94 case BENCH_FORMAT_DEFAULT:
95 printf("# Extecuted %d pipe operations between two tasks\n\n",
96 loops);
97
98 result_usec = diff.tv_sec * 1000000;
99 result_usec += diff.tv_usec;
100
101 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
102 diff.tv_sec, diff.tv_usec/1000);
103
104 printf(" %14lf usecs/op\n",
105 (double)result_usec / (double)loops);
106 printf(" %14d ops/sec\n",
107 (int)((double)loops /
108 ((double)result_usec / (double)1000000)));
109 break;
110
111 case BENCH_FORMAT_SIMPLE:
112 printf("%lu.%03lu\n",
113 diff.tv_sec, diff.tv_usec / 1000);
114 break;
115
116 default:
117 /* reaching here is something disaster */
118 fprintf(stderr, "Unknown format:%d\n", bench_format);
119 exit(1);
120 break;
121 }
122
123 return 0;
124}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 6d63c2eea2c7..77d50a6d6802 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -55,11 +55,11 @@ struct sym_priv {
55 55
56static const char *sym_hist_filter; 56static const char *sym_hist_filter;
57 57
58static int symbol_filter(struct map *map, struct symbol *sym) 58static int symbol_filter(struct map *map __used, struct symbol *sym)
59{ 59{
60 if (sym_hist_filter == NULL || 60 if (sym_hist_filter == NULL ||
61 strcmp(sym->name, sym_hist_filter) == 0) { 61 strcmp(sym->name, sym_hist_filter) == 0) {
62 struct sym_priv *priv = dso__sym_priv(map->dso, sym); 62 struct sym_priv *priv = symbol__priv(sym);
63 const int size = (sizeof(*priv->hist) + 63 const int size = (sizeof(*priv->hist) +
64 (sym->end - sym->start) * sizeof(u64)); 64 (sym->end - sym->start) * sizeof(u64));
65 65
@@ -92,7 +92,7 @@ static void hist_hit(struct hist_entry *he, u64 ip)
92 if (!sym || !he->map) 92 if (!sym || !he->map)
93 return; 93 return;
94 94
95 priv = dso__sym_priv(he->map->dso, sym); 95 priv = symbol__priv(sym);
96 if (!priv->hist) 96 if (!priv->hist)
97 return; 97 return;
98 98
@@ -165,7 +165,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
165 if (map != NULL) { 165 if (map != NULL) {
166got_map: 166got_map:
167 ip = map->map_ip(map, ip); 167 ip = map->map_ip(map, ip);
168 sym = map->dso->find_symbol(map->dso, ip); 168 sym = map__find_symbol(map, ip, symbol_filter);
169 } else { 169 } else {
170 /* 170 /*
171 * If this is outside of all known maps, 171 * If this is outside of all known maps,
@@ -202,8 +202,7 @@ got_map:
202static int 202static int
203process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 203process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
204{ 204{
205 struct map *map = map__new(&event->mmap, NULL, 0, 205 struct map *map = map__new(&event->mmap, NULL, 0);
206 sizeof(struct sym_priv), symbol_filter);
207 struct thread *thread = threads__findnew(event->mmap.pid); 206 struct thread *thread = threads__findnew(event->mmap.pid);
208 207
209 dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n", 208 dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
@@ -355,7 +354,7 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
355 unsigned int hits = 0; 354 unsigned int hits = 0;
356 double percent = 0.0; 355 double percent = 0.0;
357 const char *color; 356 const char *color;
358 struct sym_priv *priv = dso__sym_priv(he->map->dso, sym); 357 struct sym_priv *priv = symbol__priv(sym);
359 struct sym_ext *sym_ext = priv->ext; 358 struct sym_ext *sym_ext = priv->ext;
360 struct sym_hist *h = priv->hist; 359 struct sym_hist *h = priv->hist;
361 360
@@ -422,7 +421,7 @@ static void insert_source_line(struct sym_ext *sym_ext)
422 421
423static void free_source_line(struct hist_entry *he, int len) 422static void free_source_line(struct hist_entry *he, int len)
424{ 423{
425 struct sym_priv *priv = dso__sym_priv(he->map->dso, he->sym); 424 struct sym_priv *priv = symbol__priv(he->sym);
426 struct sym_ext *sym_ext = priv->ext; 425 struct sym_ext *sym_ext = priv->ext;
427 int i; 426 int i;
428 427
@@ -446,7 +445,7 @@ get_source_line(struct hist_entry *he, int len, const char *filename)
446 int i; 445 int i;
447 char cmd[PATH_MAX * 2]; 446 char cmd[PATH_MAX * 2];
448 struct sym_ext *sym_ext; 447 struct sym_ext *sym_ext;
449 struct sym_priv *priv = dso__sym_priv(he->map->dso, sym); 448 struct sym_priv *priv = symbol__priv(sym);
450 struct sym_hist *h = priv->hist; 449 struct sym_hist *h = priv->hist;
451 450
452 if (!h->sum) 451 if (!h->sum)
@@ -589,7 +588,7 @@ static void find_annotations(void)
589 if (he->sym == NULL) 588 if (he->sym == NULL)
590 continue; 589 continue;
591 590
592 priv = dso__sym_priv(he->map->dso, he->sym); 591 priv = symbol__priv(he->sym);
593 if (priv->hist == NULL) 592 if (priv->hist == NULL)
594 continue; 593 continue;
595 594
@@ -637,7 +636,7 @@ static int __cmd_annotate(void)
637 exit(0); 636 exit(0);
638 } 637 }
639 638
640 if (load_kernel(sizeof(struct sym_priv), symbol_filter) < 0) { 639 if (load_kernel(symbol_filter) < 0) {
641 perror("failed to load kernel symbols"); 640 perror("failed to load kernel symbols");
642 return EXIT_FAILURE; 641 return EXIT_FAILURE;
643 } 642 }
@@ -769,7 +768,7 @@ static void setup_sorting(void)
769 768
770int cmd_annotate(int argc, const char **argv, const char *prefix __used) 769int cmd_annotate(int argc, const char **argv, const char *prefix __used)
771{ 770{
772 symbol__init(); 771 symbol__init(sizeof(struct sym_priv));
773 772
774 page_size = getpagesize(); 773 page_size = getpagesize();
775 774
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
new file mode 100644
index 000000000000..90c39baae0de
--- /dev/null
+++ b/tools/perf/builtin-bench.c
@@ -0,0 +1,183 @@
1/*
2 *
3 * builtin-bench.c
4 *
5 * General benchmarking subsystem provided by perf
6 *
7 * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
8 *
9 */
10
11/*
12 *
13 * Available subsystem list:
14 * sched ... scheduler and IPC mechanism
15 *
16 */
17
18#include "perf.h"
19#include "util/util.h"
20#include "util/parse-options.h"
21#include "builtin.h"
22#include "bench/bench.h"
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28struct bench_suite {
29 const char *name;
30 const char *summary;
31 int (*fn)(int, const char **, const char *);
32};
33
34static struct bench_suite sched_suites[] = {
35 { "messaging",
36 "Benchmark for scheduler and IPC mechanisms",
37 bench_sched_messaging },
38 { "pipe",
39 "Flood of communication over pipe() between two processes",
40 bench_sched_pipe },
41 { NULL,
42 NULL,
43 NULL }
44};
45
46struct bench_subsys {
47 const char *name;
48 const char *summary;
49 struct bench_suite *suites;
50};
51
52static struct bench_subsys subsystems[] = {
53 { "sched",
54 "scheduler and IPC mechanism",
55 sched_suites },
56 { NULL,
57 NULL,
58 NULL }
59};
60
61static void dump_suites(int subsys_index)
62{
63 int i;
64
65 printf("List of available suites for %s...\n\n",
66 subsystems[subsys_index].name);
67
68 for (i = 0; subsystems[subsys_index].suites[i].name; i++)
69 printf("\t%s: %s\n",
70 subsystems[subsys_index].suites[i].name,
71 subsystems[subsys_index].suites[i].summary);
72
73 printf("\n");
74 return;
75}
76
77static char *bench_format_str;
78int bench_format = BENCH_FORMAT_DEFAULT;
79
80static const struct option bench_options[] = {
81 OPT_STRING('f', "format", &bench_format_str, "default",
82 "Specify format style"),
83 OPT_END()
84};
85
86static const char * const bench_usage[] = {
87 "perf bench [<common options>] <subsystem> <suite> [<options>]",
88 NULL
89};
90
91static void print_usage(void)
92{
93 int i;
94
95 printf("Usage: \n");
96 for (i = 0; bench_usage[i]; i++)
97 printf("\t%s\n", bench_usage[i]);
98 printf("\n");
99
100 printf("List of available subsystems...\n\n");
101
102 for (i = 0; subsystems[i].name; i++)
103 printf("\t%s: %s\n",
104 subsystems[i].name, subsystems[i].summary);
105 printf("\n");
106}
107
108static int bench_str2int(char *str)
109{
110 if (!str)
111 return BENCH_FORMAT_DEFAULT;
112
113 if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
114 return BENCH_FORMAT_DEFAULT;
115 else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
116 return BENCH_FORMAT_SIMPLE;
117
118 return BENCH_FORMAT_UNKNOWN;
119}
120
121int cmd_bench(int argc, const char **argv, const char *prefix __used)
122{
123 int i, j, status = 0;
124
125 if (argc < 2) {
126 /* No subsystem specified. */
127 print_usage();
128 goto end;
129 }
130
131 argc = parse_options(argc, argv, bench_options, bench_usage,
132 PARSE_OPT_STOP_AT_NON_OPTION);
133
134 bench_format = bench_str2int(bench_format_str);
135 if (bench_format == BENCH_FORMAT_UNKNOWN) {
136 printf("Unknown format descriptor:%s\n", bench_format_str);
137 goto end;
138 }
139
140 if (argc < 1) {
141 print_usage();
142 goto end;
143 }
144
145 for (i = 0; subsystems[i].name; i++) {
146 if (strcmp(subsystems[i].name, argv[0]))
147 continue;
148
149 if (argc < 2) {
150 /* No suite specified. */
151 dump_suites(i);
152 goto end;
153 }
154
155 for (j = 0; subsystems[i].suites[j].name; j++) {
156 if (strcmp(subsystems[i].suites[j].name, argv[1]))
157 continue;
158
159 if (bench_format == BENCH_FORMAT_DEFAULT)
160 printf("# Running %s/%s benchmark...\n",
161 subsystems[i].name,
162 subsystems[i].suites[j].name);
163 status = subsystems[i].suites[j].fn(argc - 1,
164 argv + 1, prefix);
165 goto end;
166 }
167
168 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
169 dump_suites(i);
170 goto end;
171 }
172
173 printf("Unknown suite:%s for %s\n", argv[1], argv[0]);
174 status = 1;
175 goto end;
176 }
177
178 printf("Unknown subsystem:%s\n", argv[0]);
179 status = 1;
180
181end:
182 return status;
183}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
new file mode 100644
index 000000000000..7dee9d19ab7a
--- /dev/null
+++ b/tools/perf/builtin-buildid-list.c
@@ -0,0 +1,116 @@
1/*
2 * builtin-buildid-list.c
3 *
4 * Builtin buildid-list command: list buildids in perf.data
5 *
6 * Copyright (C) 2009, Red Hat Inc.
7 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "builtin.h"
10#include "perf.h"
11#include "util/cache.h"
12#include "util/data_map.h"
13#include "util/debug.h"
14#include "util/header.h"
15#include "util/parse-options.h"
16#include "util/symbol.h"
17
18static char const *input_name = "perf.data";
19static int force;
20
21static const char *const buildid_list_usage[] = {
22 "perf report [<options>]",
23 NULL
24};
25
26static const struct option options[] = {
27 OPT_STRING('i', "input", &input_name, "file",
28 "input file name"),
29 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
30 OPT_BOOLEAN('v', "verbose", &verbose,
31 "be more verbose"),
32 OPT_END()
33};
34
35static int perf_file_section__process_buildids(struct perf_file_section *self,
36 int feat, int fd)
37{
38 if (feat != HEADER_BUILD_ID)
39 return 0;
40
41 if (lseek(fd, self->offset, SEEK_SET) < 0) {
42 pr_warning("Failed to lseek to %Ld offset for buildids!\n",
43 self->offset);
44 return -1;
45 }
46
47 if (perf_header__read_build_ids(fd, self->offset, self->size)) {
48 pr_warning("Failed to read buildids!\n");
49 return -1;
50 }
51
52 return 0;
53}
54
55static int __cmd_buildid_list(void)
56{
57 int err = -1;
58 struct perf_header *header;
59 struct perf_file_header f_header;
60 struct stat input_stat;
61 int input = open(input_name, O_RDONLY);
62
63 if (input < 0) {
64 pr_err("failed to open file: %s", input_name);
65 if (!strcmp(input_name, "perf.data"))
66 pr_err(" (try 'perf record' first)");
67 pr_err("\n");
68 goto out;
69 }
70
71 err = fstat(input, &input_stat);
72 if (err < 0) {
73 perror("failed to stat file");
74 goto out_close;
75 }
76
77 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
78 pr_err("file %s not owned by current user or root\n",
79 input_name);
80 goto out_close;
81 }
82
83 if (!input_stat.st_size) {
84 pr_info("zero-sized file, nothing to do!\n");
85 goto out_close;
86 }
87
88 err = -1;
89 header = perf_header__new();
90 if (header == NULL)
91 goto out_close;
92
93 if (perf_file_header__read(&f_header, header, input) < 0) {
94 pr_warning("incompatible file format");
95 goto out_close;
96 }
97
98 err = perf_header__process_sections(header, input,
99 perf_file_section__process_buildids);
100
101 if (err < 0)
102 goto out_close;
103
104 dsos__fprintf_buildid(stdout);
105out_close:
106 close(input);
107out:
108 return err;
109}
110
111int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
112{
113 argc = parse_options(argc, argv, options, buildid_list_usage, 0);
114 setup_pager();
115 return __cmd_buildid_list();
116}
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 4fb8734a796e..768f9c826312 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -61,8 +61,7 @@ static const char *get_man_viewer_info(const char *name)
61{ 61{
62 struct man_viewer_info_list *viewer; 62 struct man_viewer_info_list *viewer;
63 63
64 for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) 64 for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) {
65 {
66 if (!strcasecmp(name, viewer->name)) 65 if (!strcasecmp(name, viewer->name))
67 return viewer->info; 66 return viewer->info;
68 } 67 }
@@ -115,7 +114,7 @@ static int check_emacsclient_version(void)
115 return 0; 114 return 0;
116} 115}
117 116
118static void exec_woman_emacs(const char* path, const char *page) 117static void exec_woman_emacs(const char *path, const char *page)
119{ 118{
120 if (!check_emacsclient_version()) { 119 if (!check_emacsclient_version()) {
121 /* This works only with emacsclient version >= 22. */ 120 /* This works only with emacsclient version >= 22. */
@@ -129,7 +128,7 @@ static void exec_woman_emacs(const char* path, const char *page)
129 } 128 }
130} 129}
131 130
132static void exec_man_konqueror(const char* path, const char *page) 131static void exec_man_konqueror(const char *path, const char *page)
133{ 132{
134 const char *display = getenv("DISPLAY"); 133 const char *display = getenv("DISPLAY");
135 if (display && *display) { 134 if (display && *display) {
@@ -157,7 +156,7 @@ static void exec_man_konqueror(const char* path, const char *page)
157 } 156 }
158} 157}
159 158
160static void exec_man_man(const char* path, const char *page) 159static void exec_man_man(const char *path, const char *page)
161{ 160{
162 if (!path) 161 if (!path)
163 path = "man"; 162 path = "man";
@@ -364,9 +363,8 @@ static void show_man_page(const char *perf_cmd)
364 363
365 setup_man_path(); 364 setup_man_path();
366 for (viewer = man_viewer_list; viewer; viewer = viewer->next) 365 for (viewer = man_viewer_list; viewer; viewer = viewer->next)
367 {
368 exec_viewer(viewer->name, page); /* will return when unable */ 366 exec_viewer(viewer->name, page); /* will return when unable */
369 } 367
370 if (fallback) 368 if (fallback)
371 exec_viewer(fallback, page); 369 exec_viewer(fallback, page);
372 exec_viewer("man", page); 370 exec_viewer("man", page);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ac5ddfff4456..82260c56db3d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -17,6 +17,7 @@
17#include "util/header.h" 17#include "util/header.h"
18#include "util/event.h" 18#include "util/event.h"
19#include "util/debug.h" 19#include "util/debug.h"
20#include "util/symbol.h"
20 21
21#include <unistd.h> 22#include <unistd.h>
22#include <sched.h> 23#include <sched.h>
@@ -109,6 +110,24 @@ static void write_output(void *buf, size_t size)
109 } 110 }
110} 111}
111 112
113static void write_event(event_t *buf, size_t size)
114{
115 /*
116 * Add it to the list of DSOs, so that when we finish this
117 * record session we can pick the available build-ids.
118 */
119 if (buf->header.type == PERF_RECORD_MMAP)
120 dsos__findnew(buf->mmap.filename);
121
122 write_output(buf, size);
123}
124
125static int process_synthesized_event(event_t *event)
126{
127 write_event(event, event->header.size);
128 return 0;
129}
130
112static void mmap_read(struct mmap_data *md) 131static void mmap_read(struct mmap_data *md)
113{ 132{
114 unsigned int head = mmap_read_head(md); 133 unsigned int head = mmap_read_head(md);
@@ -157,14 +176,14 @@ static void mmap_read(struct mmap_data *md)
157 size = md->mask + 1 - (old & md->mask); 176 size = md->mask + 1 - (old & md->mask);
158 old += size; 177 old += size;
159 178
160 write_output(buf, size); 179 write_event(buf, size);
161 } 180 }
162 181
163 buf = &data[old & md->mask]; 182 buf = &data[old & md->mask];
164 size = head - old; 183 size = head - old;
165 old += size; 184 old += size;
166 185
167 write_output(buf, size); 186 write_event(buf, size);
168 187
169 md->prev = old; 188 md->prev = old;
170 mmap_write_tail(md, old); 189 mmap_write_tail(md, old);
@@ -191,168 +210,6 @@ static void sig_atexit(void)
191 kill(getpid(), signr); 210 kill(getpid(), signr);
192} 211}
193 212
194static pid_t pid_synthesize_comm_event(pid_t pid, int full)
195{
196 struct comm_event comm_ev;
197 char filename[PATH_MAX];
198 char bf[BUFSIZ];
199 FILE *fp;
200 size_t size = 0;
201 DIR *tasks;
202 struct dirent dirent, *next;
203 pid_t tgid = 0;
204
205 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
206
207 fp = fopen(filename, "r");
208 if (fp == NULL) {
209 /*
210 * We raced with a task exiting - just return:
211 */
212 if (verbose)
213 fprintf(stderr, "couldn't open %s\n", filename);
214 return 0;
215 }
216
217 memset(&comm_ev, 0, sizeof(comm_ev));
218 while (!comm_ev.comm[0] || !comm_ev.pid) {
219 if (fgets(bf, sizeof(bf), fp) == NULL)
220 goto out_failure;
221
222 if (memcmp(bf, "Name:", 5) == 0) {
223 char *name = bf + 5;
224 while (*name && isspace(*name))
225 ++name;
226 size = strlen(name) - 1;
227 memcpy(comm_ev.comm, name, size++);
228 } else if (memcmp(bf, "Tgid:", 5) == 0) {
229 char *tgids = bf + 5;
230 while (*tgids && isspace(*tgids))
231 ++tgids;
232 tgid = comm_ev.pid = atoi(tgids);
233 }
234 }
235
236 comm_ev.header.type = PERF_RECORD_COMM;
237 size = ALIGN(size, sizeof(u64));
238 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
239
240 if (!full) {
241 comm_ev.tid = pid;
242
243 write_output(&comm_ev, comm_ev.header.size);
244 goto out_fclose;
245 }
246
247 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
248
249 tasks = opendir(filename);
250 while (!readdir_r(tasks, &dirent, &next) && next) {
251 char *end;
252 pid = strtol(dirent.d_name, &end, 10);
253 if (*end)
254 continue;
255
256 comm_ev.tid = pid;
257
258 write_output(&comm_ev, comm_ev.header.size);
259 }
260 closedir(tasks);
261
262out_fclose:
263 fclose(fp);
264 return tgid;
265
266out_failure:
267 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
268 filename);
269 exit(EXIT_FAILURE);
270}
271
272static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
273{
274 char filename[PATH_MAX];
275 FILE *fp;
276
277 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
278
279 fp = fopen(filename, "r");
280 if (fp == NULL) {
281 /*
282 * We raced with a task exiting - just return:
283 */
284 if (verbose)
285 fprintf(stderr, "couldn't open %s\n", filename);
286 return;
287 }
288 while (1) {
289 char bf[BUFSIZ], *pbf = bf;
290 struct mmap_event mmap_ev = {
291 .header = { .type = PERF_RECORD_MMAP },
292 };
293 int n;
294 size_t size;
295 if (fgets(bf, sizeof(bf), fp) == NULL)
296 break;
297
298 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
299 n = hex2u64(pbf, &mmap_ev.start);
300 if (n < 0)
301 continue;
302 pbf += n + 1;
303 n = hex2u64(pbf, &mmap_ev.len);
304 if (n < 0)
305 continue;
306 pbf += n + 3;
307 if (*pbf == 'x') { /* vm_exec */
308 char *execname = strchr(bf, '/');
309
310 /* Catch VDSO */
311 if (execname == NULL)
312 execname = strstr(bf, "[vdso]");
313
314 if (execname == NULL)
315 continue;
316
317 size = strlen(execname);
318 execname[size - 1] = '\0'; /* Remove \n */
319 memcpy(mmap_ev.filename, execname, size);
320 size = ALIGN(size, sizeof(u64));
321 mmap_ev.len -= mmap_ev.start;
322 mmap_ev.header.size = (sizeof(mmap_ev) -
323 (sizeof(mmap_ev.filename) - size));
324 mmap_ev.pid = tgid;
325 mmap_ev.tid = pid;
326
327 write_output(&mmap_ev, mmap_ev.header.size);
328 }
329 }
330
331 fclose(fp);
332}
333
334static void synthesize_all(void)
335{
336 DIR *proc;
337 struct dirent dirent, *next;
338
339 proc = opendir("/proc");
340
341 while (!readdir_r(proc, &dirent, &next) && next) {
342 char *end;
343 pid_t pid, tgid;
344
345 pid = strtol(dirent.d_name, &end, 10);
346 if (*end) /* only interested in proper numerical dirents */
347 continue;
348
349 tgid = pid_synthesize_comm_event(pid, 1);
350 pid_synthesize_mmap_samples(pid, tgid);
351 }
352
353 closedir(proc);
354}
355
356static int group_fd; 213static int group_fd;
357 214
358static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) 215static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
@@ -363,7 +220,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
363 h_attr = header->attr[nr]; 220 h_attr = header->attr[nr];
364 } else { 221 } else {
365 h_attr = perf_header_attr__new(a); 222 h_attr = perf_header_attr__new(a);
366 perf_header__add_attr(header, h_attr); 223 if (h_attr != NULL)
224 if (perf_header__add_attr(header, h_attr) < 0) {
225 perf_header_attr__delete(h_attr);
226 h_attr = NULL;
227 }
367 } 228 }
368 229
369 return h_attr; 230 return h_attr;
@@ -424,7 +285,7 @@ try_again:
424 if (fd[nr_cpu][counter] < 0) { 285 if (fd[nr_cpu][counter] < 0) {
425 int err = errno; 286 int err = errno;
426 287
427 if (err == EPERM) 288 if (err == EPERM || err == EACCES)
428 die("Permission error - are you root?\n"); 289 die("Permission error - are you root?\n");
429 else if (err == ENODEV && profile_cpu != -1) 290 else if (err == ENODEV && profile_cpu != -1)
430 die("No such device - did you specify an out-of-range profile CPU?\n"); 291 die("No such device - did you specify an out-of-range profile CPU?\n");
@@ -451,6 +312,8 @@ try_again:
451 } 312 }
452 313
453 h_attr = get_header_attr(attr, counter); 314 h_attr = get_header_attr(attr, counter);
315 if (h_attr == NULL)
316 die("nomem\n");
454 317
455 if (!file_new) { 318 if (!file_new) {
456 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 319 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
@@ -464,7 +327,10 @@ try_again:
464 exit(-1); 327 exit(-1);
465 } 328 }
466 329
467 perf_header_attr__add_id(h_attr, read_data.id); 330 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
331 pr_warning("Not enough memory to add id\n");
332 exit(-1);
333 }
468 334
469 assert(fd[nr_cpu][counter] >= 0); 335 assert(fd[nr_cpu][counter] >= 0);
470 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 336 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
@@ -525,7 +391,7 @@ static void atexit_header(void)
525{ 391{
526 header->data_size += bytes_written; 392 header->data_size += bytes_written;
527 393
528 perf_header__write(header, output); 394 perf_header__write(header, output, true);
529} 395}
530 396
531static int __cmd_record(int argc, const char **argv) 397static int __cmd_record(int argc, const char **argv)
@@ -573,12 +439,17 @@ static int __cmd_record(int argc, const char **argv)
573 else 439 else
574 header = perf_header__new(); 440 header = perf_header__new();
575 441
442 if (header == NULL) {
443 pr_err("Not enough memory for reading perf file header\n");
444 return -1;
445 }
446
576 if (raw_samples) { 447 if (raw_samples) {
577 perf_header__feat_trace_info(header); 448 perf_header__set_feat(header, HEADER_TRACE_INFO);
578 } else { 449 } else {
579 for (i = 0; i < nr_counters; i++) { 450 for (i = 0; i < nr_counters; i++) {
580 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 451 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
581 perf_header__feat_trace_info(header); 452 perf_header__set_feat(header, HEADER_TRACE_INFO);
582 break; 453 break;
583 } 454 }
584 } 455 }
@@ -602,24 +473,32 @@ static int __cmd_record(int argc, const char **argv)
602 } 473 }
603 474
604 if (file_new) 475 if (file_new)
605 perf_header__write(header, output); 476 perf_header__write(header, output, false);
606 477
607 if (!system_wide) { 478 if (!system_wide)
608 pid_t tgid = pid_synthesize_comm_event(pid, 0); 479 event__synthesize_thread(pid, process_synthesized_event);
609 pid_synthesize_mmap_samples(pid, tgid); 480 else
610 } else 481 event__synthesize_threads(process_synthesized_event);
611 synthesize_all();
612 482
613 if (target_pid == -1 && argc) { 483 if (target_pid == -1 && argc) {
614 pid = fork(); 484 pid = fork();
615 if (pid < 0) 485 if (pid < 0)
616 perror("failed to fork"); 486 die("failed to fork");
617 487
618 if (!pid) { 488 if (!pid) {
619 if (execvp(argv[0], (char **)argv)) { 489 if (execvp(argv[0], (char **)argv)) {
620 perror(argv[0]); 490 perror(argv[0]);
621 exit(-1); 491 exit(-1);
622 } 492 }
493 } else {
494 /*
495 * Wait a bit for the execv'ed child to appear
496 * and be updated in /proc
497 * FIXME: Do you know a less heuristical solution?
498 */
499 usleep(1000);
500 event__synthesize_thread(pid,
501 process_synthesized_event);
623 } 502 }
624 503
625 child_pid = pid; 504 child_pid = pid;
@@ -729,6 +608,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
729{ 608{
730 int counter; 609 int counter;
731 610
611 symbol__init(0);
612
732 argc = parse_options(argc, argv, options, record_usage, 613 argc = parse_options(argc, argv, options, record_usage,
733 PARSE_OPT_STOP_AT_NON_OPTION); 614 PARSE_OPT_STOP_AT_NON_OPTION);
734 if (!argc && target_pid == -1 && !system_wide) 615 if (!argc && target_pid == -1 && !system_wide)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index b3d814b54555..1a806d5f05cf 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -455,7 +455,7 @@ got_map:
455 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); 455 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
456 *ipp = ip; 456 *ipp = ip;
457 457
458 return map ? map->dso->find_symbol(map->dso, ip) : NULL; 458 return map ? map__find_symbol(map, ip, NULL) : NULL;
459} 459}
460 460
461static int call__match(struct symbol *sym) 461static int call__match(struct symbol *sym)
@@ -751,7 +751,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
751static int 751static int
752process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 752process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
753{ 753{
754 struct map *map = map__new(&event->mmap, cwd, cwdlen, 0, NULL); 754 struct map *map = map__new(&event->mmap, cwd, cwdlen);
755 struct thread *thread = threads__findnew(event->mmap.pid); 755 struct thread *thread = threads__findnew(event->mmap.pid);
756 756
757 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n", 757 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
@@ -1093,7 +1093,7 @@ static void setup_list(struct strlist **list, const char *list_str,
1093 1093
1094int cmd_report(int argc, const char **argv, const char *prefix __used) 1094int cmd_report(int argc, const char **argv, const char *prefix __used)
1095{ 1095{
1096 symbol__init(); 1096 symbol__init(0);
1097 1097
1098 argc = parse_options(argc, argv, options, report_usage, 0); 1098 argc = parse_options(argc, argv, options, report_usage, 0);
1099 1099
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 9a48d9626be4..df44b756cecc 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1937,7 +1937,7 @@ static int __cmd_record(int argc, const char **argv)
1937 1937
1938int cmd_sched(int argc, const char **argv, const char *prefix __used) 1938int cmd_sched(int argc, const char **argv, const char *prefix __used)
1939{ 1939{
1940 symbol__init(); 1940 symbol__init(0);
1941 1941
1942 argc = parse_options(argc, argv, sched_options, sched_usage, 1942 argc = parse_options(argc, argv, sched_options, sched_usage,
1943 PARSE_OPT_STOP_AT_NON_OPTION); 1943 PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c6df3770b87e..c70d72003557 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -357,7 +357,8 @@ static void abs_printout(int counter, double avg)
357 ratio = avg / total; 357 ratio = avg / total;
358 358
359 fprintf(stderr, " # %10.3f IPC ", ratio); 359 fprintf(stderr, " # %10.3f IPC ", ratio);
360 } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter)) { 360 } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) &&
361 runtime_branches_stats.n != 0) {
361 total = avg_stats(&runtime_branches_stats); 362 total = avg_stats(&runtime_branches_stats);
362 363
363 if (total) 364 if (total)
@@ -365,7 +366,7 @@ static void abs_printout(int counter, double avg)
365 366
366 fprintf(stderr, " # %10.3f %% ", ratio); 367 fprintf(stderr, " # %10.3f %% ", ratio);
367 368
368 } else { 369 } else if (runtime_nsecs_stats.n != 0) {
369 total = avg_stats(&runtime_nsecs_stats); 370 total = avg_stats(&runtime_nsecs_stats);
370 371
371 if (total) 372 if (total)
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 0a2f22261c3a..665877e4a944 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1266,7 +1266,7 @@ static const struct option options[] = {
1266 1266
1267int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1267int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1268{ 1268{
1269 symbol__init(); 1269 symbol__init(0);
1270 1270
1271 page_size = getpagesize(); 1271 page_size = getpagesize();
1272 1272
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 4a9fe228be2a..89b7f68a1799 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -60,7 +60,7 @@ static int system_wide = 0;
60static int default_interval = 0; 60static int default_interval = 0;
61 61
62static int count_filter = 5; 62static int count_filter = 5;
63static int print_entries = 15; 63static int print_entries;
64 64
65static int target_pid = -1; 65static int target_pid = -1;
66static int inherit = 0; 66static int inherit = 0;
@@ -76,6 +76,9 @@ static int delay_secs = 2;
76static int zero = 0; 76static int zero = 0;
77static int dump_symtab = 0; 77static int dump_symtab = 0;
78 78
79static bool hide_kernel_symbols = false;
80static bool hide_user_symbols = false;
81
79/* 82/*
80 * Source 83 * Source
81 */ 84 */
@@ -104,6 +107,7 @@ struct sym_entry {
104 unsigned long snap_count; 107 unsigned long snap_count;
105 double weight; 108 double weight;
106 int skip; 109 int skip;
110 u8 origin;
107 struct map *map; 111 struct map *map;
108 struct source_line *source; 112 struct source_line *source;
109 struct source_line *lines; 113 struct source_line *lines;
@@ -115,6 +119,36 @@ struct sym_entry {
115 * Source functions 119 * Source functions
116 */ 120 */
117 121
122/* most GUI terminals set LINES (although some don't export it) */
123static int term_rows(void)
124{
125 char *lines_string = getenv("LINES");
126 int n_lines;
127
128 if (lines_string && (n_lines = atoi(lines_string)) > 0)
129 return n_lines;
130#ifdef TIOCGWINSZ
131 else {
132 struct winsize ws;
133 if (!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_row)
134 return ws.ws_row;
135 }
136#endif
137 return 25;
138}
139
140static void update_print_entries(void)
141{
142 print_entries = term_rows();
143 if (print_entries > 9)
144 print_entries -= 9;
145}
146
147static void sig_winch_handler(int sig __used)
148{
149 update_print_entries();
150}
151
118static void parse_source(struct sym_entry *syme) 152static void parse_source(struct sym_entry *syme)
119{ 153{
120 struct symbol *sym; 154 struct symbol *sym;
@@ -318,7 +352,7 @@ static void show_details(struct sym_entry *syme)
318} 352}
319 353
320/* 354/*
321 * Symbols will be added here in record_ip and will get out 355 * Symbols will be added here in event__process_sample and will get out
322 * after decayed. 356 * after decayed.
323 */ 357 */
324static LIST_HEAD(active_symbols); 358static LIST_HEAD(active_symbols);
@@ -400,6 +434,13 @@ static void print_sym_table(void)
400 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 434 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
401 syme->snap_count = syme->count[snap]; 435 syme->snap_count = syme->count[snap];
402 if (syme->snap_count != 0) { 436 if (syme->snap_count != 0) {
437 if ((hide_user_symbols &&
438 syme->origin == PERF_RECORD_MISC_USER) ||
439 (hide_kernel_symbols &&
440 syme->origin == PERF_RECORD_MISC_KERNEL)) {
441 list_remove_active_sym(syme);
442 continue;
443 }
403 syme->weight = sym_weight(syme); 444 syme->weight = sym_weight(syme);
404 rb_insert_active_sym(&tmp, syme); 445 rb_insert_active_sym(&tmp, syme);
405 sum_ksamples += syme->snap_count; 446 sum_ksamples += syme->snap_count;
@@ -459,18 +500,18 @@ static void print_sym_table(void)
459 } 500 }
460 501
461 if (nr_counters == 1) 502 if (nr_counters == 1)
462 printf(" samples pcnt"); 503 printf(" samples pcnt");
463 else 504 else
464 printf(" weight samples pcnt"); 505 printf(" weight samples pcnt");
465 506
466 if (verbose) 507 if (verbose)
467 printf(" RIP "); 508 printf(" RIP ");
468 printf(" kernel function\n"); 509 printf(" function DSO\n");
469 printf(" %s _______ _____", 510 printf(" %s _______ _____",
470 nr_counters == 1 ? " " : "______"); 511 nr_counters == 1 ? " " : "______");
471 if (verbose) 512 if (verbose)
472 printf(" ________________"); 513 printf(" ________________");
473 printf(" _______________\n\n"); 514 printf(" ________________________________ ________________\n\n");
474 515
475 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 516 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
476 struct symbol *sym; 517 struct symbol *sym;
@@ -486,16 +527,15 @@ static void print_sym_table(void)
486 sum_ksamples)); 527 sum_ksamples));
487 528
488 if (nr_counters == 1 || !display_weighted) 529 if (nr_counters == 1 || !display_weighted)
489 printf("%20.2f - ", syme->weight); 530 printf("%20.2f ", syme->weight);
490 else 531 else
491 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 532 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
492 533
493 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 534 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
494 if (verbose) 535 if (verbose)
495 printf(" - %016llx", sym->start); 536 printf(" %016llx", sym->start);
496 printf(" : %s", sym->name); 537 printf(" %-32s", sym->name);
497 if (syme->map->dso->name[0] == '[') 538 printf(" %s", syme->map->dso->short_name);
498 printf(" \t%s", syme->map->dso->name);
499 printf("\n"); 539 printf("\n");
500 } 540 }
501} 541}
@@ -608,6 +648,12 @@ static void print_mapped_keys(void)
608 if (nr_counters > 1) 648 if (nr_counters > 1)
609 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 649 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
610 650
651 fprintf(stdout,
652 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
653 hide_kernel_symbols ? "yes" : "no");
654 fprintf(stdout,
655 "\t[U] hide user symbols. \t(%s)\n",
656 hide_user_symbols ? "yes" : "no");
611 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); 657 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0);
612 fprintf(stdout, "\t[qQ] quit.\n"); 658 fprintf(stdout, "\t[qQ] quit.\n");
613} 659}
@@ -621,6 +667,8 @@ static int key_mapped(int c)
621 case 'z': 667 case 'z':
622 case 'q': 668 case 'q':
623 case 'Q': 669 case 'Q':
670 case 'K':
671 case 'U':
624 return 1; 672 return 1;
625 case 'E': 673 case 'E':
626 case 'w': 674 case 'w':
@@ -669,6 +717,11 @@ static void handle_keypress(int c)
669 break; 717 break;
670 case 'e': 718 case 'e':
671 prompt_integer(&print_entries, "Enter display entries (lines)"); 719 prompt_integer(&print_entries, "Enter display entries (lines)");
720 if (print_entries == 0) {
721 update_print_entries();
722 signal(SIGWINCH, sig_winch_handler);
723 } else
724 signal(SIGWINCH, SIG_DFL);
672 break; 725 break;
673 case 'E': 726 case 'E':
674 if (nr_counters > 1) { 727 if (nr_counters > 1) {
@@ -693,6 +746,9 @@ static void handle_keypress(int c)
693 case 'F': 746 case 'F':
694 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 747 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
695 break; 748 break;
749 case 'K':
750 hide_kernel_symbols = !hide_kernel_symbols;
751 break;
696 case 'q': 752 case 'q':
697 case 'Q': 753 case 'Q':
698 printf("exiting.\n"); 754 printf("exiting.\n");
@@ -712,6 +768,9 @@ static void handle_keypress(int c)
712 pthread_mutex_unlock(&syme->source_lock); 768 pthread_mutex_unlock(&syme->source_lock);
713 } 769 }
714 break; 770 break;
771 case 'U':
772 hide_user_symbols = !hide_user_symbols;
773 break;
715 case 'w': 774 case 'w':
716 display_weighted = ~display_weighted; 775 display_weighted = ~display_weighted;
717 break; 776 break;
@@ -790,7 +849,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
790 strstr(name, "_text_end")) 849 strstr(name, "_text_end"))
791 return 1; 850 return 1;
792 851
793 syme = dso__sym_priv(map->dso, sym); 852 syme = symbol__priv(sym);
794 syme->map = map; 853 syme->map = map;
795 pthread_mutex_init(&syme->source_lock, NULL); 854 pthread_mutex_init(&syme->source_lock, NULL);
796 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 855 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
@@ -808,8 +867,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
808 867
809static int parse_symbols(void) 868static int parse_symbols(void)
810{ 869{
811 if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry), 870 if (dsos__load_kernel(vmlinux_name, symbol_filter, 1) <= 0)
812 symbol_filter, 1) <= 0)
813 return -1; 871 return -1;
814 872
815 if (dump_symtab) 873 if (dump_symtab)
@@ -818,41 +876,104 @@ static int parse_symbols(void)
818 return 0; 876 return 0;
819} 877}
820 878
821/* 879static void event__process_sample(const event_t *self, int counter)
822 * Binary search in the histogram table and record the hit:
823 */
824static void record_ip(u64 ip, int counter)
825{ 880{
881 u64 ip = self->ip.ip;
826 struct map *map; 882 struct map *map;
827 struct symbol *sym = kernel_maps__find_symbol(ip, &map); 883 struct sym_entry *syme;
828 884 struct symbol *sym;
829 if (sym != NULL) { 885 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
830 struct sym_entry *syme = dso__sym_priv(map->dso, sym); 886
831 887 switch (origin) {
832 if (!syme->skip) { 888 case PERF_RECORD_MISC_USER: {
833 syme->count[counter]++; 889 struct thread *thread;
834 record_precise_ip(syme, counter, ip); 890
835 pthread_mutex_lock(&active_symbols_lock); 891 if (hide_user_symbols)
836 if (list_empty(&syme->node) || !syme->node.next) 892 return;
837 __list_insert_active_sym(syme); 893
838 pthread_mutex_unlock(&active_symbols_lock); 894 thread = threads__findnew(self->ip.pid);
895 if (thread == NULL)
839 return; 896 return;
897
898 map = thread__find_map(thread, ip);
899 if (map != NULL) {
900 ip = map->map_ip(map, ip);
901 sym = map__find_symbol(map, ip, symbol_filter);
902 if (sym == NULL)
903 return;
904 userspace_samples++;
905 break;
840 } 906 }
841 } 907 }
908 /*
909 * If this is outside of all known maps,
910 * and is a negative address, try to look it
911 * up in the kernel dso, as it might be a
912 * vsyscall or vdso (which executes in user-mode).
913 */
914 if ((long long)ip >= 0)
915 return;
916 /* Fall thru */
917 case PERF_RECORD_MISC_KERNEL:
918 if (hide_kernel_symbols)
919 return;
920
921 sym = kernel_maps__find_symbol(ip, &map);
922 if (sym == NULL)
923 return;
924 break;
925 default:
926 return;
927 }
842 928
843 samples--; 929 syme = symbol__priv(sym);
930
931 if (!syme->skip) {
932 syme->count[counter]++;
933 syme->origin = origin;
934 record_precise_ip(syme, counter, ip);
935 pthread_mutex_lock(&active_symbols_lock);
936 if (list_empty(&syme->node) || !syme->node.next)
937 __list_insert_active_sym(syme);
938 pthread_mutex_unlock(&active_symbols_lock);
939 ++samples;
940 return;
941 }
844} 942}
845 943
846static void process_event(u64 ip, int counter, int user) 944static void event__process_mmap(event_t *self)
847{ 945{
848 samples++; 946 struct thread *thread = threads__findnew(self->mmap.pid);
849 947
850 if (user) { 948 if (thread != NULL) {
851 userspace_samples++; 949 struct map *map = map__new(&self->mmap, NULL, 0);
852 return; 950 if (map != NULL)
951 thread__insert_map(thread, map);
853 } 952 }
953}
854 954
855 record_ip(ip, counter); 955static void event__process_comm(event_t *self)
956{
957 struct thread *thread = threads__findnew(self->comm.pid);
958
959 if (thread != NULL)
960 thread__set_comm(thread, self->comm.comm);
961}
962
963static int event__process(event_t *event)
964{
965 switch (event->header.type) {
966 case PERF_RECORD_COMM:
967 event__process_comm(event);
968 break;
969 case PERF_RECORD_MMAP:
970 event__process_mmap(event);
971 break;
972 default:
973 break;
974 }
975
976 return 0;
856} 977}
857 978
858struct mmap_data { 979struct mmap_data {
@@ -925,13 +1046,11 @@ static void mmap_read_counter(struct mmap_data *md)
925 event = &event_copy; 1046 event = &event_copy;
926 } 1047 }
927 1048
1049 if (event->header.type == PERF_RECORD_SAMPLE)
1050 event__process_sample(event, md->counter);
1051 else
1052 event__process(event);
928 old += size; 1053 old += size;
929
930 if (event->header.type == PERF_RECORD_SAMPLE) {
931 int user =
932 (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
933 process_event(event->ip.ip, md->counter, user);
934 }
935 } 1054 }
936 1055
937 md->prev = old; 1056 md->prev = old;
@@ -973,6 +1092,7 @@ static void start_counter(int i, int counter)
973 } 1092 }
974 1093
975 attr->inherit = (cpu < 0) && inherit; 1094 attr->inherit = (cpu < 0) && inherit;
1095 attr->mmap = 1;
976 1096
977try_again: 1097try_again:
978 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); 1098 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
@@ -980,7 +1100,7 @@ try_again:
980 if (fd[i][counter] < 0) { 1100 if (fd[i][counter] < 0) {
981 int err = errno; 1101 int err = errno;
982 1102
983 if (err == EPERM) 1103 if (err == EPERM || err == EACCES)
984 die("No permission - are you root?\n"); 1104 die("No permission - are you root?\n");
985 /* 1105 /*
986 * If it's cycles then fall back to hrtimer 1106 * If it's cycles then fall back to hrtimer
@@ -1031,6 +1151,11 @@ static int __cmd_top(void)
1031 int i, counter; 1151 int i, counter;
1032 int ret; 1152 int ret;
1033 1153
1154 if (target_pid != -1)
1155 event__synthesize_thread(target_pid, event__process);
1156 else
1157 event__synthesize_threads(event__process);
1158
1034 for (i = 0; i < nr_cpus; i++) { 1159 for (i = 0; i < nr_cpus; i++) {
1035 group_fd = -1; 1160 group_fd = -1;
1036 for (counter = 0; counter < nr_counters; counter++) 1161 for (counter = 0; counter < nr_counters; counter++)
@@ -1087,6 +1212,8 @@ static const struct option options[] = {
1087 OPT_INTEGER('C', "CPU", &profile_cpu, 1212 OPT_INTEGER('C', "CPU", &profile_cpu,
1088 "CPU to profile on"), 1213 "CPU to profile on"),
1089 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 1214 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
1215 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
1216 "hide kernel symbols"),
1090 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1217 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
1091 "number of mmap data pages"), 1218 "number of mmap data pages"),
1092 OPT_INTEGER('r', "realtime", &realtime_prio, 1219 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -1109,6 +1236,8 @@ static const struct option options[] = {
1109 "profile at this frequency"), 1236 "profile at this frequency"),
1110 OPT_INTEGER('E', "entries", &print_entries, 1237 OPT_INTEGER('E', "entries", &print_entries,
1111 "display this many functions"), 1238 "display this many functions"),
1239 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
1240 "hide user symbols"),
1112 OPT_BOOLEAN('v', "verbose", &verbose, 1241 OPT_BOOLEAN('v', "verbose", &verbose,
1113 "be more verbose (show counter open errors, etc)"), 1242 "be more verbose (show counter open errors, etc)"),
1114 OPT_END() 1243 OPT_END()
@@ -1118,7 +1247,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1118{ 1247{
1119 int counter; 1248 int counter;
1120 1249
1121 symbol__init(); 1250 symbol__init(sizeof(struct sym_entry));
1122 1251
1123 page_size = sysconf(_SC_PAGE_SIZE); 1252 page_size = sysconf(_SC_PAGE_SIZE);
1124 1253
@@ -1172,5 +1301,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1172 if (target_pid != -1 || profile_cpu != -1) 1301 if (target_pid != -1 || profile_cpu != -1)
1173 nr_cpus = 1; 1302 nr_cpus = 1;
1174 1303
1304 if (print_entries == 0) {
1305 update_print_entries();
1306 signal(SIGWINCH, sig_winch_handler);
1307 }
1308
1175 return __cmd_top(); 1309 return __cmd_top();
1176} 1310}
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index e566bbe3f22d..d042d656c561 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -151,7 +151,7 @@ static const struct option options[] = {
151 151
152int cmd_trace(int argc, const char **argv, const char *prefix __used) 152int cmd_trace(int argc, const char **argv, const char *prefix __used)
153{ 153{
154 symbol__init(); 154 symbol__init(0);
155 155
156 argc = parse_options(argc, argv, options, annotate_usage, 0); 156 argc = parse_options(argc, argv, options, annotate_usage, 0);
157 if (argc) { 157 if (argc) {
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index ad5f0f4c49ee..9b02d85091fe 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -15,6 +15,8 @@ extern int read_line_with_nul(char *buf, int size, FILE *file);
15extern int check_pager_config(const char *cmd); 15extern int check_pager_config(const char *cmd);
16 16
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_bench(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
18extern int cmd_help(int argc, const char **argv, const char *prefix); 20extern int cmd_help(int argc, const char **argv, const char *prefix);
19extern int cmd_sched(int argc, const char **argv, const char *prefix); 21extern int cmd_sched(int argc, const char **argv, const char *prefix);
20extern int cmd_list(int argc, const char **argv, const char *prefix); 22extern int cmd_list(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 6475db4f194c..d3a6e18e4a5e 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -3,6 +3,8 @@
3# command name category [deprecated] [common] 3# command name category [deprecated] [common]
4# 4#
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-bench mainporcelain common
7perf-buildid-list mainporcelain common
6perf-list mainporcelain common 8perf-list mainporcelain common
7perf-sched mainporcelain common 9perf-sched mainporcelain common
8perf-record mainporcelain common 10perf-record mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index fdd42a824c98..f000c30877ac 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -137,6 +137,8 @@ enum sw_event_ids {
137 PERF_COUNT_SW_CPU_MIGRATIONS = 4, 137 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, 138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
139 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, 139 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
140 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
141 PERF_COUNT_SW_EMULATION_FAULTS = 8,
140}; 142};
141 143
142Counters of the type PERF_TYPE_TRACEPOINT are available when the ftrace event 144Counters of the type PERF_TYPE_TRACEPOINT are available when the ftrace event
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 9cafe5463266..89b82acac7d9 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -14,6 +14,7 @@
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include "util/string.h" 16#include "util/string.h"
17#include "util/debugfs.h"
17 18
18const char perf_usage_string[] = 19const char perf_usage_string[] =
19 "perf [--version] [--help] COMMAND [ARGS]"; 20 "perf [--version] [--help] COMMAND [ARGS]";
@@ -286,8 +287,10 @@ static void handle_internal_command(int argc, const char **argv)
286 static struct cmd_struct commands[] = { 287 static struct cmd_struct commands[] = {
287 { "help", cmd_help, 0 }, 288 { "help", cmd_help, 0 },
288 { "list", cmd_list, 0 }, 289 { "list", cmd_list, 0 },
290 { "buildid-list", cmd_buildid_list, 0 },
289 { "record", cmd_record, 0 }, 291 { "record", cmd_record, 0 },
290 { "report", cmd_report, 0 }, 292 { "report", cmd_report, 0 },
293 { "bench", cmd_bench, 0 },
291 { "stat", cmd_stat, 0 }, 294 { "stat", cmd_stat, 0 },
292 { "timechart", cmd_timechart, 0 }, 295 { "timechart", cmd_timechart, 0 },
293 { "top", cmd_top, 0 }, 296 { "top", cmd_top, 0 },
@@ -383,45 +386,12 @@ static int run_argv(int *argcp, const char ***argv)
383/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ 386/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
384static void get_debugfs_mntpt(void) 387static void get_debugfs_mntpt(void)
385{ 388{
386 FILE *file; 389 const char *path = debugfs_find_mountpoint();
387 char fs_type[100];
388 char debugfs[MAXPATHLEN];
389 390
390 /* 391 if (path)
391 * try the standard location 392 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
392 */ 393 else
393 if (valid_debugfs_mount("/sys/kernel/debug/") == 0) { 394 debugfs_mntpt[0] = '\0';
394 strcpy(debugfs_mntpt, "/sys/kernel/debug/");
395 return;
396 }
397
398 /*
399 * try the sane location
400 */
401 if (valid_debugfs_mount("/debug/") == 0) {
402 strcpy(debugfs_mntpt, "/debug/");
403 return;
404 }
405
406 /*
407 * give up and parse /proc/mounts
408 */
409 file = fopen("/proc/mounts", "r");
410 if (file == NULL)
411 return;
412
413 while (fscanf(file, "%*s %"
414 STR(MAXPATHLEN)
415 "s %99s %*s %*d %*d\n",
416 debugfs, fs_type) == 2) {
417 if (strcmp(fs_type, "debugfs") == 0)
418 break;
419 }
420 fclose(file);
421 if (strcmp(fs_type, "debugfs") == 0) {
422 strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
423 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
424 }
425} 395}
426 396
427int main(int argc, const char **argv) 397int main(int argc, const char **argv)
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 8cc4623afd6f..216bdb223f63 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -47,6 +47,12 @@
47#define cpu_relax() asm volatile("":::"memory") 47#define cpu_relax() asm volatile("":::"memory")
48#endif 48#endif
49 49
50#ifdef __alpha__
51#include "../../arch/alpha/include/asm/unistd.h"
52#define rmb() asm volatile("mb" ::: "memory")
53#define cpu_relax() asm volatile("" ::: "memory")
54#endif
55
50#include <time.h> 56#include <time.h>
51#include <unistd.h> 57#include <unistd.h>
52#include <sys/types.h> 58#include <sys/types.h>
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index 18accb8fee4d..14cb8465eb08 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -70,6 +70,35 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
70 } 70 }
71} 71}
72 72
73int perf_header__read_build_ids(int input, off_t offset, off_t size)
74{
75 struct build_id_event bev;
76 char filename[PATH_MAX];
77 off_t limit = offset + size;
78 int err = -1;
79
80 while (offset < limit) {
81 struct dso *dso;
82 ssize_t len;
83
84 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
85 goto out;
86
87 len = bev.header.size - sizeof(bev);
88 if (read(input, filename, len) != len)
89 goto out;
90
91 dso = dsos__findnew(filename);
92 if (dso != NULL)
93 dso__set_build_id(dso, &bev.build_id);
94
95 offset += bev.header.size;
96 }
97 err = 0;
98out:
99 return err;
100}
101
73int mmap_dispatch_perf_file(struct perf_header **pheader, 102int mmap_dispatch_perf_file(struct perf_header **pheader,
74 const char *input_name, 103 const char *input_name,
75 int force, 104 int force,
@@ -130,7 +159,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
130 if (curr_handler->sample_type_check(sample_type) < 0) 159 if (curr_handler->sample_type_check(sample_type) < 0)
131 exit(-1); 160 exit(-1);
132 161
133 if (load_kernel(0, NULL) < 0) { 162 if (load_kernel(NULL) < 0) {
134 perror("failed to load kernel symbols"); 163 perror("failed to load kernel symbols");
135 return EXIT_FAILURE; 164 return EXIT_FAILURE;
136 } 165 }
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
index 716d1053b074..ae036ecd7625 100644
--- a/tools/perf/util/data_map.h
+++ b/tools/perf/util/data_map.h
@@ -27,5 +27,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
27 int full_paths, 27 int full_paths,
28 int *cwdlen, 28 int *cwdlen,
29 char **cwd); 29 char **cwd);
30int perf_header__read_build_ids(int input, off_t offset, off_t file_size);
30 31
31#endif 32#endif
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index e8b18a1f87a4..c6c24c522dea 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -2,6 +2,8 @@
2#ifndef __PERF_DEBUG_H 2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H 3#define __PERF_DEBUG_H
4 4
5#include "event.h"
6
5extern int verbose; 7extern int verbose;
6extern int dump_trace; 8extern int dump_trace;
7 9
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
new file mode 100644
index 000000000000..06b73ee02c49
--- /dev/null
+++ b/tools/perf/util/debugfs.c
@@ -0,0 +1,241 @@
1#include "util.h"
2#include "debugfs.h"
3#include "cache.h"
4
5static int debugfs_premounted;
6static char debugfs_mountpoint[MAX_PATH+1];
7
8static const char *debugfs_known_mountpoints[] = {
9 "/sys/kernel/debug/",
10 "/debug/",
11 0,
12};
13
14/* use this to force a umount */
15void debugfs_force_cleanup(void)
16{
17 debugfs_find_mountpoint();
18 debugfs_premounted = 0;
19 debugfs_umount();
20}
21
22/* construct a full path to a debugfs element */
23int debugfs_make_path(const char *element, char *buffer, int size)
24{
25 int len;
26
27 if (strlen(debugfs_mountpoint) == 0) {
28 buffer[0] = '\0';
29 return -1;
30 }
31
32 len = strlen(debugfs_mountpoint) + strlen(element) + 1;
33 if (len >= size)
34 return len+1;
35
36 snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
37 return 0;
38}
39
40static int debugfs_found;
41
42/* find the path to the mounted debugfs */
43const char *debugfs_find_mountpoint(void)
44{
45 const char **ptr;
46 char type[100];
47 FILE *fp;
48
49 if (debugfs_found)
50 return (const char *) debugfs_mountpoint;
51
52 ptr = debugfs_known_mountpoints;
53 while (*ptr) {
54 if (debugfs_valid_mountpoint(*ptr) == 0) {
55 debugfs_found = 1;
56 strcpy(debugfs_mountpoint, *ptr);
57 return debugfs_mountpoint;
58 }
59 ptr++;
60 }
61
62 /* give up and parse /proc/mounts */
63 fp = fopen("/proc/mounts", "r");
64 if (fp == NULL)
65 die("Can't open /proc/mounts for read");
66
67 while (fscanf(fp, "%*s %"
68 STR(MAX_PATH)
69 "s %99s %*s %*d %*d\n",
70 debugfs_mountpoint, type) == 2) {
71 if (strcmp(type, "debugfs") == 0)
72 break;
73 }
74 fclose(fp);
75
76 if (strcmp(type, "debugfs") != 0)
77 return NULL;
78
79 debugfs_found = 1;
80
81 return debugfs_mountpoint;
82}
83
84/* verify that a mountpoint is actually a debugfs instance */
85
86int debugfs_valid_mountpoint(const char *debugfs)
87{
88 struct statfs st_fs;
89
90 if (statfs(debugfs, &st_fs) < 0)
91 return -ENOENT;
92 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
93 return -ENOENT;
94
95 return 0;
96}
97
98
99int debugfs_valid_entry(const char *path)
100{
101 struct stat st;
102
103 if (stat(path, &st))
104 return -errno;
105
106 return 0;
107}
108
109/* mount the debugfs somewhere */
110
111int debugfs_mount(const char *mountpoint)
112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1;
118 return 0;
119 }
120
121 /* if not mounted and no argument */
122 if (mountpoint == NULL) {
123 /* see if environment variable set */
124 mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
125 /* if no environment variable, use default */
126 if (mountpoint == NULL)
127 mountpoint = "/sys/kernel/debug";
128 }
129
130 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
132
133 /* mount it */
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137}
138
139/* umount the debugfs */
140
141int debugfs_umount(void)
142{
143 char umountcmd[128];
144 int ret;
145
146 /* if it was already mounted, leave it */
147 if (debugfs_premounted)
148 return 0;
149
150 /* make sure it's a valid mount point */
151 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
152 if (ret)
153 return ret;
154
155 snprintf(umountcmd, sizeof(umountcmd),
156 "/bin/umount %s", debugfs_mountpoint);
157 return system(umountcmd);
158}
159
160int debugfs_write(const char *entry, const char *value)
161{
162 char path[MAX_PATH+1];
163 int ret, count;
164 int fd;
165
166 /* construct the path */
167 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
168
169 /* verify that it exists */
170 ret = debugfs_valid_entry(path);
171 if (ret)
172 return ret;
173
174 /* get how many chars we're going to write */
175 count = strlen(value);
176
177 /* open the debugfs entry */
178 fd = open(path, O_RDWR);
179 if (fd < 0)
180 return -errno;
181
182 while (count > 0) {
183 /* write it */
184 ret = write(fd, value, count);
185 if (ret <= 0) {
186 if (ret == EAGAIN)
187 continue;
188 close(fd);
189 return -errno;
190 }
191 count -= ret;
192 }
193
194 /* close it */
195 close(fd);
196
197 /* return success */
198 return 0;
199}
200
201/*
202 * read a debugfs entry
203 * returns the number of chars read or a negative errno
204 */
205int debugfs_read(const char *entry, char *buffer, size_t size)
206{
207 char path[MAX_PATH+1];
208 int ret;
209 int fd;
210
211 /* construct the path */
212 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
213
214 /* verify that it exists */
215 ret = debugfs_valid_entry(path);
216 if (ret)
217 return ret;
218
219 /* open the debugfs entry */
220 fd = open(path, O_RDONLY);
221 if (fd < 0)
222 return -errno;
223
224 do {
225 /* read it */
226 ret = read(fd, buffer, size);
227 if (ret == 0) {
228 close(fd);
229 return EOF;
230 }
231 } while (ret < 0 && errno == EAGAIN);
232
233 /* close it */
234 close(fd);
235
236 /* make *sure* there's a null character at the end */
237 buffer[ret] = '\0';
238
239 /* return the number of chars read */
240 return ret;
241}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
new file mode 100644
index 000000000000..3cd14f9ae784
--- /dev/null
+++ b/tools/perf/util/debugfs.h
@@ -0,0 +1,25 @@
1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__
3
4#include <sys/mount.h>
5
6#ifndef MAX_PATH
7# define MAX_PATH 256
8#endif
9
10#ifndef STR
11# define _STR(x) #x
12# define STR(x) _STR(x)
13#endif
14
15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path);
18extern int debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size);
22extern void debugfs_force_cleanup(void);
23extern int debugfs_make_path(const char *element, char *buffer, int size);
24
25#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
new file mode 100644
index 000000000000..1dae7e3b400d
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,177 @@
1#include <linux/types.h>
2#include "event.h"
3#include "debug.h"
4#include "string.h"
5
6static pid_t event__synthesize_comm(pid_t pid, int full,
7 int (*process)(event_t *event))
8{
9 event_t ev;
10 char filename[PATH_MAX];
11 char bf[BUFSIZ];
12 FILE *fp;
13 size_t size = 0;
14 DIR *tasks;
15 struct dirent dirent, *next;
16 pid_t tgid = 0;
17
18 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
19
20 fp = fopen(filename, "r");
21 if (fp == NULL) {
22out_race:
23 /*
24 * We raced with a task exiting - just return:
25 */
26 pr_debug("couldn't open %s\n", filename);
27 return 0;
28 }
29
30 memset(&ev.comm, 0, sizeof(ev.comm));
31 while (!ev.comm.comm[0] || !ev.comm.pid) {
32 if (fgets(bf, sizeof(bf), fp) == NULL)
33 goto out_failure;
34
35 if (memcmp(bf, "Name:", 5) == 0) {
36 char *name = bf + 5;
37 while (*name && isspace(*name))
38 ++name;
39 size = strlen(name) - 1;
40 memcpy(ev.comm.comm, name, size++);
41 } else if (memcmp(bf, "Tgid:", 5) == 0) {
42 char *tgids = bf + 5;
43 while (*tgids && isspace(*tgids))
44 ++tgids;
45 tgid = ev.comm.pid = atoi(tgids);
46 }
47 }
48
49 ev.comm.header.type = PERF_RECORD_COMM;
50 size = ALIGN(size, sizeof(u64));
51 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
52
53 if (!full) {
54 ev.comm.tid = pid;
55
56 process(&ev);
57 goto out_fclose;
58 }
59
60 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
61
62 tasks = opendir(filename);
63 if (tasks == NULL)
64 goto out_race;
65
66 while (!readdir_r(tasks, &dirent, &next) && next) {
67 char *end;
68 pid = strtol(dirent.d_name, &end, 10);
69 if (*end)
70 continue;
71
72 ev.comm.tid = pid;
73
74 process(&ev);
75 }
76 closedir(tasks);
77
78out_fclose:
79 fclose(fp);
80 return tgid;
81
82out_failure:
83 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
84 return -1;
85}
86
87static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
88 int (*process)(event_t *event))
89{
90 char filename[PATH_MAX];
91 FILE *fp;
92
93 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
94
95 fp = fopen(filename, "r");
96 if (fp == NULL) {
97 /*
98 * We raced with a task exiting - just return:
99 */
100 pr_debug("couldn't open %s\n", filename);
101 return -1;
102 }
103
104 while (1) {
105 char bf[BUFSIZ], *pbf = bf;
106 event_t ev = {
107 .header = { .type = PERF_RECORD_MMAP },
108 };
109 int n;
110 size_t size;
111 if (fgets(bf, sizeof(bf), fp) == NULL)
112 break;
113
114 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
115 n = hex2u64(pbf, &ev.mmap.start);
116 if (n < 0)
117 continue;
118 pbf += n + 1;
119 n = hex2u64(pbf, &ev.mmap.len);
120 if (n < 0)
121 continue;
122 pbf += n + 3;
123 if (*pbf == 'x') { /* vm_exec */
124 char *execname = strchr(bf, '/');
125
126 /* Catch VDSO */
127 if (execname == NULL)
128 execname = strstr(bf, "[vdso]");
129
130 if (execname == NULL)
131 continue;
132
133 size = strlen(execname);
134 execname[size - 1] = '\0'; /* Remove \n */
135 memcpy(ev.mmap.filename, execname, size);
136 size = ALIGN(size, sizeof(u64));
137 ev.mmap.len -= ev.mmap.start;
138 ev.mmap.header.size = (sizeof(ev.mmap) -
139 (sizeof(ev.mmap.filename) - size));
140 ev.mmap.pid = tgid;
141 ev.mmap.tid = pid;
142
143 process(&ev);
144 }
145 }
146
147 fclose(fp);
148 return 0;
149}
150
151int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
152{
153 pid_t tgid = event__synthesize_comm(pid, 1, process);
154 if (tgid == -1)
155 return -1;
156 return event__synthesize_mmap_events(pid, tgid, process);
157}
158
159void event__synthesize_threads(int (*process)(event_t *event))
160{
161 DIR *proc;
162 struct dirent dirent, *next;
163
164 proc = opendir("/proc");
165
166 while (!readdir_r(proc, &dirent, &next) && next) {
167 char *end;
168 pid_t pid = strtol(dirent.d_name, &end, 10);
169
170 if (*end) /* only interested in proper numerical dirents */
171 continue;
172
173 event__synthesize_thread(pid, process);
174 }
175
176 closedir(proc);
177}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index d972b4b0d38c..1f771ce3a957 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -61,6 +61,20 @@ struct sample_event{
61 u64 array[]; 61 u64 array[];
62}; 62};
63 63
64#define BUILD_ID_SIZE 20
65
66struct build_id_event {
67 struct perf_event_header header;
68 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
69 char filename[];
70};
71
72struct build_id_list {
73 struct build_id_event event;
74 struct list_head list;
75 const char *dso_name;
76 int len;
77};
64 78
65typedef union event_union { 79typedef union event_union {
66 struct perf_event_header header; 80 struct perf_event_header header;
@@ -105,10 +119,15 @@ struct symbol;
105 119
106typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 120typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
107 121
108struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, 122void map__init(struct map *self, u64 start, u64 end, u64 pgoff,
109 unsigned int sym_priv_size, symbol_filter_t filter); 123 struct dso *dso);
124struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
110struct map *map__clone(struct map *self); 125struct map *map__clone(struct map *self);
111int map__overlap(struct map *l, struct map *r); 126int map__overlap(struct map *l, struct map *r);
112size_t map__fprintf(struct map *self, FILE *fp); 127size_t map__fprintf(struct map *self, FILE *fp);
128struct symbol *map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter);
129
130int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
131void event__synthesize_threads(int (*process)(event_t *event));
113 132
114#endif /* __PERF_RECORD_H */ 133#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7d26659b806c..b01a9537977f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2,11 +2,15 @@
2#include <unistd.h> 2#include <unistd.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <stdlib.h> 4#include <stdlib.h>
5#include <linux/list.h>
5 6
6#include "util.h" 7#include "util.h"
7#include "header.h" 8#include "header.h"
8#include "../perf.h" 9#include "../perf.h"
9#include "trace-event.h" 10#include "trace-event.h"
11#include "symbol.h"
12#include "data_map.h"
13#include "debug.h"
10 14
11/* 15/*
12 * Create new perf.data header attribute: 16 * Create new perf.data header attribute:
@@ -15,32 +19,43 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
15{ 19{
16 struct perf_header_attr *self = malloc(sizeof(*self)); 20 struct perf_header_attr *self = malloc(sizeof(*self));
17 21
18 if (!self) 22 if (self != NULL) {
19 die("nomem"); 23 self->attr = *attr;
20 24 self->ids = 0;
21 self->attr = *attr; 25 self->size = 1;
22 self->ids = 0; 26 self->id = malloc(sizeof(u64));
23 self->size = 1; 27 if (self->id == NULL) {
24 self->id = malloc(sizeof(u64)); 28 free(self);
25 29 self = NULL;
26 if (!self->id) 30 }
27 die("nomem"); 31 }
28 32
29 return self; 33 return self;
30} 34}
31 35
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) 36void perf_header_attr__delete(struct perf_header_attr *self)
37{
38 free(self->id);
39 free(self);
40}
41
42int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
33{ 43{
34 int pos = self->ids; 44 int pos = self->ids;
35 45
36 self->ids++; 46 self->ids++;
37 if (self->ids > self->size) { 47 if (self->ids > self->size) {
38 self->size *= 2; 48 int nsize = self->size * 2;
39 self->id = realloc(self->id, self->size * sizeof(u64)); 49 u64 *nid = realloc(self->id, nsize * sizeof(u64));
40 if (!self->id) 50
41 die("nomem"); 51 if (nid == NULL)
52 return -1;
53
54 self->size = nsize;
55 self->id = nid;
42 } 56 }
43 self->id[pos] = id; 57 self->id[pos] = id;
58 return 0;
44} 59}
45 60
46/* 61/*
@@ -50,34 +65,41 @@ struct perf_header *perf_header__new(void)
50{ 65{
51 struct perf_header *self = calloc(sizeof(*self), 1); 66 struct perf_header *self = calloc(sizeof(*self), 1);
52 67
53 if (!self) 68 if (self != NULL) {
54 die("nomem"); 69 self->size = 1;
55 70 self->attr = malloc(sizeof(void *));
56 self->size = 1;
57 self->attr = malloc(sizeof(void *));
58 71
59 if (!self->attr) 72 if (self->attr == NULL) {
60 die("nomem"); 73 free(self);
74 self = NULL;
75 }
76 }
61 77
62 return self; 78 return self;
63} 79}
64 80
65void perf_header__add_attr(struct perf_header *self, 81int perf_header__add_attr(struct perf_header *self,
66 struct perf_header_attr *attr) 82 struct perf_header_attr *attr)
67{ 83{
68 int pos = self->attrs; 84 int pos = self->attrs;
69 85
70 if (self->frozen) 86 if (self->frozen)
71 die("frozen"); 87 return -1;
72 88
73 self->attrs++; 89 self->attrs++;
74 if (self->attrs > self->size) { 90 if (self->attrs > self->size) {
75 self->size *= 2; 91 int nsize = self->size * 2;
76 self->attr = realloc(self->attr, self->size * sizeof(void *)); 92 struct perf_header_attr **nattr;
77 if (!self->attr) 93
78 die("nomem"); 94 nattr = realloc(self->attr, nsize * sizeof(void *));
95 if (nattr == NULL)
96 return -1;
97
98 self->size = nsize;
99 self->attr = nattr;
79 } 100 }
80 self->attr[pos] = attr; 101 self->attr[pos] = attr;
102 return 0;
81} 103}
82 104
83#define MAX_EVENT_NAME 64 105#define MAX_EVENT_NAME 64
@@ -124,71 +146,110 @@ static const char *__perf_magic = "PERFFILE";
124 146
125#define PERF_MAGIC (*(u64 *)__perf_magic) 147#define PERF_MAGIC (*(u64 *)__perf_magic)
126 148
127struct perf_file_section {
128 u64 offset;
129 u64 size;
130};
131
132struct perf_file_attr { 149struct perf_file_attr {
133 struct perf_event_attr attr; 150 struct perf_event_attr attr;
134 struct perf_file_section ids; 151 struct perf_file_section ids;
135}; 152};
136 153
137struct perf_file_header { 154void perf_header__set_feat(struct perf_header *self, int feat)
138 u64 magic; 155{
139 u64 size; 156 set_bit(feat, self->adds_features);
140 u64 attr_size; 157}
141 struct perf_file_section attrs;
142 struct perf_file_section data;
143 struct perf_file_section event_types;
144 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
145};
146 158
147void perf_header__feat_trace_info(struct perf_header *header) 159bool perf_header__has_feat(const struct perf_header *self, int feat)
148{ 160{
149 set_bit(HEADER_TRACE_INFO, header->adds_features); 161 return test_bit(feat, self->adds_features);
150} 162}
151 163
152static void do_write(int fd, void *buf, size_t size) 164static int do_write(int fd, const void *buf, size_t size)
153{ 165{
154 while (size) { 166 while (size) {
155 int ret = write(fd, buf, size); 167 int ret = write(fd, buf, size);
156 168
157 if (ret < 0) 169 if (ret < 0)
158 die("failed to write"); 170 return -1;
159 171
160 size -= ret; 172 size -= ret;
161 buf += ret; 173 buf += ret;
162 } 174 }
175
176 return 0;
177}
178
179static int write_buildid_table(int fd, struct list_head *id_head)
180{
181 struct build_id_list *iter, *next;
182
183 list_for_each_entry_safe(iter, next, id_head, list) {
184 struct build_id_event *b = &iter->event;
185
186 if (do_write(fd, b, sizeof(*b)) < 0 ||
187 do_write(fd, iter->dso_name, iter->len) < 0)
188 return -1;
189 list_del(&iter->list);
190 free(iter);
191 }
192
193 return 0;
163} 194}
164 195
165static void perf_header__adds_write(struct perf_header *self, int fd) 196static void
197perf_header__adds_write(struct perf_header *self, int fd)
166{ 198{
167 struct perf_file_section trace_sec; 199 LIST_HEAD(id_list);
168 u64 cur_offset = lseek(fd, 0, SEEK_CUR); 200 int nr_sections;
169 unsigned long *feat_mask = self->adds_features; 201 struct perf_file_section *feat_sec;
202 int sec_size;
203 u64 sec_start;
204 int idx = 0;
205
206 if (fetch_build_id_table(&id_list))
207 perf_header__set_feat(self, HEADER_BUILD_ID);
208
209 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
210 if (!nr_sections)
211 return;
212
213 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
214 if (!feat_sec)
215 die("No memory");
216
217 sec_size = sizeof(*feat_sec) * nr_sections;
218
219 sec_start = self->data_offset + self->data_size;
220 lseek(fd, sec_start + sec_size, SEEK_SET);
221
222 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
223 struct perf_file_section *trace_sec;
224
225 trace_sec = &feat_sec[idx++];
170 226
171 if (test_bit(HEADER_TRACE_INFO, feat_mask)) {
172 /* Write trace info */ 227 /* Write trace info */
173 trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); 228 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
174 read_tracing_data(fd, attrs, nr_counters); 229 read_tracing_data(fd, attrs, nr_counters);
175 trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset; 230 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
176
177 /* Write trace info headers */
178 lseek(fd, cur_offset, SEEK_SET);
179 do_write(fd, &trace_sec, sizeof(trace_sec));
180
181 /*
182 * Update cur_offset. So that other (future)
183 * features can set their own infos in this place. But if we are
184 * the only feature, at least that seeks to the place the data
185 * should begin.
186 */
187 cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET);
188 } 231 }
189};
190 232
191void perf_header__write(struct perf_header *self, int fd) 233
234 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
235 struct perf_file_section *buildid_sec;
236
237 buildid_sec = &feat_sec[idx++];
238
239 /* Write build-ids */
240 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
241 if (write_buildid_table(fd, &id_list) < 0)
242 die("failed to write buildid table");
243 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
244 }
245
246 lseek(fd, sec_start, SEEK_SET);
247 if (do_write(fd, feat_sec, sec_size) < 0)
248 die("failed to write feature section");
249 free(feat_sec);
250}
251
252void perf_header__write(struct perf_header *self, int fd, bool at_exit)
192{ 253{
193 struct perf_file_header f_header; 254 struct perf_file_header f_header;
194 struct perf_file_attr f_attr; 255 struct perf_file_attr f_attr;
@@ -202,7 +263,8 @@ void perf_header__write(struct perf_header *self, int fd)
202 attr = self->attr[i]; 263 attr = self->attr[i];
203 264
204 attr->id_offset = lseek(fd, 0, SEEK_CUR); 265 attr->id_offset = lseek(fd, 0, SEEK_CUR);
205 do_write(fd, attr->id, attr->ids * sizeof(u64)); 266 if (do_write(fd, attr->id, attr->ids * sizeof(u64)) < 0)
267 die("failed to write perf header");
206 } 268 }
207 269
208 270
@@ -218,18 +280,21 @@ void perf_header__write(struct perf_header *self, int fd)
218 .size = attr->ids * sizeof(u64), 280 .size = attr->ids * sizeof(u64),
219 } 281 }
220 }; 282 };
221 do_write(fd, &f_attr, sizeof(f_attr)); 283 if (do_write(fd, &f_attr, sizeof(f_attr)) < 0)
284 die("failed to write perf header attribute");
222 } 285 }
223 286
224 self->event_offset = lseek(fd, 0, SEEK_CUR); 287 self->event_offset = lseek(fd, 0, SEEK_CUR);
225 self->event_size = event_count * sizeof(struct perf_trace_event_type); 288 self->event_size = event_count * sizeof(struct perf_trace_event_type);
226 if (events) 289 if (events)
227 do_write(fd, events, self->event_size); 290 if (do_write(fd, events, self->event_size) < 0)
228 291 die("failed to write perf header events");
229 perf_header__adds_write(self, fd);
230 292
231 self->data_offset = lseek(fd, 0, SEEK_CUR); 293 self->data_offset = lseek(fd, 0, SEEK_CUR);
232 294
295 if (at_exit)
296 perf_header__adds_write(self, fd);
297
233 f_header = (struct perf_file_header){ 298 f_header = (struct perf_file_header){
234 .magic = PERF_MAGIC, 299 .magic = PERF_MAGIC,
235 .size = sizeof(f_header), 300 .size = sizeof(f_header),
@@ -251,7 +316,8 @@ void perf_header__write(struct perf_header *self, int fd)
251 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); 316 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
252 317
253 lseek(fd, 0, SEEK_SET); 318 lseek(fd, 0, SEEK_SET);
254 do_write(fd, &f_header, sizeof(f_header)); 319 if (do_write(fd, &f_header, sizeof(f_header)) < 0)
320 die("failed to write perf header");
255 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 321 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
256 322
257 self->frozen = 1; 323 self->frozen = 1;
@@ -272,43 +338,112 @@ static void do_read(int fd, void *buf, size_t size)
272 } 338 }
273} 339}
274 340
275static void perf_header__adds_read(struct perf_header *self, int fd) 341int perf_header__process_sections(struct perf_header *self, int fd,
342 int (*process)(struct perf_file_section *self,
343 int feat, int fd))
276{ 344{
277 const unsigned long *feat_mask = self->adds_features; 345 struct perf_file_section *feat_sec;
346 int nr_sections;
347 int sec_size;
348 int idx = 0;
349 int err = 0, feat = 1;
278 350
279 if (test_bit(HEADER_TRACE_INFO, feat_mask)) { 351 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
280 struct perf_file_section trace_sec; 352 if (!nr_sections)
353 return 0;
281 354
282 do_read(fd, &trace_sec, sizeof(trace_sec)); 355 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
283 lseek(fd, trace_sec.offset, SEEK_SET); 356 if (!feat_sec)
284 trace_report(fd); 357 return -1;
285 lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); 358
359 sec_size = sizeof(*feat_sec) * nr_sections;
360
361 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
362
363 do_read(fd, feat_sec, sec_size);
364
365 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
366 if (perf_header__has_feat(self, feat)) {
367 struct perf_file_section *sec = &feat_sec[idx++];
368
369 err = process(sec, feat, fd);
370 if (err < 0)
371 break;
372 }
373 ++feat;
286 } 374 }
375
376 free(feat_sec);
377 return err;
287}; 378};
288 379
380int perf_file_header__read(struct perf_file_header *self,
381 struct perf_header *ph, int fd)
382{
383 lseek(fd, 0, SEEK_SET);
384 do_read(fd, self, sizeof(*self));
385
386 if (self->magic != PERF_MAGIC ||
387 self->attr_size != sizeof(struct perf_file_attr))
388 return -1;
389
390 if (self->size != sizeof(*self)) {
391 /* Support the previous format */
392 if (self->size == offsetof(typeof(*self), adds_features))
393 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
394 else
395 return -1;
396 }
397
398 memcpy(&ph->adds_features, &self->adds_features,
399 sizeof(self->adds_features));
400
401 ph->event_offset = self->event_types.offset;
402 ph->event_size = self->event_types.size;
403 ph->data_offset = self->data.offset;
404 ph->data_size = self->data.size;
405 return 0;
406}
407
408static int perf_file_section__process(struct perf_file_section *self,
409 int feat, int fd)
410{
411 if (lseek(fd, self->offset, SEEK_SET) < 0) {
412 pr_debug("Failed to lseek to %Ld offset for feature %d, "
413 "continuing...\n", self->offset, feat);
414 return 0;
415 }
416
417 switch (feat) {
418 case HEADER_TRACE_INFO:
419 trace_report(fd);
420 break;
421
422 case HEADER_BUILD_ID:
423 if (perf_header__read_build_ids(fd, self->offset, self->size))
424 pr_debug("Failed to read buildids, continuing...\n");
425 break;
426 default:
427 pr_debug("unknown feature %d, continuing...\n", feat);
428 }
429
430 return 0;
431}
432
289struct perf_header *perf_header__read(int fd) 433struct perf_header *perf_header__read(int fd)
290{ 434{
291 struct perf_header *self = perf_header__new(); 435 struct perf_header *self = perf_header__new();
292 struct perf_file_header f_header; 436 struct perf_file_header f_header;
293 struct perf_file_attr f_attr; 437 struct perf_file_attr f_attr;
294 u64 f_id; 438 u64 f_id;
295
296 int nr_attrs, nr_ids, i, j; 439 int nr_attrs, nr_ids, i, j;
297 440
298 lseek(fd, 0, SEEK_SET); 441 if (self == NULL)
299 do_read(fd, &f_header, sizeof(f_header)); 442 die("nomem");
300 443
301 if (f_header.magic != PERF_MAGIC || 444 if (perf_file_header__read(&f_header, self, fd) < 0)
302 f_header.attr_size != sizeof(f_attr))
303 die("incompatible file format"); 445 die("incompatible file format");
304 446
305 if (f_header.size != sizeof(f_header)) {
306 /* Support the previous format */
307 if (f_header.size == offsetof(typeof(f_header), adds_features))
308 bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS);
309 else
310 die("incompatible file format");
311 }
312 nr_attrs = f_header.attrs.size / sizeof(f_attr); 447 nr_attrs = f_header.attrs.size / sizeof(f_attr);
313 lseek(fd, f_header.attrs.offset, SEEK_SET); 448 lseek(fd, f_header.attrs.offset, SEEK_SET);
314 449
@@ -320,6 +455,8 @@ struct perf_header *perf_header__read(int fd)
320 tmp = lseek(fd, 0, SEEK_CUR); 455 tmp = lseek(fd, 0, SEEK_CUR);
321 456
322 attr = perf_header_attr__new(&f_attr.attr); 457 attr = perf_header_attr__new(&f_attr.attr);
458 if (attr == NULL)
459 die("nomem");
323 460
324 nr_ids = f_attr.ids.size / sizeof(u64); 461 nr_ids = f_attr.ids.size / sizeof(u64);
325 lseek(fd, f_attr.ids.offset, SEEK_SET); 462 lseek(fd, f_attr.ids.offset, SEEK_SET);
@@ -327,9 +464,12 @@ struct perf_header *perf_header__read(int fd)
327 for (j = 0; j < nr_ids; j++) { 464 for (j = 0; j < nr_ids; j++) {
328 do_read(fd, &f_id, sizeof(f_id)); 465 do_read(fd, &f_id, sizeof(f_id));
329 466
330 perf_header_attr__add_id(attr, f_id); 467 if (perf_header_attr__add_id(attr, f_id) < 0)
468 die("nomem");
331 } 469 }
332 perf_header__add_attr(self, attr); 470 if (perf_header__add_attr(self, attr) < 0)
471 die("nomem");
472
333 lseek(fd, tmp, SEEK_SET); 473 lseek(fd, tmp, SEEK_SET);
334 } 474 }
335 475
@@ -342,15 +482,7 @@ struct perf_header *perf_header__read(int fd)
342 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 482 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
343 } 483 }
344 484
345 memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features)); 485 perf_header__process_sections(self, fd, perf_file_section__process);
346
347 perf_header__adds_read(self, fd);
348
349 self->event_offset = f_header.event_types.offset;
350 self->event_size = f_header.event_types.size;
351
352 self->data_offset = f_header.data.offset;
353 self->data_size = f_header.data.size;
354 486
355 lseek(fd, self->data_offset, SEEK_SET); 487 lseek(fd, self->data_offset, SEEK_SET);
356 488
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 2ea9dfb1236a..f46a94e09eea 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -3,6 +3,7 @@
3 3
4#include "../../../include/linux/perf_event.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h>
6#include "types.h" 7#include "types.h"
7 8
8#include <linux/bitmap.h> 9#include <linux/bitmap.h>
@@ -14,10 +15,34 @@ struct perf_header_attr {
14 off_t id_offset; 15 off_t id_offset;
15}; 16};
16 17
17#define HEADER_TRACE_INFO 1 18enum {
19 HEADER_TRACE_INFO = 1,
20 HEADER_BUILD_ID,
21 HEADER_LAST_FEATURE,
22};
18 23
19#define HEADER_FEAT_BITS 256 24#define HEADER_FEAT_BITS 256
20 25
26struct perf_file_section {
27 u64 offset;
28 u64 size;
29};
30
31struct perf_file_header {
32 u64 magic;
33 u64 size;
34 u64 attr_size;
35 struct perf_file_section attrs;
36 struct perf_file_section data;
37 struct perf_file_section event_types;
38 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
39};
40
41struct perf_header;
42
43int perf_file_header__read(struct perf_file_header *self,
44 struct perf_header *ph, int fd);
45
21struct perf_header { 46struct perf_header {
22 int frozen; 47 int frozen;
23 int attrs, size; 48 int attrs, size;
@@ -31,24 +56,29 @@ struct perf_header {
31}; 56};
32 57
33struct perf_header *perf_header__read(int fd); 58struct perf_header *perf_header__read(int fd);
34void perf_header__write(struct perf_header *self, int fd); 59void perf_header__write(struct perf_header *self, int fd, bool at_exit);
35 60
36void perf_header__add_attr(struct perf_header *self, 61int perf_header__add_attr(struct perf_header *self,
37 struct perf_header_attr *attr); 62 struct perf_header_attr *attr);
38 63
39void perf_header__push_event(u64 id, const char *name); 64void perf_header__push_event(u64 id, const char *name);
40char *perf_header__find_event(u64 id); 65char *perf_header__find_event(u64 id);
41 66
67struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
68void perf_header_attr__delete(struct perf_header_attr *self);
42 69
43struct perf_header_attr * 70int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
44perf_header_attr__new(struct perf_event_attr *attr);
45void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
46 71
47u64 perf_header__sample_type(struct perf_header *header); 72u64 perf_header__sample_type(struct perf_header *header);
48struct perf_event_attr * 73struct perf_event_attr *
49perf_header__find_attr(u64 id, struct perf_header *header); 74perf_header__find_attr(u64 id, struct perf_header *header);
50void perf_header__feat_trace_info(struct perf_header *header); 75void perf_header__set_feat(struct perf_header *self, int feat);
76bool perf_header__has_feat(const struct perf_header *self, int feat);
51 77
52struct perf_header *perf_header__new(void); 78struct perf_header *perf_header__new(void);
53 79
80int perf_header__process_sections(struct perf_header *self, int fd,
81 int (*process)(struct perf_file_section *self,
82 int feat, int fd));
83
54#endif /* __PERF_HEADER_H */ 84#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index 821c1033bccf..94507639a8c4 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -1,2 +1,3 @@
1#include "../../../../include/linux/bitmap.h" 1#include "../../../../include/linux/bitmap.h"
2#include "../../../../include/asm-generic/bitops/find.h" 2#include "../../../../include/asm-generic/bitops/find.h"
3#include <linux/errno.h>
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
index bae5783282ef..a53d4ee1e0b7 100644
--- a/tools/perf/util/include/linux/ctype.h
+++ b/tools/perf/util/include/linux/ctype.h
@@ -1 +1 @@
#include "../../../../include/linux/ctype.h" #include "../util.h"
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index c1c556825343..94ca95073c40 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -20,16 +20,27 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
20 return n; 20 return n;
21} 21}
22 22
23struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, 23void map__init(struct map *self, u64 start, u64 end, u64 pgoff,
24 unsigned int sym_priv_size, symbol_filter_t filter) 24 struct dso *dso)
25{
26 self->start = start;
27 self->end = end;
28 self->pgoff = pgoff;
29 self->dso = dso;
30 self->map_ip = map__map_ip;
31 self->unmap_ip = map__unmap_ip;
32 RB_CLEAR_NODE(&self->rb_node);
33}
34
35struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
25{ 36{
26 struct map *self = malloc(sizeof(*self)); 37 struct map *self = malloc(sizeof(*self));
27 38
28 if (self != NULL) { 39 if (self != NULL) {
29 const char *filename = event->filename; 40 const char *filename = event->filename;
30 char newfilename[PATH_MAX]; 41 char newfilename[PATH_MAX];
42 struct dso *dso;
31 int anon; 43 int anon;
32 bool new_dso;
33 44
34 if (cwd) { 45 if (cwd) {
35 int n = strcommon(filename, cwd, cwdlen); 46 int n = strcommon(filename, cwd, cwdlen);
@@ -48,33 +59,15 @@ struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen,
48 filename = newfilename; 59 filename = newfilename;
49 } 60 }
50 61
51 self->start = event->start; 62 dso = dsos__findnew(filename);
52 self->end = event->start + event->len; 63 if (dso == NULL)
53 self->pgoff = event->pgoff;
54
55 self->dso = dsos__findnew(filename, sym_priv_size, &new_dso);
56 if (self->dso == NULL)
57 goto out_delete; 64 goto out_delete;
58 65
59 if (new_dso) { 66 map__init(self, event->start, event->start + event->len,
60 int nr = dso__load(self->dso, self, filter); 67 event->pgoff, dso);
61
62 if (nr < 0)
63 pr_warning("Failed to open %s, continuing "
64 "without symbols\n",
65 self->dso->long_name);
66 else if (nr == 0)
67 pr_warning("No symbols found in %s, maybe "
68 "install a debug package?\n",
69 self->dso->long_name);
70 }
71 68
72 if (self->dso == vdso || anon) 69 if (self->dso == vdso || anon)
73 self->map_ip = self->unmap_ip = identity__map_ip; 70 self->map_ip = self->unmap_ip = identity__map_ip;
74 else {
75 self->map_ip = map__map_ip;
76 self->unmap_ip = map__unmap_ip;
77 }
78 } 71 }
79 return self; 72 return self;
80out_delete: 73out_delete:
@@ -82,6 +75,47 @@ out_delete:
82 return NULL; 75 return NULL;
83} 76}
84 77
78#define DSO__DELETED "(deleted)"
79
80struct symbol *
81map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter)
82{
83 if (!self->dso->loaded) {
84 int nr = dso__load(self->dso, self, filter);
85
86 if (nr < 0) {
87 if (self->dso->has_build_id) {
88 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
89
90 build_id__sprintf(self->dso->build_id,
91 sizeof(self->dso->build_id),
92 sbuild_id);
93 pr_warning("%s with build id %s not found",
94 self->dso->long_name, sbuild_id);
95 } else
96 pr_warning("Failed to open %s",
97 self->dso->long_name);
98 pr_warning(", continuing without symbols\n");
99 return NULL;
100 } else if (nr == 0) {
101 const char *name = self->dso->long_name;
102 const size_t len = strlen(name);
103 const size_t real_len = len - sizeof(DSO__DELETED);
104
105 if (len > sizeof(DSO__DELETED) &&
106 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
107 pr_warning("%.*s was updated, restart the long running apps that use it!\n",
108 (int)real_len, name);
109 } else {
110 pr_warning("no symbols found in %s, maybe install a debug package?\n", name);
111 }
112 return NULL;
113 }
114 }
115
116 return self->dso->find_symbol(self->dso, ip);
117}
118
85struct map *map__clone(struct map *self) 119struct map *map__clone(struct map *self)
86{ 120{
87 struct map *map = malloc(sizeof(*self)); 121 struct map *map = malloc(sizeof(*self));
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b097570e9623..0faf4f2bb5ca 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -7,6 +7,7 @@
7#include "string.h" 7#include "string.h"
8#include "cache.h" 8#include "cache.h"
9#include "header.h" 9#include "header.h"
10#include "debugfs.h"
10 11
11int nr_counters; 12int nr_counters;
12 13
@@ -47,6 +48,8 @@ static struct event_symbol event_symbols[] = {
47 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, 48 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
48 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, 49 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
49 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, 50 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
51 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" },
52 { CSW(EMULATION_FAULTS), "emulation-faults", "" },
50}; 53};
51 54
52#define __PERF_EVENT_FIELD(config, name) \ 55#define __PERF_EVENT_FIELD(config, name) \
@@ -75,6 +78,8 @@ static const char *sw_event_names[] = {
75 "CPU-migrations", 78 "CPU-migrations",
76 "minor-faults", 79 "minor-faults",
77 "major-faults", 80 "major-faults",
81 "alignment-faults",
82 "emulation-faults",
78}; 83};
79 84
80#define MAX_ALIASES 8 85#define MAX_ALIASES 8
@@ -149,16 +154,6 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
149 154
150#define MAX_EVENT_LENGTH 512 155#define MAX_EVENT_LENGTH 512
151 156
152int valid_debugfs_mount(const char *debugfs)
153{
154 struct statfs st_fs;
155
156 if (statfs(debugfs, &st_fs) < 0)
157 return -ENOENT;
158 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
159 return -ENOENT;
160 return 0;
161}
162 157
163struct tracepoint_path *tracepoint_id_to_path(u64 config) 158struct tracepoint_path *tracepoint_id_to_path(u64 config)
164{ 159{
@@ -171,7 +166,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
171 char evt_path[MAXPATHLEN]; 166 char evt_path[MAXPATHLEN];
172 char dir_path[MAXPATHLEN]; 167 char dir_path[MAXPATHLEN];
173 168
174 if (valid_debugfs_mount(debugfs_path)) 169 if (debugfs_valid_mountpoint(debugfs_path))
175 return NULL; 170 return NULL;
176 171
177 sys_dir = opendir(debugfs_path); 172 sys_dir = opendir(debugfs_path);
@@ -510,7 +505,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
510 char sys_name[MAX_EVENT_LENGTH]; 505 char sys_name[MAX_EVENT_LENGTH];
511 unsigned int sys_length, evt_length; 506 unsigned int sys_length, evt_length;
512 507
513 if (valid_debugfs_mount(debugfs_path)) 508 if (debugfs_valid_mountpoint(debugfs_path))
514 return 0; 509 return 0;
515 510
516 evt_name = strchr(*strp, ':'); 511 evt_name = strchr(*strp, ':');
@@ -678,6 +673,8 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
678 if (ret != EVT_FAILED) 673 if (ret != EVT_FAILED)
679 goto modifier; 674 goto modifier;
680 675
676 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
677 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
681 return EVT_FAILED; 678 return EVT_FAILED;
682 679
683modifier: 680modifier:
@@ -786,7 +783,7 @@ static void print_tracepoint_events(void)
786 char evt_path[MAXPATHLEN]; 783 char evt_path[MAXPATHLEN];
787 char dir_path[MAXPATHLEN]; 784 char dir_path[MAXPATHLEN];
788 785
789 if (valid_debugfs_mount(debugfs_path)) 786 if (debugfs_valid_mountpoint(debugfs_path))
790 return; 787 return;
791 788
792 sys_dir = opendir(debugfs_path); 789 sys_dir = opendir(debugfs_path);
@@ -804,7 +801,7 @@ static void print_tracepoint_events(void)
804 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 801 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
805 snprintf(evt_path, MAXPATHLEN, "%s:%s", 802 snprintf(evt_path, MAXPATHLEN, "%s:%s",
806 sys_dirent.d_name, evt_dirent.d_name); 803 sys_dirent.d_name, evt_dirent.d_name);
807 fprintf(stderr, " %-42s [%s]\n", evt_path, 804 printf(" %-42s [%s]\n", evt_path,
808 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 805 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
809 } 806 }
810 closedir(evt_dir); 807 closedir(evt_dir);
@@ -821,8 +818,8 @@ void print_events(void)
821 unsigned int i, type, op, prev_type = -1; 818 unsigned int i, type, op, prev_type = -1;
822 char name[40]; 819 char name[40];
823 820
824 fprintf(stderr, "\n"); 821 printf("\n");
825 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 822 printf("List of pre-defined events (to be used in -e):\n");
826 823
827 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 824 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
828 type = syms->type + 1; 825 type = syms->type + 1;
@@ -830,19 +827,19 @@ void print_events(void)
830 type = 0; 827 type = 0;
831 828
832 if (type != prev_type) 829 if (type != prev_type)
833 fprintf(stderr, "\n"); 830 printf("\n");
834 831
835 if (strlen(syms->alias)) 832 if (strlen(syms->alias))
836 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 833 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
837 else 834 else
838 strcpy(name, syms->symbol); 835 strcpy(name, syms->symbol);
839 fprintf(stderr, " %-42s [%s]\n", name, 836 printf(" %-42s [%s]\n", name,
840 event_type_descriptors[type]); 837 event_type_descriptors[type]);
841 838
842 prev_type = type; 839 prev_type = type;
843 } 840 }
844 841
845 fprintf(stderr, "\n"); 842 printf("\n");
846 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 843 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
847 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 844 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
848 /* skip invalid cache type */ 845 /* skip invalid cache type */
@@ -850,17 +847,17 @@ void print_events(void)
850 continue; 847 continue;
851 848
852 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 849 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
853 fprintf(stderr, " %-42s [%s]\n", 850 printf(" %-42s [%s]\n",
854 event_cache_name(type, op, i), 851 event_cache_name(type, op, i),
855 event_type_descriptors[4]); 852 event_type_descriptors[4]);
856 } 853 }
857 } 854 }
858 } 855 }
859 856
860 fprintf(stderr, "\n"); 857 printf("\n");
861 fprintf(stderr, " %-42s [raw hardware event descriptor]\n", 858 printf(" %-42s [raw hardware event descriptor]\n",
862 "rNNN"); 859 "rNNN");
863 fprintf(stderr, "\n"); 860 printf("\n");
864 861
865 print_tracepoint_events(); 862 print_tracepoint_events();
866 863
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 04743d3e9039..227043577e06 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,5 +1,7 @@
1#include <string.h> 1#include <string.h>
2#include <stdlib.h>
2#include "string.h" 3#include "string.h"
4#include "util.h"
3 5
4static int hex(char ch) 6static int hex(char ch)
5{ 7{
@@ -43,3 +45,85 @@ char *strxfrchar(char *s, char from, char to)
43 45
44 return s; 46 return s;
45} 47}
48
49#define K 1024LL
50/*
51 * perf_atoll()
52 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
53 * and return its numeric value
54 */
55s64 perf_atoll(const char *str)
56{
57 unsigned int i;
58 s64 length = -1, unit = 1;
59
60 if (!isdigit(str[0]))
61 goto out_err;
62
63 for (i = 1; i < strlen(str); i++) {
64 switch (str[i]) {
65 case 'B':
66 case 'b':
67 break;
68 case 'K':
69 if (str[i + 1] != 'B')
70 goto out_err;
71 else
72 goto kilo;
73 case 'k':
74 if (str[i + 1] != 'b')
75 goto out_err;
76kilo:
77 unit = K;
78 break;
79 case 'M':
80 if (str[i + 1] != 'B')
81 goto out_err;
82 else
83 goto mega;
84 case 'm':
85 if (str[i + 1] != 'b')
86 goto out_err;
87mega:
88 unit = K * K;
89 break;
90 case 'G':
91 if (str[i + 1] != 'B')
92 goto out_err;
93 else
94 goto giga;
95 case 'g':
96 if (str[i + 1] != 'b')
97 goto out_err;
98giga:
99 unit = K * K * K;
100 break;
101 case 'T':
102 if (str[i + 1] != 'B')
103 goto out_err;
104 else
105 goto tera;
106 case 't':
107 if (str[i + 1] != 'b')
108 goto out_err;
109tera:
110 unit = K * K * K * K;
111 break;
112 case '\0': /* only specified figures */
113 unit = 1;
114 break;
115 default:
116 if (!isdigit(str[i]))
117 goto out_err;
118 break;
119 }
120 }
121
122 length = atoll(str) * unit;
123 goto out;
124
125out_err:
126 length = -1;
127out:
128 return length;
129}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 2c84bf65ba0f..e50b07f80827 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -5,6 +5,7 @@
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7char *strxfrchar(char *s, char from, char to); 7char *strxfrchar(char *s, char from, char to);
8s64 perf_atoll(const char *str);
8 9
9#define _STR(x) #x 10#define _STR(x) #x
10#define STR(x) _STR(x) 11#define STR(x) _STR(x)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8f0208ce237a..1b77e81b38de 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -26,6 +26,7 @@ static void dsos__add(struct dso *dso);
26static struct dso *dsos__find(const char *name); 26static struct dso *dsos__find(const char *name);
27static struct map *map__new2(u64 start, struct dso *dso); 27static struct map *map__new2(u64 start, struct dso *dso);
28static void kernel_maps__insert(struct map *map); 28static void kernel_maps__insert(struct map *map);
29unsigned int symbol__priv_size;
29 30
30static struct rb_root kernel_maps; 31static struct rb_root kernel_maps;
31 32
@@ -75,18 +76,17 @@ static void kernel_maps__fixup_end(void)
75 } 76 }
76} 77}
77 78
78static struct symbol *symbol__new(u64 start, u64 len, const char *name, 79static struct symbol *symbol__new(u64 start, u64 len, const char *name)
79 unsigned int priv_size)
80{ 80{
81 size_t namelen = strlen(name) + 1; 81 size_t namelen = strlen(name) + 1;
82 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 82 struct symbol *self = calloc(1, (symbol__priv_size +
83 83 sizeof(*self) + namelen));
84 if (!self) 84 if (!self)
85 return NULL; 85 return NULL;
86 86
87 if (priv_size) { 87 if (symbol__priv_size) {
88 memset(self, 0, priv_size); 88 memset(self, 0, symbol__priv_size);
89 self = ((void *)self) + priv_size; 89 self = ((void *)self) + symbol__priv_size;
90 } 90 }
91 self->start = start; 91 self->start = start;
92 self->end = len ? start + len - 1 : start; 92 self->end = len ? start + len - 1 : start;
@@ -98,9 +98,9 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name,
98 return self; 98 return self;
99} 99}
100 100
101static void symbol__delete(struct symbol *self, unsigned int priv_size) 101static void symbol__delete(struct symbol *self)
102{ 102{
103 free(((void *)self) - priv_size); 103 free(((void *)self) - symbol__priv_size);
104} 104}
105 105
106static size_t symbol__fprintf(struct symbol *self, FILE *fp) 106static size_t symbol__fprintf(struct symbol *self, FILE *fp)
@@ -109,7 +109,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
109 self->start, self->end, self->name); 109 self->start, self->end, self->name);
110} 110}
111 111
112struct dso *dso__new(const char *name, unsigned int sym_priv_size) 112struct dso *dso__new(const char *name)
113{ 113{
114 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 114 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
115 115
@@ -118,10 +118,11 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
118 self->long_name = self->name; 118 self->long_name = self->name;
119 self->short_name = self->name; 119 self->short_name = self->name;
120 self->syms = RB_ROOT; 120 self->syms = RB_ROOT;
121 self->sym_priv_size = sym_priv_size;
122 self->find_symbol = dso__find_symbol; 121 self->find_symbol = dso__find_symbol;
123 self->slen_calculated = 0; 122 self->slen_calculated = 0;
124 self->origin = DSO__ORIG_NOT_FOUND; 123 self->origin = DSO__ORIG_NOT_FOUND;
124 self->loaded = 0;
125 self->has_build_id = 0;
125 } 126 }
126 127
127 return self; 128 return self;
@@ -136,7 +137,7 @@ static void dso__delete_symbols(struct dso *self)
136 pos = rb_entry(next, struct symbol, rb_node); 137 pos = rb_entry(next, struct symbol, rb_node);
137 next = rb_next(&pos->rb_node); 138 next = rb_next(&pos->rb_node);
138 rb_erase(&pos->rb_node, &self->syms); 139 rb_erase(&pos->rb_node, &self->syms);
139 symbol__delete(pos, self->sym_priv_size); 140 symbol__delete(pos);
140 } 141 }
141} 142}
142 143
@@ -148,6 +149,12 @@ void dso__delete(struct dso *self)
148 free(self); 149 free(self);
149} 150}
150 151
152void dso__set_build_id(struct dso *self, void *build_id)
153{
154 memcpy(self->build_id, build_id, sizeof(self->build_id));
155 self->has_build_id = 1;
156}
157
151static void dso__insert_symbol(struct dso *self, struct symbol *sym) 158static void dso__insert_symbol(struct dso *self, struct symbol *sym)
152{ 159{
153 struct rb_node **p = &self->syms.rb_node; 160 struct rb_node **p = &self->syms.rb_node;
@@ -190,11 +197,37 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
190 return NULL; 197 return NULL;
191} 198}
192 199
193size_t dso__fprintf(struct dso *self, FILE *fp) 200int build_id__sprintf(u8 *self, int len, char *bf)
194{ 201{
195 size_t ret = fprintf(fp, "dso: %s\n", self->short_name); 202 char *bid = bf;
203 u8 *raw = self;
204 int i;
196 205
206 for (i = 0; i < len; ++i) {
207 sprintf(bid, "%02x", *raw);
208 ++raw;
209 bid += 2;
210 }
211
212 return raw - self;
213}
214
215size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
216{
217 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
218
219 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
220 return fprintf(fp, "%s", sbuild_id);
221}
222
223size_t dso__fprintf(struct dso *self, FILE *fp)
224{
197 struct rb_node *nd; 225 struct rb_node *nd;
226 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
227
228 ret += dso__fprintf_buildid(self, fp);
229 ret += fprintf(fp, ")\n");
230
198 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 231 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
199 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 232 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
200 ret += symbol__fprintf(pos, fp); 233 ret += symbol__fprintf(pos, fp);
@@ -250,12 +283,16 @@ static int kernel_maps__load_all_kallsyms(void)
250 /* 283 /*
251 * Will fix up the end later, when we have all symbols sorted. 284 * Will fix up the end later, when we have all symbols sorted.
252 */ 285 */
253 sym = symbol__new(start, 0, symbol_name, 286 sym = symbol__new(start, 0, symbol_name);
254 kernel_map->dso->sym_priv_size);
255 287
256 if (sym == NULL) 288 if (sym == NULL)
257 goto out_delete_line; 289 goto out_delete_line;
258 290
291 /*
292 * We will pass the symbols to the filter later, in
293 * kernel_maps__split_kallsyms, when we have split the
294 * maps per module
295 */
259 dso__insert_symbol(kernel_map->dso, sym); 296 dso__insert_symbol(kernel_map->dso, sym);
260 } 297 }
261 298
@@ -317,8 +354,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
317 snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 354 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
318 kernel_range++); 355 kernel_range++);
319 356
320 dso = dso__new(dso_name, 357 dso = dso__new(dso_name);
321 kernel_map->dso->sym_priv_size);
322 if (dso == NULL) 358 if (dso == NULL)
323 return -1; 359 return -1;
324 360
@@ -336,7 +372,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
336 if (filter && filter(map, pos)) { 372 if (filter && filter(map, pos)) {
337delete_symbol: 373delete_symbol:
338 rb_erase(&pos->rb_node, &kernel_map->dso->syms); 374 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
339 symbol__delete(pos, kernel_map->dso->sym_priv_size); 375 symbol__delete(pos);
340 } else { 376 } else {
341 if (map != kernel_map) { 377 if (map != kernel_map) {
342 rb_erase(&pos->rb_node, &kernel_map->dso->syms); 378 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
@@ -417,14 +453,13 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
417 if (len + 2 >= line_len) 453 if (len + 2 >= line_len)
418 continue; 454 continue;
419 455
420 sym = symbol__new(start, size, line + len, 456 sym = symbol__new(start, size, line + len);
421 self->sym_priv_size);
422 457
423 if (sym == NULL) 458 if (sym == NULL)
424 goto out_delete_line; 459 goto out_delete_line;
425 460
426 if (filter && filter(map, sym)) 461 if (filter && filter(map, sym))
427 symbol__delete(sym, self->sym_priv_size); 462 symbol__delete(sym);
428 else { 463 else {
429 dso__insert_symbol(self, sym); 464 dso__insert_symbol(self, sym);
430 nr_syms++; 465 nr_syms++;
@@ -532,7 +567,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
532 * And always look at the original dso, not at debuginfo packages, that 567 * And always look at the original dso, not at debuginfo packages, that
533 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 568 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
534 */ 569 */
535static int dso__synthesize_plt_symbols(struct dso *self) 570static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
571 symbol_filter_t filter)
536{ 572{
537 uint32_t nr_rel_entries, idx; 573 uint32_t nr_rel_entries, idx;
538 GElf_Sym sym; 574 GElf_Sym sym;
@@ -552,7 +588,7 @@ static int dso__synthesize_plt_symbols(struct dso *self)
552 if (fd < 0) 588 if (fd < 0)
553 goto out; 589 goto out;
554 590
555 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 591 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
556 if (elf == NULL) 592 if (elf == NULL)
557 goto out_close; 593 goto out_close;
558 594
@@ -616,12 +652,16 @@ static int dso__synthesize_plt_symbols(struct dso *self)
616 "%s@plt", elf_sym__name(&sym, symstrs)); 652 "%s@plt", elf_sym__name(&sym, symstrs));
617 653
618 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 654 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
619 sympltname, self->sym_priv_size); 655 sympltname);
620 if (!f) 656 if (!f)
621 goto out_elf_end; 657 goto out_elf_end;
622 658
623 dso__insert_symbol(self, f); 659 if (filter && filter(map, f))
624 ++nr; 660 symbol__delete(f);
661 else {
662 dso__insert_symbol(self, f);
663 ++nr;
664 }
625 } 665 }
626 } else if (shdr_rel_plt.sh_type == SHT_REL) { 666 } else if (shdr_rel_plt.sh_type == SHT_REL) {
627 GElf_Rel pos_mem, *pos; 667 GElf_Rel pos_mem, *pos;
@@ -634,12 +674,16 @@ static int dso__synthesize_plt_symbols(struct dso *self)
634 "%s@plt", elf_sym__name(&sym, symstrs)); 674 "%s@plt", elf_sym__name(&sym, symstrs));
635 675
636 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 676 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
637 sympltname, self->sym_priv_size); 677 sympltname);
638 if (!f) 678 if (!f)
639 goto out_elf_end; 679 goto out_elf_end;
640 680
641 dso__insert_symbol(self, f); 681 if (filter && filter(map, f))
642 ++nr; 682 symbol__delete(f);
683 else {
684 dso__insert_symbol(self, f);
685 ++nr;
686 }
643 } 687 }
644 } 688 }
645 689
@@ -676,7 +720,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
676 Elf *elf; 720 Elf *elf;
677 int nr = 0; 721 int nr = 0;
678 722
679 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 723 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
680 if (elf == NULL) { 724 if (elf == NULL) {
681 pr_err("%s: cannot read %s ELF file.\n", __func__, name); 725 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
682 goto out_close; 726 goto out_close;
@@ -769,7 +813,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
769 if (kmodule) 813 if (kmodule)
770 start += map->start + shdr.sh_offset; 814 start += map->start + shdr.sh_offset;
771 815
772 curr_dso = dso__new(dso_name, self->sym_priv_size); 816 curr_dso = dso__new(dso_name);
773 if (curr_dso == NULL) 817 if (curr_dso == NULL)
774 goto out_elf_end; 818 goto out_elf_end;
775 curr_map = map__new2(start, curr_dso); 819 curr_map = map__new2(start, curr_dso);
@@ -803,14 +847,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
803 if (demangled != NULL) 847 if (demangled != NULL)
804 elf_name = demangled; 848 elf_name = demangled;
805new_symbol: 849new_symbol:
806 f = symbol__new(sym.st_value, sym.st_size, elf_name, 850 f = symbol__new(sym.st_value, sym.st_size, elf_name);
807 curr_dso->sym_priv_size);
808 free(demangled); 851 free(demangled);
809 if (!f) 852 if (!f)
810 goto out_elf_end; 853 goto out_elf_end;
811 854
812 if (filter && filter(curr_map, f)) 855 if (filter && filter(curr_map, f))
813 symbol__delete(f, curr_dso->sym_priv_size); 856 symbol__delete(f);
814 else { 857 else {
815 dso__insert_symbol(curr_dso, f); 858 dso__insert_symbol(curr_dso, f);
816 nr++; 859 nr++;
@@ -829,27 +872,59 @@ out_close:
829 return err; 872 return err;
830} 873}
831 874
832#define BUILD_ID_SIZE 128 875bool fetch_build_id_table(struct list_head *head)
876{
877 bool have_buildid = false;
878 struct dso *pos;
833 879
834static char *dso__read_build_id(struct dso *self) 880 list_for_each_entry(pos, &dsos, node) {
881 struct build_id_list *new;
882 struct build_id_event b;
883 size_t len;
884
885 if (filename__read_build_id(pos->long_name,
886 &b.build_id,
887 sizeof(b.build_id)) < 0)
888 continue;
889 have_buildid = true;
890 memset(&b.header, 0, sizeof(b.header));
891 len = strlen(pos->long_name) + 1;
892 len = ALIGN(len, 64);
893 b.header.size = sizeof(b) + len;
894
895 new = malloc(sizeof(*new));
896 if (!new)
897 die("No memory\n");
898
899 memcpy(&new->event, &b, sizeof(b));
900 new->dso_name = pos->long_name;
901 new->len = len;
902
903 list_add_tail(&new->list, head);
904 }
905
906 return have_buildid;
907}
908
909int filename__read_build_id(const char *filename, void *bf, size_t size)
835{ 910{
836 int i; 911 int fd, err = -1;
837 GElf_Ehdr ehdr; 912 GElf_Ehdr ehdr;
838 GElf_Shdr shdr; 913 GElf_Shdr shdr;
839 Elf_Data *build_id_data; 914 Elf_Data *build_id_data;
840 Elf_Scn *sec; 915 Elf_Scn *sec;
841 char *build_id = NULL, *bid;
842 unsigned char *raw;
843 Elf *elf; 916 Elf *elf;
844 int fd = open(self->long_name, O_RDONLY);
845 917
918 if (size < BUILD_ID_SIZE)
919 goto out;
920
921 fd = open(filename, O_RDONLY);
846 if (fd < 0) 922 if (fd < 0)
847 goto out; 923 goto out;
848 924
849 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 925 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
850 if (elf == NULL) { 926 if (elf == NULL) {
851 pr_err("%s: cannot read %s ELF file.\n", __func__, 927 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
852 self->long_name);
853 goto out_close; 928 goto out_close;
854 } 929 }
855 930
@@ -858,30 +933,40 @@ static char *dso__read_build_id(struct dso *self)
858 goto out_elf_end; 933 goto out_elf_end;
859 } 934 }
860 935
861 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 936 sec = elf_section_by_name(elf, &ehdr, &shdr,
937 ".note.gnu.build-id", NULL);
862 if (sec == NULL) 938 if (sec == NULL)
863 goto out_elf_end; 939 goto out_elf_end;
864 940
865 build_id_data = elf_getdata(sec, NULL); 941 build_id_data = elf_getdata(sec, NULL);
866 if (build_id_data == NULL) 942 if (build_id_data == NULL)
867 goto out_elf_end; 943 goto out_elf_end;
868 build_id = malloc(BUILD_ID_SIZE); 944 memcpy(bf, build_id_data->d_buf + 16, BUILD_ID_SIZE);
869 if (build_id == NULL) 945 err = BUILD_ID_SIZE;
870 goto out_elf_end;
871 raw = build_id_data->d_buf + 16;
872 bid = build_id;
873
874 for (i = 0; i < 20; ++i) {
875 sprintf(bid, "%02x", *raw);
876 ++raw;
877 bid += 2;
878 }
879 pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id);
880out_elf_end: 946out_elf_end:
881 elf_end(elf); 947 elf_end(elf);
882out_close: 948out_close:
883 close(fd); 949 close(fd);
884out: 950out:
951 return err;
952}
953
954static char *dso__read_build_id(struct dso *self)
955{
956 int len;
957 char *build_id = NULL;
958 unsigned char rawbf[BUILD_ID_SIZE];
959
960 len = filename__read_build_id(self->long_name, rawbf, sizeof(rawbf));
961 if (len < 0)
962 goto out;
963
964 build_id = malloc(len * 2 + 1);
965 if (build_id == NULL)
966 goto out;
967
968 build_id__sprintf(rawbf, len, build_id);
969out:
885 return build_id; 970 return build_id;
886} 971}
887 972
@@ -909,6 +994,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
909 int ret = -1; 994 int ret = -1;
910 int fd; 995 int fd;
911 996
997 self->loaded = 1;
998
912 if (!name) 999 if (!name)
913 return -1; 1000 return -1;
914 1001
@@ -925,6 +1012,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
925 1012
926more: 1013more:
927 do { 1014 do {
1015 int berr = 0;
1016
928 self->origin++; 1017 self->origin++;
929 switch (self->origin) { 1018 switch (self->origin) {
930 case DSO__ORIG_FEDORA: 1019 case DSO__ORIG_FEDORA:
@@ -941,8 +1030,7 @@ more:
941 snprintf(name, size, 1030 snprintf(name, size,
942 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1031 "/usr/lib/debug/.build-id/%.2s/%s.debug",
943 build_id, build_id + 2); 1032 build_id, build_id + 2);
944 free(build_id); 1033 goto compare_build_id;
945 break;
946 } 1034 }
947 self->origin++; 1035 self->origin++;
948 /* Fall thru */ 1036 /* Fall thru */
@@ -954,6 +1042,22 @@ more:
954 goto out; 1042 goto out;
955 } 1043 }
956 1044
1045 if (self->has_build_id) {
1046 bool match;
1047 build_id = malloc(BUILD_ID_SIZE);
1048 if (build_id == NULL)
1049 goto more;
1050 berr = filename__read_build_id(name, build_id,
1051 BUILD_ID_SIZE);
1052compare_build_id:
1053 match = berr > 0 && memcmp(build_id, self->build_id,
1054 sizeof(self->build_id)) == 0;
1055 free(build_id);
1056 build_id = NULL;
1057 if (!match)
1058 goto more;
1059 }
1060
957 fd = open(name, O_RDONLY); 1061 fd = open(name, O_RDONLY);
958 } while (fd < 0); 1062 } while (fd < 0);
959 1063
@@ -967,7 +1071,7 @@ more:
967 goto more; 1071 goto more;
968 1072
969 if (ret > 0) { 1073 if (ret > 0) {
970 int nr_plt = dso__synthesize_plt_symbols(self); 1074 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
971 if (nr_plt > 0) 1075 if (nr_plt > 0)
972 ret += nr_plt; 1076 ret += nr_plt;
973 } 1077 }
@@ -1019,6 +1123,8 @@ static int dso__load_module_sym(struct dso *self, struct map *map,
1019{ 1123{
1020 int err = 0, fd = open(self->long_name, O_RDONLY); 1124 int err = 0, fd = open(self->long_name, O_RDONLY);
1021 1125
1126 self->loaded = 1;
1127
1022 if (fd < 0) { 1128 if (fd < 0) {
1023 pr_err("%s: cannot open %s\n", __func__, self->long_name); 1129 pr_err("%s: cannot open %s\n", __func__, self->long_name);
1024 return err; 1130 return err;
@@ -1128,22 +1234,16 @@ static struct map *map__new2(u64 start, struct dso *dso)
1128 struct map *self = malloc(sizeof(*self)); 1234 struct map *self = malloc(sizeof(*self));
1129 1235
1130 if (self != NULL) { 1236 if (self != NULL) {
1131 self->start = start;
1132 /* 1237 /*
1133 * Will be filled after we load all the symbols 1238 * ->end will be filled after we load all the symbols
1134 */ 1239 */
1135 self->end = 0; 1240 map__init(self, start, 0, 0, dso);
1136
1137 self->pgoff = 0;
1138 self->dso = dso;
1139 self->map_ip = map__map_ip;
1140 self->unmap_ip = map__unmap_ip;
1141 RB_CLEAR_NODE(&self->rb_node);
1142 } 1241 }
1242
1143 return self; 1243 return self;
1144} 1244}
1145 1245
1146static int dsos__load_modules(unsigned int sym_priv_size) 1246static int dsos__load_modules(void)
1147{ 1247{
1148 char *line = NULL; 1248 char *line = NULL;
1149 size_t n; 1249 size_t n;
@@ -1182,7 +1282,7 @@ static int dsos__load_modules(unsigned int sym_priv_size)
1182 *sep = '\0'; 1282 *sep = '\0';
1183 1283
1184 snprintf(name, sizeof(name), "[%s]", line); 1284 snprintf(name, sizeof(name), "[%s]", line);
1185 dso = dso__new(name, sym_priv_size); 1285 dso = dso__new(name);
1186 1286
1187 if (dso == NULL) 1287 if (dso == NULL)
1188 goto out_delete_line; 1288 goto out_delete_line;
@@ -1214,6 +1314,8 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1214{ 1314{
1215 int err, fd = open(vmlinux, O_RDONLY); 1315 int err, fd = open(vmlinux, O_RDONLY);
1216 1316
1317 self->loaded = 1;
1318
1217 if (fd < 0) 1319 if (fd < 0)
1218 return -1; 1320 return -1;
1219 1321
@@ -1224,11 +1326,11 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1224 return err; 1326 return err;
1225} 1327}
1226 1328
1227int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, 1329int dsos__load_kernel(const char *vmlinux, symbol_filter_t filter,
1228 symbol_filter_t filter, int use_modules) 1330 int use_modules)
1229{ 1331{
1230 int err = -1; 1332 int err = -1;
1231 struct dso *dso = dso__new(vmlinux, sym_priv_size); 1333 struct dso *dso = dso__new(vmlinux);
1232 1334
1233 if (dso == NULL) 1335 if (dso == NULL)
1234 return -1; 1336 return -1;
@@ -1240,7 +1342,7 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
1240 1342
1241 kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; 1343 kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
1242 1344
1243 if (use_modules && dsos__load_modules(sym_priv_size) < 0) { 1345 if (use_modules && dsos__load_modules() < 0) {
1244 pr_warning("Failed to load list of modules in use! " 1346 pr_warning("Failed to load list of modules in use! "
1245 "Continuing...\n"); 1347 "Continuing...\n");
1246 use_modules = 0; 1348 use_modules = 0;
@@ -1312,19 +1414,15 @@ static struct dso *dsos__find(const char *name)
1312 return NULL; 1414 return NULL;
1313} 1415}
1314 1416
1315struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size, 1417struct dso *dsos__findnew(const char *name)
1316 bool *is_new)
1317{ 1418{
1318 struct dso *dso = dsos__find(name); 1419 struct dso *dso = dsos__find(name);
1319 1420
1320 if (!dso) { 1421 if (!dso) {
1321 dso = dso__new(name, sym_priv_size); 1422 dso = dso__new(name);
1322 if (dso) { 1423 if (dso != NULL)
1323 dsos__add(dso); 1424 dsos__add(dso);
1324 *is_new = true; 1425 }
1325 }
1326 } else
1327 *is_new = false;
1328 1426
1329 return dso; 1427 return dso;
1330} 1428}
@@ -1337,13 +1435,24 @@ void dsos__fprintf(FILE *fp)
1337 dso__fprintf(pos, fp); 1435 dso__fprintf(pos, fp);
1338} 1436}
1339 1437
1340int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter) 1438size_t dsos__fprintf_buildid(FILE *fp)
1439{
1440 struct dso *pos;
1441 size_t ret = 0;
1442
1443 list_for_each_entry(pos, &dsos, node) {
1444 ret += dso__fprintf_buildid(pos, fp);
1445 ret += fprintf(fp, " %s\n", pos->long_name);
1446 }
1447 return ret;
1448}
1449
1450int load_kernel(symbol_filter_t filter)
1341{ 1451{
1342 if (dsos__load_kernel(vmlinux_name, sym_priv_size, filter, 1452 if (dsos__load_kernel(vmlinux_name, filter, modules) <= 0)
1343 modules) <= 0)
1344 return -1; 1453 return -1;
1345 1454
1346 vdso = dso__new("[vdso]", 0); 1455 vdso = dso__new("[vdso]");
1347 if (!vdso) 1456 if (!vdso)
1348 return -1; 1457 return -1;
1349 1458
@@ -1352,7 +1461,8 @@ int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter)
1352 return 0; 1461 return 0;
1353} 1462}
1354 1463
1355void symbol__init(void) 1464void symbol__init(unsigned int priv_size)
1356{ 1465{
1357 elf_version(EV_CURRENT); 1466 elf_version(EV_CURRENT);
1467 symbol__priv_size = priv_size;
1358} 1468}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 77b7b3e42417..51c5a4a08133 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -27,6 +27,16 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
27#endif 27#endif
28#endif 28#endif
29 29
30/*
31 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
32 * for newer versions we can use mmap to reduce memory usage:
33 */
34#ifdef LIBELF_NO_MMAP
35# define PERF_ELF_C_READ_MMAP ELF_C_READ
36#else
37# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP
38#endif
39
30#ifndef DMGL_PARAMS 40#ifndef DMGL_PARAMS
31#define DMGL_PARAMS (1 << 0) /* Include function args */ 41#define DMGL_PARAMS (1 << 0) /* Include function args */
32#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 42#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
@@ -39,42 +49,51 @@ struct symbol {
39 char name[0]; 49 char name[0];
40}; 50};
41 51
52extern unsigned int symbol__priv_size;
53
54static inline void *symbol__priv(struct symbol *self)
55{
56 return ((void *)self) - symbol__priv_size;
57}
58
42struct dso { 59struct dso {
43 struct list_head node; 60 struct list_head node;
44 struct rb_root syms; 61 struct rb_root syms;
45 struct symbol *(*find_symbol)(struct dso *, u64 ip); 62 struct symbol *(*find_symbol)(struct dso *, u64 ip);
46 unsigned int sym_priv_size; 63 u8 adjust_symbols:1;
47 unsigned char adjust_symbols; 64 u8 slen_calculated:1;
48 unsigned char slen_calculated; 65 u8 loaded:1;
66 u8 has_build_id:1;
49 unsigned char origin; 67 unsigned char origin;
68 u8 build_id[BUILD_ID_SIZE];
50 const char *short_name; 69 const char *short_name;
51 char *long_name; 70 char *long_name;
52 char name[0]; 71 char name[0];
53}; 72};
54 73
55struct dso *dso__new(const char *name, unsigned int sym_priv_size); 74struct dso *dso__new(const char *name);
56void dso__delete(struct dso *self); 75void dso__delete(struct dso *self);
57 76
58static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
59{
60 return ((void *)sym) - self->sym_priv_size;
61}
62
63struct symbol *dso__find_symbol(struct dso *self, u64 ip); 77struct symbol *dso__find_symbol(struct dso *self, u64 ip);
64 78
65int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, 79int dsos__load_kernel(const char *vmlinux, symbol_filter_t filter, int modules);
66 symbol_filter_t filter, int modules); 80struct dso *dsos__findnew(const char *name);
67struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size,
68 bool *is_new);
69int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 81int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
70void dsos__fprintf(FILE *fp); 82void dsos__fprintf(FILE *fp);
83size_t dsos__fprintf_buildid(FILE *fp);
71 84
85size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
72size_t dso__fprintf(struct dso *self, FILE *fp); 86size_t dso__fprintf(struct dso *self, FILE *fp);
73char dso__symtab_origin(const struct dso *self); 87char dso__symtab_origin(const struct dso *self);
88void dso__set_build_id(struct dso *self, void *build_id);
89
90int filename__read_build_id(const char *filename, void *bf, size_t size);
91bool fetch_build_id_table(struct list_head *head);
92int build_id__sprintf(u8 *self, int len, char *bf);
74 93
75int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter); 94int load_kernel(symbol_filter_t filter);
76 95
77void symbol__init(void); 96void symbol__init(unsigned int priv_size);
78 97
79extern struct list_head dsos; 98extern struct list_head dsos;
80extern struct map *kernel_map; 99extern struct map *kernel_map;
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0daa341734f9..f2203a0946bc 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -315,6 +315,7 @@ static inline int has_extension(const char *filename, const char *ext)
315#undef isascii 315#undef isascii
316#undef isspace 316#undef isspace
317#undef isdigit 317#undef isdigit
318#undef isxdigit
318#undef isalpha 319#undef isalpha
319#undef isprint 320#undef isprint
320#undef isalnum 321#undef isalnum
@@ -332,6 +333,8 @@ extern unsigned char sane_ctype[256];
332#define isascii(x) (((x) & ~0x7f) == 0) 333#define isascii(x) (((x) & ~0x7f) == 0)
333#define isspace(x) sane_istest(x,GIT_SPACE) 334#define isspace(x) sane_istest(x,GIT_SPACE)
334#define isdigit(x) sane_istest(x,GIT_DIGIT) 335#define isdigit(x) sane_istest(x,GIT_DIGIT)
336#define isxdigit(x) \
337 (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G')
335#define isalpha(x) sane_istest(x,GIT_ALPHA) 338#define isalpha(x) sane_istest(x,GIT_ALPHA)
336#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 339#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
337#define isprint(x) sane_istest(x,GIT_PRINT) 340#define isprint(x) sane_istest(x,GIT_PRINT)