aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-12-14 22:10:10 -0500
committerPaul Mundt <lethal@linux-sh.org>2009-12-14 22:10:10 -0500
commite0aa51f54faa0659b529143de6c608e76675326f (patch)
tree22fc566b74bfe6bd612a858ba354818900cdc394 /tools/perf
parent9f815a1765b0ce766ab1d26ef192d30410f70b2b (diff)
parent3ea6b3d0e6d0ffd91c0f8cadeb69b7133c038b32 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-kmem.txt13
-rw-r--r--tools/perf/Documentation/perf-probe.txt21
-rw-r--r--tools/perf/Makefile9
-rw-r--r--tools/perf/bench/sched-messaging.c8
-rw-r--r--tools/perf/bench/sched-pipe.c11
-rw-r--r--tools/perf/builtin-annotate.c15
-rw-r--r--tools/perf/builtin-bench.c57
-rw-r--r--tools/perf/builtin-buildid-list.c57
-rw-r--r--tools/perf/builtin-kmem.c138
-rw-r--r--tools/perf/builtin-probe.c80
-rw-r--r--tools/perf/builtin-record.c25
-rw-r--r--tools/perf/builtin-report.c59
-rw-r--r--tools/perf/builtin-sched.c225
-rw-r--r--tools/perf/builtin-timechart.c69
-rw-r--r--tools/perf/builtin-trace.c68
-rw-r--r--tools/perf/perf.h12
-rw-r--r--tools/perf/util/data_map.c75
-rw-r--r--tools/perf/util/data_map.h11
-rw-r--r--tools/perf/util/event.c78
-rw-r--r--tools/perf/util/event.h24
-rw-r--r--tools/perf/util/header.c37
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/map.c87
-rw-r--r--tools/perf/util/parse-events.c17
-rw-r--r--tools/perf/util/parse-options.c3
-rw-r--r--tools/perf/util/probe-event.c133
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-finder.c2
-rw-r--r--tools/perf/util/session.c80
-rw-r--r--tools/perf/util/session.h16
-rw-r--r--tools/perf/util/symbol.c273
-rw-r--r--tools/perf/util/symbol.h17
-rw-r--r--tools/perf/util/thread.c63
-rw-r--r--tools/perf/util/thread.h42
-rw-r--r--tools/perf/util/trace-event-parse.c4
-rw-r--r--tools/perf/util/trace-event-perl.c67
-rw-r--r--tools/perf/util/trace-event-perl.h4
-rw-r--r--tools/perf/util/trace-event-read.c3
38 files changed, 1216 insertions, 692 deletions
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
index 44b0ce35c28a..eac4d852e7cd 100644
--- a/tools/perf/Documentation/perf-kmem.txt
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -8,16 +8,16 @@ perf-kmem - Tool to trace/measure kernel memory(slab) properties
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf kmem' {record} [<options>] 11'perf kmem' {record|stat} [<options>]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15There's two variants of perf kmem: 15There are two variants of perf kmem:
16 16
17 'perf kmem record <command>' to record the kmem events 17 'perf kmem record <command>' to record the kmem events
18 of an arbitrary workload. 18 of an arbitrary workload.
19 19
20 'perf kmem' to report kernel memory statistics. 20 'perf kmem stat' to report kernel memory statistics.
21 21
22OPTIONS 22OPTIONS
23------- 23-------
@@ -25,8 +25,11 @@ OPTIONS
25--input=<file>:: 25--input=<file>::
26 Select the input file (default: perf.data) 26 Select the input file (default: perf.data)
27 27
28--stat=<caller|alloc>:: 28--caller::
29 Select per callsite or per allocation statistics 29 Show per-callsite statistics
30
31--alloc::
32 Show per-allocation statistics
30 33
31-s <key[,key2...]>:: 34-s <key[,key2...]>::
32--sort=<key[,key2...]>:: 35--sort=<key[,key2...]>::
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 9270594e6dfd..8fa6bf99fcb5 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -8,10 +8,13 @@ perf-probe - Define new dynamic tracepoints
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf probe' [options] --add 'PROBE' [--add 'PROBE' ...] 11'perf probe' [options] --add='PROBE' [...]
12or 12or
13'perf probe' [options] 'PROBE' ['PROBE' ...] 13'perf probe' [options] PROBE
14 14or
15'perf probe' [options] --del='[GROUP:]EVENT' [...]
16or
17'perf probe' --list
15 18
16DESCRIPTION 19DESCRIPTION
17----------- 20-----------
@@ -31,8 +34,16 @@ OPTIONS
31 Be more verbose (show parsed arguments, etc). 34 Be more verbose (show parsed arguments, etc).
32 35
33-a:: 36-a::
34--add:: 37--add=::
35 Define a probe point (see PROBE SYNTAX for detail) 38 Define a probe event (see PROBE SYNTAX for detail).
39
40-d::
41--del=::
42 Delete a probe event.
43
44-l::
45--list::
46 List up current probe events.
36 47
37PROBE SYNTAX 48PROBE SYNTAX
38------------ 49------------
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 23ec66098bdc..406999668cab 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -237,8 +237,8 @@ lib = lib
237 237
238export prefix bindir sharedir sysconfdir 238export prefix bindir sharedir sysconfdir
239 239
240CC = gcc 240CC = $(CROSS_COMPILE)gcc
241AR = ar 241AR = $(CROSS_COMPILE)ar
242RM = rm -f 242RM = rm -f
243TAR = tar 243TAR = tar
244FIND = find 244FIND = find
@@ -356,7 +356,9 @@ LIB_H += util/parse-options.h
356LIB_H += util/parse-events.h 356LIB_H += util/parse-events.h
357LIB_H += util/quote.h 357LIB_H += util/quote.h
358LIB_H += util/util.h 358LIB_H += util/util.h
359LIB_H += util/header.h
359LIB_H += util/help.h 360LIB_H += util/help.h
361LIB_H += util/session.h
360LIB_H += util/strbuf.h 362LIB_H += util/strbuf.h
361LIB_H += util/string.h 363LIB_H += util/string.h
362LIB_H += util/strlist.h 364LIB_H += util/strlist.h
@@ -405,6 +407,7 @@ LIB_OBJS += util/callchain.o
405LIB_OBJS += util/values.o 407LIB_OBJS += util/values.o
406LIB_OBJS += util/debug.o 408LIB_OBJS += util/debug.o
407LIB_OBJS += util/map.o 409LIB_OBJS += util/map.o
410LIB_OBJS += util/session.o
408LIB_OBJS += util/thread.o 411LIB_OBJS += util/thread.o
409LIB_OBJS += util/trace-event-parse.o 412LIB_OBJS += util/trace-event-parse.o
410LIB_OBJS += util/trace-event-read.o 413LIB_OBJS += util/trace-event-read.o
@@ -492,8 +495,10 @@ else
492 LIB_OBJS += util/probe-finder.o 495 LIB_OBJS += util/probe-finder.o
493endif 496endif
494 497
498ifndef NO_LIBPERL
495PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` 499PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
496PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 500PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
501endif
497 502
498ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) 503ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
499 BASIC_CFLAGS += -DNO_LIBPERL 504 BASIC_CFLAGS += -DNO_LIBPERL
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index 605a2a959aa8..81cee78181fa 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * builtin-bench-messaging.c 3 * sched-messaging.c
4 * 4 *
5 * messaging: Benchmark for scheduler and IPC mechanisms 5 * messaging: Benchmark for scheduler and IPC mechanisms
6 * 6 *
@@ -320,10 +320,12 @@ int bench_sched_messaging(int argc, const char **argv,
320 num_groups, num_groups * 2 * num_fds, 320 num_groups, num_groups * 2 * num_fds,
321 thread_mode ? "threads" : "processes"); 321 thread_mode ? "threads" : "processes");
322 printf(" %14s: %lu.%03lu [sec]\n", "Total time", 322 printf(" %14s: %lu.%03lu [sec]\n", "Total time",
323 diff.tv_sec, diff.tv_usec/1000); 323 diff.tv_sec,
324 (unsigned long) (diff.tv_usec/1000));
324 break; 325 break;
325 case BENCH_FORMAT_SIMPLE: 326 case BENCH_FORMAT_SIMPLE:
326 printf("%lu.%03lu\n", diff.tv_sec, diff.tv_usec/1000); 327 printf("%lu.%03lu\n", diff.tv_sec,
328 (unsigned long) (diff.tv_usec/1000));
327 break; 329 break;
328 default: 330 default:
329 /* reaching here is something disaster */ 331 /* reaching here is something disaster */
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 238185f97977..4f77c7c27640 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * builtin-bench-pipe.c 3 * sched-pipe.c
4 * 4 *
5 * pipe: Benchmark for pipe() 5 * pipe: Benchmark for pipe()
6 * 6 *
@@ -87,7 +87,8 @@ int bench_sched_pipe(int argc, const char **argv,
87 if (pid) { 87 if (pid) {
88 retpid = waitpid(pid, &wait_stat, 0); 88 retpid = waitpid(pid, &wait_stat, 0);
89 assert((retpid == pid) && WIFEXITED(wait_stat)); 89 assert((retpid == pid) && WIFEXITED(wait_stat));
90 return 0; 90 } else {
91 exit(0);
91 } 92 }
92 93
93 switch (bench_format) { 94 switch (bench_format) {
@@ -99,7 +100,8 @@ int bench_sched_pipe(int argc, const char **argv,
99 result_usec += diff.tv_usec; 100 result_usec += diff.tv_usec;
100 101
101 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", 102 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
102 diff.tv_sec, diff.tv_usec/1000); 103 diff.tv_sec,
104 (unsigned long) (diff.tv_usec/1000));
103 105
104 printf(" %14lf usecs/op\n", 106 printf(" %14lf usecs/op\n",
105 (double)result_usec / (double)loops); 107 (double)result_usec / (double)loops);
@@ -110,7 +112,8 @@ int bench_sched_pipe(int argc, const char **argv,
110 112
111 case BENCH_FORMAT_SIMPLE: 113 case BENCH_FORMAT_SIMPLE:
112 printf("%lu.%03lu\n", 114 printf("%lu.%03lu\n",
113 diff.tv_sec, diff.tv_usec / 1000); 115 diff.tv_sec,
116 (unsigned long) (diff.tv_usec / 1000));
114 break; 117 break;
115 118
116 default: 119 default:
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 0bf2e8f9af57..21a78d30d53d 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -25,6 +25,7 @@
25#include "util/thread.h" 25#include "util/thread.h"
26#include "util/sort.h" 26#include "util/sort.h"
27#include "util/hist.h" 27#include "util/hist.h"
28#include "util/session.h"
28#include "util/data_map.h" 29#include "util/data_map.h"
29 30
30static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
@@ -462,21 +463,23 @@ static struct perf_file_handler file_handler = {
462 463
463static int __cmd_annotate(void) 464static int __cmd_annotate(void)
464{ 465{
465 struct perf_header *header; 466 struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
466 struct thread *idle; 467 struct thread *idle;
467 int ret; 468 int ret;
468 469
470 if (session == NULL)
471 return -ENOMEM;
472
469 idle = register_idle_thread(); 473 idle = register_idle_thread();
470 register_perf_file_handler(&file_handler); 474 register_perf_file_handler(&file_handler);
471 475
472 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0, 476 ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
473 &event__cwdlen, &event__cwd);
474 if (ret) 477 if (ret)
475 return ret; 478 goto out_delete;
476 479
477 if (dump_trace) { 480 if (dump_trace) {
478 event__print_totals(); 481 event__print_totals();
479 return 0; 482 goto out_delete;
480 } 483 }
481 484
482 if (verbose > 3) 485 if (verbose > 3)
@@ -489,6 +492,8 @@ static int __cmd_annotate(void)
489 output__resort(event__total[0]); 492 output__resort(event__total[0]);
490 493
491 find_annotations(); 494 find_annotations();
495out_delete:
496 perf_session__delete(session);
492 497
493 return ret; 498 return ret;
494} 499}
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index e043eb83092a..46996774e559 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -31,6 +31,9 @@ struct bench_suite {
31 const char *summary; 31 const char *summary;
32 int (*fn)(int, const char **, const char *); 32 int (*fn)(int, const char **, const char *);
33}; 33};
34 \
35/* sentinel: easy for help */
36#define suite_all { "all", "test all suite (pseudo suite)", NULL }
34 37
35static struct bench_suite sched_suites[] = { 38static struct bench_suite sched_suites[] = {
36 { "messaging", 39 { "messaging",
@@ -39,6 +42,7 @@ static struct bench_suite sched_suites[] = {
39 { "pipe", 42 { "pipe",
40 "Flood of communication over pipe() between two processes", 43 "Flood of communication over pipe() between two processes",
41 bench_sched_pipe }, 44 bench_sched_pipe },
45 suite_all,
42 { NULL, 46 { NULL,
43 NULL, 47 NULL,
44 NULL } 48 NULL }
@@ -48,6 +52,7 @@ static struct bench_suite mem_suites[] = {
48 { "memcpy", 52 { "memcpy",
49 "Simple memory copy in various ways", 53 "Simple memory copy in various ways",
50 bench_mem_memcpy }, 54 bench_mem_memcpy },
55 suite_all,
51 { NULL, 56 { NULL,
52 NULL, 57 NULL,
53 NULL } 58 NULL }
@@ -66,6 +71,9 @@ static struct bench_subsys subsystems[] = {
66 { "mem", 71 { "mem",
67 "memory access performance", 72 "memory access performance",
68 mem_suites }, 73 mem_suites },
74 { "all", /* sentinel: easy for help */
75 "test all subsystem (pseudo subsystem)",
76 NULL },
69 { NULL, 77 { NULL,
70 NULL, 78 NULL,
71 NULL } 79 NULL }
@@ -75,11 +83,11 @@ static void dump_suites(int subsys_index)
75{ 83{
76 int i; 84 int i;
77 85
78 printf("List of available suites for %s...\n\n", 86 printf("# List of available suites for %s...\n\n",
79 subsystems[subsys_index].name); 87 subsystems[subsys_index].name);
80 88
81 for (i = 0; subsystems[subsys_index].suites[i].name; i++) 89 for (i = 0; subsystems[subsys_index].suites[i].name; i++)
82 printf("\t%s: %s\n", 90 printf("%14s: %s\n",
83 subsystems[subsys_index].suites[i].name, 91 subsystems[subsys_index].suites[i].name,
84 subsystems[subsys_index].suites[i].summary); 92 subsystems[subsys_index].suites[i].summary);
85 93
@@ -110,10 +118,10 @@ static void print_usage(void)
110 printf("\t%s\n", bench_usage[i]); 118 printf("\t%s\n", bench_usage[i]);
111 printf("\n"); 119 printf("\n");
112 120
113 printf("List of available subsystems...\n\n"); 121 printf("# List of available subsystems...\n\n");
114 122
115 for (i = 0; subsystems[i].name; i++) 123 for (i = 0; subsystems[i].name; i++)
116 printf("\t%s: %s\n", 124 printf("%14s: %s\n",
117 subsystems[i].name, subsystems[i].summary); 125 subsystems[i].name, subsystems[i].summary);
118 printf("\n"); 126 printf("\n");
119} 127}
@@ -131,6 +139,37 @@ static int bench_str2int(char *str)
131 return BENCH_FORMAT_UNKNOWN; 139 return BENCH_FORMAT_UNKNOWN;
132} 140}
133 141
142static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
143{
144 int i;
145 const char *argv[2];
146 struct bench_suite *suites = subsys->suites;
147
148 argv[1] = NULL;
149 /*
150 * TODO:
151 * preparing preset parameters for
152 * embedded, ordinary PC, HPC, etc...
153 * will be helpful
154 */
155 for (i = 0; suites[i].fn; i++) {
156 printf("# Running %s/%s benchmark...\n",
157 subsys->name,
158 suites[i].name);
159
160 argv[1] = suites[i].name;
161 suites[i].fn(1, argv, NULL);
162 printf("\n");
163 }
164}
165
166static void all_subsystem(void)
167{
168 int i;
169 for (i = 0; subsystems[i].suites; i++)
170 all_suite(&subsystems[i]);
171}
172
134int cmd_bench(int argc, const char **argv, const char *prefix __used) 173int cmd_bench(int argc, const char **argv, const char *prefix __used)
135{ 174{
136 int i, j, status = 0; 175 int i, j, status = 0;
@@ -155,6 +194,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
155 goto end; 194 goto end;
156 } 195 }
157 196
197 if (!strcmp(argv[0], "all")) {
198 all_subsystem();
199 goto end;
200 }
201
158 for (i = 0; subsystems[i].name; i++) { 202 for (i = 0; subsystems[i].name; i++) {
159 if (strcmp(subsystems[i].name, argv[0])) 203 if (strcmp(subsystems[i].name, argv[0]))
160 continue; 204 continue;
@@ -165,6 +209,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
165 goto end; 209 goto end;
166 } 210 }
167 211
212 if (!strcmp(argv[1], "all")) {
213 all_suite(&subsystems[i]);
214 goto end;
215 }
216
168 for (j = 0; subsystems[i].suites[j].name; j++) { 217 for (j = 0; subsystems[i].suites[j].name; j++) {
169 if (strcmp(subsystems[i].suites[j].name, argv[1])) 218 if (strcmp(subsystems[i].suites[j].name, argv[1]))
170 continue; 219 continue;
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 7dee9d19ab7a..bfd16a1594e4 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -11,15 +11,15 @@
11#include "util/cache.h" 11#include "util/cache.h"
12#include "util/data_map.h" 12#include "util/data_map.h"
13#include "util/debug.h" 13#include "util/debug.h"
14#include "util/header.h"
15#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/session.h"
16#include "util/symbol.h" 16#include "util/symbol.h"
17 17
18static char const *input_name = "perf.data"; 18static char const *input_name = "perf.data";
19static int force; 19static int force;
20 20
21static const char *const buildid_list_usage[] = { 21static const char *const buildid_list_usage[] = {
22 "perf report [<options>]", 22 "perf buildid-list [<options>]",
23 NULL 23 NULL
24}; 24};
25 25
@@ -55,56 +55,17 @@ static int perf_file_section__process_buildids(struct perf_file_section *self,
55static int __cmd_buildid_list(void) 55static int __cmd_buildid_list(void)
56{ 56{
57 int err = -1; 57 int err = -1;
58 struct perf_header *header; 58 struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
59 struct perf_file_header f_header;
60 struct stat input_stat;
61 int input = open(input_name, O_RDONLY);
62 59
63 if (input < 0) { 60 if (session == NULL)
64 pr_err("failed to open file: %s", input_name); 61 return -1;
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 62
98 err = perf_header__process_sections(header, input, 63 err = perf_header__process_sections(&session->header, session->fd,
99 perf_file_section__process_buildids); 64 perf_file_section__process_buildids);
65 if (err >= 0)
66 dsos__fprintf_buildid(stdout);
100 67
101 if (err < 0) 68 perf_session__delete(session);
102 goto out_close;
103
104 dsos__fprintf_buildid(stdout);
105out_close:
106 close(input);
107out:
108 return err; 69 return err;
109} 70}
110 71
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 047fef74bd52..2071d2485913 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -6,6 +6,7 @@
6#include "util/symbol.h" 6#include "util/symbol.h"
7#include "util/thread.h" 7#include "util/thread.h"
8#include "util/header.h" 8#include "util/header.h"
9#include "util/session.h"
9 10
10#include "util/parse-options.h" 11#include "util/parse-options.h"
11#include "util/trace-event.h" 12#include "util/trace-event.h"
@@ -20,7 +21,6 @@ typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
20 21
21static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
22 23
23static struct perf_header *header;
24static u64 sample_type; 24static u64 sample_type;
25 25
26static int alloc_flag; 26static int alloc_flag;
@@ -57,11 +57,6 @@ static struct rb_root root_caller_sorted;
57static unsigned long total_requested, total_allocated; 57static unsigned long total_requested, total_allocated;
58static unsigned long nr_allocs, nr_cross_allocs; 58static unsigned long nr_allocs, nr_cross_allocs;
59 59
60struct raw_event_sample {
61 u32 size;
62 char data[0];
63};
64
65#define PATH_SYS_NODE "/sys/devices/system/node" 60#define PATH_SYS_NODE "/sys/devices/system/node"
66 61
67static void init_cpunode_map(void) 62static void init_cpunode_map(void)
@@ -201,7 +196,7 @@ static void insert_caller_stat(unsigned long call_site,
201 } 196 }
202} 197}
203 198
204static void process_alloc_event(struct raw_event_sample *raw, 199static void process_alloc_event(void *data,
205 struct event *event, 200 struct event *event,
206 int cpu, 201 int cpu,
207 u64 timestamp __used, 202 u64 timestamp __used,
@@ -214,10 +209,10 @@ static void process_alloc_event(struct raw_event_sample *raw,
214 int bytes_alloc; 209 int bytes_alloc;
215 int node1, node2; 210 int node1, node2;
216 211
217 ptr = raw_field_value(event, "ptr", raw->data); 212 ptr = raw_field_value(event, "ptr", data);
218 call_site = raw_field_value(event, "call_site", raw->data); 213 call_site = raw_field_value(event, "call_site", data);
219 bytes_req = raw_field_value(event, "bytes_req", raw->data); 214 bytes_req = raw_field_value(event, "bytes_req", data);
220 bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data); 215 bytes_alloc = raw_field_value(event, "bytes_alloc", data);
221 216
222 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu); 217 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
223 insert_caller_stat(call_site, bytes_req, bytes_alloc); 218 insert_caller_stat(call_site, bytes_req, bytes_alloc);
@@ -227,7 +222,7 @@ static void process_alloc_event(struct raw_event_sample *raw,
227 222
228 if (node) { 223 if (node) {
229 node1 = cpunode_map[cpu]; 224 node1 = cpunode_map[cpu];
230 node2 = raw_field_value(event, "node", raw->data); 225 node2 = raw_field_value(event, "node", data);
231 if (node1 != node2) 226 if (node1 != node2)
232 nr_cross_allocs++; 227 nr_cross_allocs++;
233 } 228 }
@@ -262,7 +257,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr,
262 return NULL; 257 return NULL;
263} 258}
264 259
265static void process_free_event(struct raw_event_sample *raw, 260static void process_free_event(void *data,
266 struct event *event, 261 struct event *event,
267 int cpu, 262 int cpu,
268 u64 timestamp __used, 263 u64 timestamp __used,
@@ -271,7 +266,7 @@ static void process_free_event(struct raw_event_sample *raw,
271 unsigned long ptr; 266 unsigned long ptr;
272 struct alloc_stat *s_alloc, *s_caller; 267 struct alloc_stat *s_alloc, *s_caller;
273 268
274 ptr = raw_field_value(event, "ptr", raw->data); 269 ptr = raw_field_value(event, "ptr", data);
275 270
276 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); 271 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
277 if (!s_alloc) 272 if (!s_alloc)
@@ -289,66 +284,53 @@ static void process_free_event(struct raw_event_sample *raw,
289} 284}
290 285
291static void 286static void
292process_raw_event(event_t *raw_event __used, void *more_data, 287process_raw_event(event_t *raw_event __used, void *data,
293 int cpu, u64 timestamp, struct thread *thread) 288 int cpu, u64 timestamp, struct thread *thread)
294{ 289{
295 struct raw_event_sample *raw = more_data;
296 struct event *event; 290 struct event *event;
297 int type; 291 int type;
298 292
299 type = trace_parse_common_type(raw->data); 293 type = trace_parse_common_type(data);
300 event = trace_find_event(type); 294 event = trace_find_event(type);
301 295
302 if (!strcmp(event->name, "kmalloc") || 296 if (!strcmp(event->name, "kmalloc") ||
303 !strcmp(event->name, "kmem_cache_alloc")) { 297 !strcmp(event->name, "kmem_cache_alloc")) {
304 process_alloc_event(raw, event, cpu, timestamp, thread, 0); 298 process_alloc_event(data, event, cpu, timestamp, thread, 0);
305 return; 299 return;
306 } 300 }
307 301
308 if (!strcmp(event->name, "kmalloc_node") || 302 if (!strcmp(event->name, "kmalloc_node") ||
309 !strcmp(event->name, "kmem_cache_alloc_node")) { 303 !strcmp(event->name, "kmem_cache_alloc_node")) {
310 process_alloc_event(raw, event, cpu, timestamp, thread, 1); 304 process_alloc_event(data, event, cpu, timestamp, thread, 1);
311 return; 305 return;
312 } 306 }
313 307
314 if (!strcmp(event->name, "kfree") || 308 if (!strcmp(event->name, "kfree") ||
315 !strcmp(event->name, "kmem_cache_free")) { 309 !strcmp(event->name, "kmem_cache_free")) {
316 process_free_event(raw, event, cpu, timestamp, thread); 310 process_free_event(data, event, cpu, timestamp, thread);
317 return; 311 return;
318 } 312 }
319} 313}
320 314
321static int process_sample_event(event_t *event) 315static int process_sample_event(event_t *event)
322{ 316{
323 u64 ip = event->ip.ip; 317 struct sample_data data;
324 u64 timestamp = -1; 318 struct thread *thread;
325 u32 cpu = -1;
326 u64 period = 1;
327 void *more_data = event->ip.__more_data;
328 struct thread *thread = threads__findnew(event->ip.pid);
329
330 if (sample_type & PERF_SAMPLE_TIME) {
331 timestamp = *(u64 *)more_data;
332 more_data += sizeof(u64);
333 }
334 319
335 if (sample_type & PERF_SAMPLE_CPU) { 320 memset(&data, 0, sizeof(data));
336 cpu = *(u32 *)more_data; 321 data.time = -1;
337 more_data += sizeof(u32); 322 data.cpu = -1;
338 more_data += sizeof(u32); /* reserved */ 323 data.period = 1;
339 }
340 324
341 if (sample_type & PERF_SAMPLE_PERIOD) { 325 event__parse_sample(event, sample_type, &data);
342 period = *(u64 *)more_data;
343 more_data += sizeof(u64);
344 }
345 326
346 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 327 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
347 event->header.misc, 328 event->header.misc,
348 event->ip.pid, event->ip.tid, 329 data.pid, data.tid,
349 (void *)(long)ip, 330 (void *)(long)data.ip,
350 (long long)period); 331 (long long)data.period);
351 332
333 thread = threads__findnew(event->ip.pid);
352 if (thread == NULL) { 334 if (thread == NULL) {
353 pr_debug("problem processing %d event, skipping it.\n", 335 pr_debug("problem processing %d event, skipping it.\n",
354 event->header.type); 336 event->header.type);
@@ -357,7 +339,8 @@ static int process_sample_event(event_t *event)
357 339
358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 340 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
359 341
360 process_raw_event(event, more_data, cpu, timestamp, thread); 342 process_raw_event(event, data.raw_data, data.cpu,
343 data.time, thread);
361 344
362 return 0; 345 return 0;
363} 346}
@@ -384,11 +367,18 @@ static struct perf_file_handler file_handler = {
384 367
385static int read_events(void) 368static int read_events(void)
386{ 369{
370 int err;
371 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
372
373 if (session == NULL)
374 return -ENOMEM;
375
387 register_idle_thread(); 376 register_idle_thread();
388 register_perf_file_handler(&file_handler); 377 register_perf_file_handler(&file_handler);
389 378
390 return mmap_dispatch_perf_file(&header, input_name, 0, 0, 379 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
391 &event__cwdlen, &event__cwd); 380 perf_session__delete(session);
381 return err;
392} 382}
393 383
394static double fragmentation(unsigned long n_req, unsigned long n_alloc) 384static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -420,7 +410,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
420 if (is_caller) { 410 if (is_caller) {
421 addr = data->call_site; 411 addr = data->call_site;
422 if (!raw_ip) 412 if (!raw_ip)
423 sym = thread__find_function(kthread, addr, NULL); 413 sym = map_groups__find_function(kmaps, addr, NULL);
424 } else 414 } else
425 addr = data->ptr; 415 addr = data->ptr;
426 416
@@ -543,7 +533,7 @@ static int __cmd_kmem(void)
543} 533}
544 534
545static const char * const kmem_usage[] = { 535static const char * const kmem_usage[] = {
546 "perf kmem [<options>] {record}", 536 "perf kmem [<options>] {record|stat}",
547 NULL 537 NULL
548}; 538};
549 539
@@ -703,18 +693,17 @@ static int parse_sort_opt(const struct option *opt __used,
703 return 0; 693 return 0;
704} 694}
705 695
706static int parse_stat_opt(const struct option *opt __used, 696static int parse_caller_opt(const struct option *opt __used,
707 const char *arg, int unset __used) 697 const char *arg __used, int unset __used)
708{ 698{
709 if (!arg) 699 caller_flag = (alloc_flag + 1);
710 return -1; 700 return 0;
701}
711 702
712 if (strcmp(arg, "alloc") == 0) 703static int parse_alloc_opt(const struct option *opt __used,
713 alloc_flag = (caller_flag + 1); 704 const char *arg __used, int unset __used)
714 else if (strcmp(arg, "caller") == 0) 705{
715 caller_flag = (alloc_flag + 1); 706 alloc_flag = (caller_flag + 1);
716 else
717 return -1;
718 return 0; 707 return 0;
719} 708}
720 709
@@ -739,14 +728,17 @@ static int parse_line_opt(const struct option *opt __used,
739static const struct option kmem_options[] = { 728static const struct option kmem_options[] = {
740 OPT_STRING('i', "input", &input_name, "file", 729 OPT_STRING('i', "input", &input_name, "file",
741 "input file name"), 730 "input file name"),
742 OPT_CALLBACK(0, "stat", NULL, "<alloc>|<caller>", 731 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
743 "stat selector, Pass 'alloc' or 'caller'.", 732 "show per-callsite statistics",
744 parse_stat_opt), 733 parse_caller_opt),
734 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
735 "show per-allocation statistics",
736 parse_alloc_opt),
745 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", 737 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
746 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", 738 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
747 parse_sort_opt), 739 parse_sort_opt),
748 OPT_CALLBACK('l', "line", NULL, "num", 740 OPT_CALLBACK('l', "line", NULL, "num",
749 "show n lins", 741 "show n lines",
750 parse_line_opt), 742 parse_line_opt),
751 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), 743 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
752 OPT_END() 744 OPT_END()
@@ -790,18 +782,22 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __used)
790 782
791 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); 783 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
792 784
793 if (argc && !strncmp(argv[0], "rec", 3)) 785 if (!argc)
794 return __cmd_record(argc, argv);
795 else if (argc)
796 usage_with_options(kmem_usage, kmem_options); 786 usage_with_options(kmem_usage, kmem_options);
797 787
798 if (list_empty(&caller_sort)) 788 if (!strncmp(argv[0], "rec", 3)) {
799 setup_sorting(&caller_sort, default_sort_order); 789 return __cmd_record(argc, argv);
800 if (list_empty(&alloc_sort)) 790 } else if (!strcmp(argv[0], "stat")) {
801 setup_sorting(&alloc_sort, default_sort_order); 791 setup_cpunode_map();
802 792
803 setup_cpunode_map(); 793 if (list_empty(&caller_sort))
794 setup_sorting(&caller_sort, default_sort_order);
795 if (list_empty(&alloc_sort))
796 setup_sorting(&alloc_sort, default_sort_order);
804 797
805 return __cmd_kmem(); 798 return __cmd_kmem();
799 }
800
801 return 0;
806} 802}
807 803
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index a58e11b7ea80..5a47c1e11f77 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -35,6 +35,7 @@
35#include "perf.h" 35#include "perf.h"
36#include "builtin.h" 36#include "builtin.h"
37#include "util/util.h" 37#include "util/util.h"
38#include "util/strlist.h"
38#include "util/event.h" 39#include "util/event.h"
39#include "util/debug.h" 40#include "util/debug.h"
40#include "util/parse-options.h" 41#include "util/parse-options.h"
@@ -43,11 +44,12 @@
43#include "util/probe-event.h" 44#include "util/probe-event.h"
44 45
45/* Default vmlinux search paths */ 46/* Default vmlinux search paths */
46#define NR_SEARCH_PATH 3 47#define NR_SEARCH_PATH 4
47const char *default_search_path[NR_SEARCH_PATH] = { 48const char *default_search_path[NR_SEARCH_PATH] = {
48"/lib/modules/%s/build/vmlinux", /* Custom build kernel */ 49"/lib/modules/%s/build/vmlinux", /* Custom build kernel */
49"/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */ 50"/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */
50"/boot/vmlinux-debug-%s", /* Ubuntu */ 51"/boot/vmlinux-debug-%s", /* Ubuntu */
52"./vmlinux", /* CWD */
51}; 53};
52 54
53#define MAX_PATH_LEN 256 55#define MAX_PATH_LEN 256
@@ -60,6 +62,7 @@ static struct {
60 int need_dwarf; 62 int need_dwarf;
61 int nr_probe; 63 int nr_probe;
62 struct probe_point probes[MAX_PROBES]; 64 struct probe_point probes[MAX_PROBES];
65 struct strlist *dellist;
63} session; 66} session;
64 67
65static bool listing; 68static bool listing;
@@ -79,6 +82,25 @@ static void parse_probe_event(const char *str)
79 pr_debug("%d arguments\n", pp->nr_args); 82 pr_debug("%d arguments\n", pp->nr_args);
80} 83}
81 84
85static void parse_probe_event_argv(int argc, const char **argv)
86{
87 int i, len;
88 char *buf;
89
90 /* Bind up rest arguments */
91 len = 0;
92 for (i = 0; i < argc; i++)
93 len += strlen(argv[i]) + 1;
94 buf = zalloc(len + 1);
95 if (!buf)
96 die("Failed to allocate memory for binding arguments.");
97 len = 0;
98 for (i = 0; i < argc; i++)
99 len += sprintf(&buf[len], "%s ", argv[i]);
100 parse_probe_event(buf);
101 free(buf);
102}
103
82static int opt_add_probe_event(const struct option *opt __used, 104static int opt_add_probe_event(const struct option *opt __used,
83 const char *str, int unset __used) 105 const char *str, int unset __used)
84{ 106{
@@ -87,6 +109,17 @@ static int opt_add_probe_event(const struct option *opt __used,
87 return 0; 109 return 0;
88} 110}
89 111
112static int opt_del_probe_event(const struct option *opt __used,
113 const char *str, int unset __used)
114{
115 if (str) {
116 if (!session.dellist)
117 session.dellist = strlist__new(true, NULL);
118 strlist__add(session.dellist, str);
119 }
120 return 0;
121}
122
90#ifndef NO_LIBDWARF 123#ifndef NO_LIBDWARF
91static int open_default_vmlinux(void) 124static int open_default_vmlinux(void)
92{ 125{
@@ -121,6 +154,7 @@ static int open_default_vmlinux(void)
121static const char * const probe_usage[] = { 154static const char * const probe_usage[] = {
122 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 155 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
123 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 156 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
157 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
124 "perf probe --list", 158 "perf probe --list",
125 NULL 159 NULL
126}; 160};
@@ -132,7 +166,9 @@ static const struct option options[] = {
132 OPT_STRING('k', "vmlinux", &session.vmlinux, "file", 166 OPT_STRING('k', "vmlinux", &session.vmlinux, "file",
133 "vmlinux/module pathname"), 167 "vmlinux/module pathname"),
134#endif 168#endif
135 OPT_BOOLEAN('l', "list", &listing, "list up current probes"), 169 OPT_BOOLEAN('l', "list", &listing, "list up current probe events"),
170 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
171 opt_del_probe_event),
136 OPT_CALLBACK('a', "add", NULL, 172 OPT_CALLBACK('a', "add", NULL,
137#ifdef NO_LIBDWARF 173#ifdef NO_LIBDWARF
138 "FUNC[+OFFS|%return] [ARG ...]", 174 "FUNC[+OFFS|%return] [ARG ...]",
@@ -160,7 +196,7 @@ static const struct option options[] = {
160 196
161int cmd_probe(int argc, const char **argv, const char *prefix __used) 197int cmd_probe(int argc, const char **argv, const char *prefix __used)
162{ 198{
163 int i, j, ret; 199 int i, ret;
164#ifndef NO_LIBDWARF 200#ifndef NO_LIBDWARF
165 int fd; 201 int fd;
166#endif 202#endif
@@ -168,40 +204,52 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
168 204
169 argc = parse_options(argc, argv, options, probe_usage, 205 argc = parse_options(argc, argv, options, probe_usage,
170 PARSE_OPT_STOP_AT_NON_OPTION); 206 PARSE_OPT_STOP_AT_NON_OPTION);
171 for (i = 0; i < argc; i++) 207 if (argc > 0)
172 parse_probe_event(argv[i]); 208 parse_probe_event_argv(argc, argv);
173 209
174 if ((session.nr_probe == 0 && !listing) || 210 if ((session.nr_probe == 0 && !session.dellist && !listing))
175 (session.nr_probe != 0 && listing))
176 usage_with_options(probe_usage, options); 211 usage_with_options(probe_usage, options);
177 212
178 if (listing) { 213 if (listing) {
214 if (session.nr_probe != 0 || session.dellist) {
215 pr_warning(" Error: Don't use --list with"
216 " --add/--del.\n");
217 usage_with_options(probe_usage, options);
218 }
179 show_perf_probe_events(); 219 show_perf_probe_events();
180 return 0; 220 return 0;
181 } 221 }
182 222
223 if (session.dellist) {
224 del_trace_kprobe_events(session.dellist);
225 strlist__delete(session.dellist);
226 if (session.nr_probe == 0)
227 return 0;
228 }
229
183 if (session.need_dwarf) 230 if (session.need_dwarf)
184#ifdef NO_LIBDWARF 231#ifdef NO_LIBDWARF
185 die("Debuginfo-analysis is not supported"); 232 die("Debuginfo-analysis is not supported");
186#else /* !NO_LIBDWARF */ 233#else /* !NO_LIBDWARF */
187 pr_debug("Some probes require debuginfo.\n"); 234 pr_debug("Some probes require debuginfo.\n");
188 235
189 if (session.vmlinux) 236 if (session.vmlinux) {
237 pr_debug("Try to open %s.", session.vmlinux);
190 fd = open(session.vmlinux, O_RDONLY); 238 fd = open(session.vmlinux, O_RDONLY);
191 else 239 } else
192 fd = open_default_vmlinux(); 240 fd = open_default_vmlinux();
193 if (fd < 0) { 241 if (fd < 0) {
194 if (session.need_dwarf) 242 if (session.need_dwarf)
195 die("Could not open vmlinux/module file."); 243 die("Could not open debuginfo file.");
196 244
197 pr_warning("Could not open vmlinux/module file." 245 pr_debug("Could not open vmlinux/module file."
198 " Try to use symbols.\n"); 246 " Try to use symbols.\n");
199 goto end_dwarf; 247 goto end_dwarf;
200 } 248 }
201 249
202 /* Searching probe points */ 250 /* Searching probe points */
203 for (j = 0; j < session.nr_probe; j++) { 251 for (i = 0; i < session.nr_probe; i++) {
204 pp = &session.probes[j]; 252 pp = &session.probes[i];
205 if (pp->found) 253 if (pp->found)
206 continue; 254 continue;
207 255
@@ -223,8 +271,8 @@ end_dwarf:
223#endif /* !NO_LIBDWARF */ 271#endif /* !NO_LIBDWARF */
224 272
225 /* Synthesize probes without dwarf */ 273 /* Synthesize probes without dwarf */
226 for (j = 0; j < session.nr_probe; j++) { 274 for (i = 0; i < session.nr_probe; i++) {
227 pp = &session.probes[j]; 275 pp = &session.probes[i];
228 if (pp->found) /* This probe is already found. */ 276 if (pp->found) /* This probe is already found. */
229 continue; 277 continue;
230 278
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 0e519c667e3a..4decbd14eaed 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/session.h"
20#include "util/symbol.h" 21#include "util/symbol.h"
21 22
22#include <unistd.h> 23#include <unistd.h>
@@ -62,7 +63,7 @@ static int nr_cpu = 0;
62 63
63static int file_new = 1; 64static int file_new = 1;
64 65
65struct perf_header *header = NULL; 66static struct perf_session *session;
66 67
67struct mmap_data { 68struct mmap_data {
68 int counter; 69 int counter;
@@ -216,12 +217,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
216{ 217{
217 struct perf_header_attr *h_attr; 218 struct perf_header_attr *h_attr;
218 219
219 if (nr < header->attrs) { 220 if (nr < session->header.attrs) {
220 h_attr = header->attr[nr]; 221 h_attr = session->header.attr[nr];
221 } else { 222 } else {
222 h_attr = perf_header_attr__new(a); 223 h_attr = perf_header_attr__new(a);
223 if (h_attr != NULL) 224 if (h_attr != NULL)
224 if (perf_header__add_attr(header, h_attr) < 0) { 225 if (perf_header__add_attr(&session->header, h_attr) < 0) {
225 perf_header_attr__delete(h_attr); 226 perf_header_attr__delete(h_attr);
226 h_attr = NULL; 227 h_attr = NULL;
227 } 228 }
@@ -395,9 +396,9 @@ static void open_counters(int cpu, pid_t pid)
395 396
396static void atexit_header(void) 397static void atexit_header(void)
397{ 398{
398 header->data_size += bytes_written; 399 session->header.data_size += bytes_written;
399 400
400 perf_header__write(header, output, true); 401 perf_header__write(&session->header, output, true);
401} 402}
402 403
403static int __cmd_record(int argc, const char **argv) 404static int __cmd_record(int argc, const char **argv)
@@ -440,24 +441,24 @@ static int __cmd_record(int argc, const char **argv)
440 exit(-1); 441 exit(-1);
441 } 442 }
442 443
443 header = perf_header__new(); 444 session = perf_session__new(output_name, O_WRONLY, force);
444 if (header == NULL) { 445 if (session == NULL) {
445 pr_err("Not enough memory for reading perf file header\n"); 446 pr_err("Not enough memory for reading perf file header\n");
446 return -1; 447 return -1;
447 } 448 }
448 449
449 if (!file_new) { 450 if (!file_new) {
450 err = perf_header__read(header, output); 451 err = perf_header__read(&session->header, output);
451 if (err < 0) 452 if (err < 0)
452 return err; 453 return err;
453 } 454 }
454 455
455 if (raw_samples) { 456 if (raw_samples) {
456 perf_header__set_feat(header, HEADER_TRACE_INFO); 457 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
457 } else { 458 } else {
458 for (i = 0; i < nr_counters; i++) { 459 for (i = 0; i < nr_counters; i++) {
459 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 460 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
460 perf_header__set_feat(header, HEADER_TRACE_INFO); 461 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
461 break; 462 break;
462 } 463 }
463 } 464 }
@@ -481,7 +482,7 @@ static int __cmd_record(int argc, const char **argv)
481 } 482 }
482 483
483 if (file_new) { 484 if (file_new) {
484 err = perf_header__write(header, output, false); 485 err = perf_header__write(&session->header, output, false);
485 if (err < 0) 486 if (err < 0)
486 return err; 487 return err;
487 } 488 }
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 383c4ab4f9af..e2ec49a9b731 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -22,6 +22,7 @@
22#include "perf.h" 22#include "perf.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/header.h" 24#include "util/header.h"
25#include "util/session.h"
25 26
26#include "util/parse-options.h" 27#include "util/parse-options.h"
27#include "util/parse-events.h" 28#include "util/parse-events.h"
@@ -52,7 +53,7 @@ static int exclude_other = 1;
52 53
53static char callchain_default_opt[] = "fractal,0.5"; 54static char callchain_default_opt[] = "fractal,0.5";
54 55
55static struct perf_header *header; 56static struct perf_session *session;
56 57
57static u64 sample_type; 58static u64 sample_type;
58 59
@@ -605,44 +606,41 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
605 606
606static int process_sample_event(event_t *event) 607static int process_sample_event(event_t *event)
607{ 608{
608 u64 ip = event->ip.ip; 609 struct sample_data data;
609 u64 period = 1;
610 void *more_data = event->ip.__more_data;
611 struct ip_callchain *chain = NULL;
612 int cpumode; 610 int cpumode;
613 struct addr_location al; 611 struct addr_location al;
614 struct thread *thread = threads__findnew(event->ip.pid); 612 struct thread *thread;
615 613
616 if (sample_type & PERF_SAMPLE_PERIOD) { 614 memset(&data, 0, sizeof(data));
617 period = *(u64 *)more_data; 615 data.period = 1;
618 more_data += sizeof(u64); 616
619 } 617 event__parse_sample(event, sample_type, &data);
620 618
621 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 619 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
622 event->header.misc, 620 event->header.misc,
623 event->ip.pid, event->ip.tid, 621 data.pid, data.tid,
624 (void *)(long)ip, 622 (void *)(long)data.ip,
625 (long long)period); 623 (long long)data.period);
626 624
627 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 625 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
628 unsigned int i; 626 unsigned int i;
629 627
630 chain = (void *)more_data; 628 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
631 629
632 dump_printf("... chain: nr:%Lu\n", chain->nr); 630 if (validate_chain(data.callchain, event) < 0) {
633
634 if (validate_chain(chain, event) < 0) {
635 pr_debug("call-chain problem with event, " 631 pr_debug("call-chain problem with event, "
636 "skipping it.\n"); 632 "skipping it.\n");
637 return 0; 633 return 0;
638 } 634 }
639 635
640 if (dump_trace) { 636 if (dump_trace) {
641 for (i = 0; i < chain->nr; i++) 637 for (i = 0; i < data.callchain->nr; i++)
642 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); 638 dump_printf("..... %2d: %016Lx\n",
639 i, data.callchain->ips[i]);
643 } 640 }
644 } 641 }
645 642
643 thread = threads__findnew(data.pid);
646 if (thread == NULL) { 644 if (thread == NULL) {
647 pr_debug("problem processing %d event, skipping it.\n", 645 pr_debug("problem processing %d event, skipping it.\n",
648 event->header.type); 646 event->header.type);
@@ -657,7 +655,7 @@ static int process_sample_event(event_t *event)
657 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 655 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
658 656
659 thread__find_addr_location(thread, cpumode, 657 thread__find_addr_location(thread, cpumode,
660 MAP__FUNCTION, ip, &al, NULL); 658 MAP__FUNCTION, data.ip, &al, NULL);
661 /* 659 /*
662 * We have to do this here as we may have a dso with no symbol hit that 660 * We have to do this here as we may have a dso with no symbol hit that
663 * has a name longer than the ones with symbols sampled. 661 * has a name longer than the ones with symbols sampled.
@@ -675,12 +673,12 @@ static int process_sample_event(event_t *event)
675 if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name)) 673 if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
676 return 0; 674 return 0;
677 675
678 if (hist_entry__add(&al, chain, period)) { 676 if (hist_entry__add(&al, data.callchain, data.period)) {
679 pr_debug("problem incrementing symbol count, skipping event\n"); 677 pr_debug("problem incrementing symbol count, skipping event\n");
680 return -1; 678 return -1;
681 } 679 }
682 680
683 event__stats.total += period; 681 event__stats.total += data.period;
684 682
685 return 0; 683 return 0;
686} 684}
@@ -704,7 +702,7 @@ static int process_read_event(event_t *event)
704{ 702{
705 struct perf_event_attr *attr; 703 struct perf_event_attr *attr;
706 704
707 attr = perf_header__find_attr(event->read.id, header); 705 attr = perf_header__find_attr(event->read.id, &session->header);
708 706
709 if (show_threads) { 707 if (show_threads) {
710 const char *name = attr ? __event_name(attr->type, attr->config) 708 const char *name = attr ? __event_name(attr->type, attr->config)
@@ -769,6 +767,10 @@ static int __cmd_report(void)
769 struct thread *idle; 767 struct thread *idle;
770 int ret; 768 int ret;
771 769
770 session = perf_session__new(input_name, O_RDONLY, force);
771 if (session == NULL)
772 return -ENOMEM;
773
772 idle = register_idle_thread(); 774 idle = register_idle_thread();
773 thread__comm_adjust(idle); 775 thread__comm_adjust(idle);
774 776
@@ -777,14 +779,14 @@ static int __cmd_report(void)
777 779
778 register_perf_file_handler(&file_handler); 780 register_perf_file_handler(&file_handler);
779 781
780 ret = mmap_dispatch_perf_file(&header, input_name, force, 782 ret = perf_session__process_events(session, full_paths,
781 full_paths, &event__cwdlen, &event__cwd); 783 &event__cwdlen, &event__cwd);
782 if (ret) 784 if (ret)
783 return ret; 785 goto out_delete;
784 786
785 if (dump_trace) { 787 if (dump_trace) {
786 event__print_totals(); 788 event__print_totals();
787 return 0; 789 goto out_delete;
788 } 790 }
789 791
790 if (verbose > 3) 792 if (verbose > 3)
@@ -799,7 +801,8 @@ static int __cmd_report(void)
799 801
800 if (show_threads) 802 if (show_threads)
801 perf_read_values_destroy(&show_threads_values); 803 perf_read_values_destroy(&show_threads_values);
802 804out_delete:
805 perf_session__delete(session);
803 return ret; 806 return ret;
804} 807}
805 808
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 26b782f26ee1..65021fe1361e 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -6,6 +6,7 @@
6#include "util/symbol.h" 6#include "util/symbol.h"
7#include "util/thread.h" 7#include "util/thread.h"
8#include "util/header.h" 8#include "util/header.h"
9#include "util/session.h"
9 10
10#include "util/parse-options.h" 11#include "util/parse-options.h"
11#include "util/trace-event.h" 12#include "util/trace-event.h"
@@ -13,7 +14,6 @@
13#include "util/debug.h" 14#include "util/debug.h"
14#include "util/data_map.h" 15#include "util/data_map.h"
15 16
16#include <sys/types.h>
17#include <sys/prctl.h> 17#include <sys/prctl.h>
18 18
19#include <semaphore.h> 19#include <semaphore.h>
@@ -22,7 +22,6 @@
22 22
23static char const *input_name = "perf.data"; 23static char const *input_name = "perf.data";
24 24
25static struct perf_header *header;
26static u64 sample_type; 25static u64 sample_type;
27 26
28static char default_sort_order[] = "avg, max, switch, runtime"; 27static char default_sort_order[] = "avg, max, switch, runtime";
@@ -141,6 +140,7 @@ struct work_atoms {
141 struct thread *thread; 140 struct thread *thread;
142 struct rb_node node; 141 struct rb_node node;
143 u64 max_lat; 142 u64 max_lat;
143 u64 max_lat_at;
144 u64 total_lat; 144 u64 total_lat;
145 u64 nb_atoms; 145 u64 nb_atoms;
146 u64 total_runtime; 146 u64 total_runtime;
@@ -414,34 +414,33 @@ static u64 get_cpu_usage_nsec_parent(void)
414 return sum; 414 return sum;
415} 415}
416 416
417static u64 get_cpu_usage_nsec_self(void) 417static int self_open_counters(void)
418{ 418{
419 char filename [] = "/proc/1234567890/sched"; 419 struct perf_event_attr attr;
420 unsigned long msecs, nsecs; 420 int fd;
421 char *line = NULL;
422 u64 total = 0;
423 size_t len = 0;
424 ssize_t chars;
425 FILE *file;
426 int ret;
427 421
428 sprintf(filename, "/proc/%d/sched", getpid()); 422 memset(&attr, 0, sizeof(attr));
429 file = fopen(filename, "r");
430 BUG_ON(!file);
431 423
432 while ((chars = getline(&line, &len, file)) != -1) { 424 attr.type = PERF_TYPE_SOFTWARE;
433 ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n", 425 attr.config = PERF_COUNT_SW_TASK_CLOCK;
434 &msecs, &nsecs); 426
435 if (ret == 2) { 427 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
436 total = msecs*1e6 + nsecs;
437 break;
438 }
439 }
440 if (line)
441 free(line);
442 fclose(file);
443 428
444 return total; 429 if (fd < 0)
430 die("Error: sys_perf_event_open() syscall returned"
431 "with %d (%s)\n", fd, strerror(errno));
432 return fd;
433}
434
435static u64 get_cpu_usage_nsec_self(int fd)
436{
437 u64 runtime;
438 int ret;
439
440 ret = read(fd, &runtime, sizeof(runtime));
441 BUG_ON(ret != sizeof(runtime));
442
443 return runtime;
445} 444}
446 445
447static void *thread_func(void *ctx) 446static void *thread_func(void *ctx)
@@ -450,9 +449,11 @@ static void *thread_func(void *ctx)
450 u64 cpu_usage_0, cpu_usage_1; 449 u64 cpu_usage_0, cpu_usage_1;
451 unsigned long i, ret; 450 unsigned long i, ret;
452 char comm2[22]; 451 char comm2[22];
452 int fd;
453 453
454 sprintf(comm2, ":%s", this_task->comm); 454 sprintf(comm2, ":%s", this_task->comm);
455 prctl(PR_SET_NAME, comm2); 455 prctl(PR_SET_NAME, comm2);
456 fd = self_open_counters();
456 457
457again: 458again:
458 ret = sem_post(&this_task->ready_for_work); 459 ret = sem_post(&this_task->ready_for_work);
@@ -462,16 +463,15 @@ again:
462 ret = pthread_mutex_unlock(&start_work_mutex); 463 ret = pthread_mutex_unlock(&start_work_mutex);
463 BUG_ON(ret); 464 BUG_ON(ret);
464 465
465 cpu_usage_0 = get_cpu_usage_nsec_self(); 466 cpu_usage_0 = get_cpu_usage_nsec_self(fd);
466 467
467 for (i = 0; i < this_task->nr_events; i++) { 468 for (i = 0; i < this_task->nr_events; i++) {
468 this_task->curr_event = i; 469 this_task->curr_event = i;
469 process_sched_event(this_task, this_task->atoms[i]); 470 process_sched_event(this_task, this_task->atoms[i]);
470 } 471 }
471 472
472 cpu_usage_1 = get_cpu_usage_nsec_self(); 473 cpu_usage_1 = get_cpu_usage_nsec_self(fd);
473 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; 474 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
474
475 ret = sem_post(&this_task->work_done_sem); 475 ret = sem_post(&this_task->work_done_sem);
476 BUG_ON(ret); 476 BUG_ON(ret);
477 477
@@ -628,11 +628,6 @@ static void test_calibrations(void)
628 printf("the sleep test took %Ld nsecs\n", T1-T0); 628 printf("the sleep test took %Ld nsecs\n", T1-T0);
629} 629}
630 630
631struct raw_event_sample {
632 u32 size;
633 char data[0];
634};
635
636#define FILL_FIELD(ptr, field, event, data) \ 631#define FILL_FIELD(ptr, field, event, data) \
637 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) 632 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
638 633
@@ -1019,8 +1014,10 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1019 1014
1020 delta = atom->sched_in_time - atom->wake_up_time; 1015 delta = atom->sched_in_time - atom->wake_up_time;
1021 atoms->total_lat += delta; 1016 atoms->total_lat += delta;
1022 if (delta > atoms->max_lat) 1017 if (delta > atoms->max_lat) {
1023 atoms->max_lat = delta; 1018 atoms->max_lat = delta;
1019 atoms->max_lat_at = timestamp;
1020 }
1024 atoms->nb_atoms++; 1021 atoms->nb_atoms++;
1025} 1022}
1026 1023
@@ -1216,10 +1213,11 @@ static void output_lat_thread(struct work_atoms *work_list)
1216 1213
1217 avg = work_list->total_lat / work_list->nb_atoms; 1214 avg = work_list->total_lat / work_list->nb_atoms;
1218 1215
1219 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms |\n", 1216 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
1220 (double)work_list->total_runtime / 1e6, 1217 (double)work_list->total_runtime / 1e6,
1221 work_list->nb_atoms, (double)avg / 1e6, 1218 work_list->nb_atoms, (double)avg / 1e6,
1222 (double)work_list->max_lat / 1e6); 1219 (double)work_list->max_lat / 1e6,
1220 (double)work_list->max_lat_at / 1e9);
1223} 1221}
1224 1222
1225static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1223static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
@@ -1356,7 +1354,7 @@ static void sort_lat(void)
1356static struct trace_sched_handler *trace_handler; 1354static struct trace_sched_handler *trace_handler;
1357 1355
1358static void 1356static void
1359process_sched_wakeup_event(struct raw_event_sample *raw, 1357process_sched_wakeup_event(void *data,
1360 struct event *event, 1358 struct event *event,
1361 int cpu __used, 1359 int cpu __used,
1362 u64 timestamp __used, 1360 u64 timestamp __used,
@@ -1364,13 +1362,13 @@ process_sched_wakeup_event(struct raw_event_sample *raw,
1364{ 1362{
1365 struct trace_wakeup_event wakeup_event; 1363 struct trace_wakeup_event wakeup_event;
1366 1364
1367 FILL_COMMON_FIELDS(wakeup_event, event, raw->data); 1365 FILL_COMMON_FIELDS(wakeup_event, event, data);
1368 1366
1369 FILL_ARRAY(wakeup_event, comm, event, raw->data); 1367 FILL_ARRAY(wakeup_event, comm, event, data);
1370 FILL_FIELD(wakeup_event, pid, event, raw->data); 1368 FILL_FIELD(wakeup_event, pid, event, data);
1371 FILL_FIELD(wakeup_event, prio, event, raw->data); 1369 FILL_FIELD(wakeup_event, prio, event, data);
1372 FILL_FIELD(wakeup_event, success, event, raw->data); 1370 FILL_FIELD(wakeup_event, success, event, data);
1373 FILL_FIELD(wakeup_event, cpu, event, raw->data); 1371 FILL_FIELD(wakeup_event, cpu, event, data);
1374 1372
1375 if (trace_handler->wakeup_event) 1373 if (trace_handler->wakeup_event)
1376 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); 1374 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread);
@@ -1469,7 +1467,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1469 1467
1470 1468
1471static void 1469static void
1472process_sched_switch_event(struct raw_event_sample *raw, 1470process_sched_switch_event(void *data,
1473 struct event *event, 1471 struct event *event,
1474 int this_cpu, 1472 int this_cpu,
1475 u64 timestamp __used, 1473 u64 timestamp __used,
@@ -1477,15 +1475,15 @@ process_sched_switch_event(struct raw_event_sample *raw,
1477{ 1475{
1478 struct trace_switch_event switch_event; 1476 struct trace_switch_event switch_event;
1479 1477
1480 FILL_COMMON_FIELDS(switch_event, event, raw->data); 1478 FILL_COMMON_FIELDS(switch_event, event, data);
1481 1479
1482 FILL_ARRAY(switch_event, prev_comm, event, raw->data); 1480 FILL_ARRAY(switch_event, prev_comm, event, data);
1483 FILL_FIELD(switch_event, prev_pid, event, raw->data); 1481 FILL_FIELD(switch_event, prev_pid, event, data);
1484 FILL_FIELD(switch_event, prev_prio, event, raw->data); 1482 FILL_FIELD(switch_event, prev_prio, event, data);
1485 FILL_FIELD(switch_event, prev_state, event, raw->data); 1483 FILL_FIELD(switch_event, prev_state, event, data);
1486 FILL_ARRAY(switch_event, next_comm, event, raw->data); 1484 FILL_ARRAY(switch_event, next_comm, event, data);
1487 FILL_FIELD(switch_event, next_pid, event, raw->data); 1485 FILL_FIELD(switch_event, next_pid, event, data);
1488 FILL_FIELD(switch_event, next_prio, event, raw->data); 1486 FILL_FIELD(switch_event, next_prio, event, data);
1489 1487
1490 if (curr_pid[this_cpu] != (u32)-1) { 1488 if (curr_pid[this_cpu] != (u32)-1) {
1491 /* 1489 /*
@@ -1502,7 +1500,7 @@ process_sched_switch_event(struct raw_event_sample *raw,
1502} 1500}
1503 1501
1504static void 1502static void
1505process_sched_runtime_event(struct raw_event_sample *raw, 1503process_sched_runtime_event(void *data,
1506 struct event *event, 1504 struct event *event,
1507 int cpu __used, 1505 int cpu __used,
1508 u64 timestamp __used, 1506 u64 timestamp __used,
@@ -1510,17 +1508,17 @@ process_sched_runtime_event(struct raw_event_sample *raw,
1510{ 1508{
1511 struct trace_runtime_event runtime_event; 1509 struct trace_runtime_event runtime_event;
1512 1510
1513 FILL_ARRAY(runtime_event, comm, event, raw->data); 1511 FILL_ARRAY(runtime_event, comm, event, data);
1514 FILL_FIELD(runtime_event, pid, event, raw->data); 1512 FILL_FIELD(runtime_event, pid, event, data);
1515 FILL_FIELD(runtime_event, runtime, event, raw->data); 1513 FILL_FIELD(runtime_event, runtime, event, data);
1516 FILL_FIELD(runtime_event, vruntime, event, raw->data); 1514 FILL_FIELD(runtime_event, vruntime, event, data);
1517 1515
1518 if (trace_handler->runtime_event) 1516 if (trace_handler->runtime_event)
1519 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); 1517 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread);
1520} 1518}
1521 1519
1522static void 1520static void
1523process_sched_fork_event(struct raw_event_sample *raw, 1521process_sched_fork_event(void *data,
1524 struct event *event, 1522 struct event *event,
1525 int cpu __used, 1523 int cpu __used,
1526 u64 timestamp __used, 1524 u64 timestamp __used,
@@ -1528,12 +1526,12 @@ process_sched_fork_event(struct raw_event_sample *raw,
1528{ 1526{
1529 struct trace_fork_event fork_event; 1527 struct trace_fork_event fork_event;
1530 1528
1531 FILL_COMMON_FIELDS(fork_event, event, raw->data); 1529 FILL_COMMON_FIELDS(fork_event, event, data);
1532 1530
1533 FILL_ARRAY(fork_event, parent_comm, event, raw->data); 1531 FILL_ARRAY(fork_event, parent_comm, event, data);
1534 FILL_FIELD(fork_event, parent_pid, event, raw->data); 1532 FILL_FIELD(fork_event, parent_pid, event, data);
1535 FILL_ARRAY(fork_event, child_comm, event, raw->data); 1533 FILL_ARRAY(fork_event, child_comm, event, data);
1536 FILL_FIELD(fork_event, child_pid, event, raw->data); 1534 FILL_FIELD(fork_event, child_pid, event, data);
1537 1535
1538 if (trace_handler->fork_event) 1536 if (trace_handler->fork_event)
1539 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); 1537 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread);
@@ -1550,7 +1548,7 @@ process_sched_exit_event(struct event *event,
1550} 1548}
1551 1549
1552static void 1550static void
1553process_sched_migrate_task_event(struct raw_event_sample *raw, 1551process_sched_migrate_task_event(void *data,
1554 struct event *event, 1552 struct event *event,
1555 int cpu __used, 1553 int cpu __used,
1556 u64 timestamp __used, 1554 u64 timestamp __used,
@@ -1558,80 +1556,66 @@ process_sched_migrate_task_event(struct raw_event_sample *raw,
1558{ 1556{
1559 struct trace_migrate_task_event migrate_task_event; 1557 struct trace_migrate_task_event migrate_task_event;
1560 1558
1561 FILL_COMMON_FIELDS(migrate_task_event, event, raw->data); 1559 FILL_COMMON_FIELDS(migrate_task_event, event, data);
1562 1560
1563 FILL_ARRAY(migrate_task_event, comm, event, raw->data); 1561 FILL_ARRAY(migrate_task_event, comm, event, data);
1564 FILL_FIELD(migrate_task_event, pid, event, raw->data); 1562 FILL_FIELD(migrate_task_event, pid, event, data);
1565 FILL_FIELD(migrate_task_event, prio, event, raw->data); 1563 FILL_FIELD(migrate_task_event, prio, event, data);
1566 FILL_FIELD(migrate_task_event, cpu, event, raw->data); 1564 FILL_FIELD(migrate_task_event, cpu, event, data);
1567 1565
1568 if (trace_handler->migrate_task_event) 1566 if (trace_handler->migrate_task_event)
1569 trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread); 1567 trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread);
1570} 1568}
1571 1569
1572static void 1570static void
1573process_raw_event(event_t *raw_event __used, void *more_data, 1571process_raw_event(event_t *raw_event __used, void *data,
1574 int cpu, u64 timestamp, struct thread *thread) 1572 int cpu, u64 timestamp, struct thread *thread)
1575{ 1573{
1576 struct raw_event_sample *raw = more_data;
1577 struct event *event; 1574 struct event *event;
1578 int type; 1575 int type;
1579 1576
1580 type = trace_parse_common_type(raw->data); 1577
1578 type = trace_parse_common_type(data);
1581 event = trace_find_event(type); 1579 event = trace_find_event(type);
1582 1580
1583 if (!strcmp(event->name, "sched_switch")) 1581 if (!strcmp(event->name, "sched_switch"))
1584 process_sched_switch_event(raw, event, cpu, timestamp, thread); 1582 process_sched_switch_event(data, event, cpu, timestamp, thread);
1585 if (!strcmp(event->name, "sched_stat_runtime")) 1583 if (!strcmp(event->name, "sched_stat_runtime"))
1586 process_sched_runtime_event(raw, event, cpu, timestamp, thread); 1584 process_sched_runtime_event(data, event, cpu, timestamp, thread);
1587 if (!strcmp(event->name, "sched_wakeup")) 1585 if (!strcmp(event->name, "sched_wakeup"))
1588 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1586 process_sched_wakeup_event(data, event, cpu, timestamp, thread);
1589 if (!strcmp(event->name, "sched_wakeup_new")) 1587 if (!strcmp(event->name, "sched_wakeup_new"))
1590 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1588 process_sched_wakeup_event(data, event, cpu, timestamp, thread);
1591 if (!strcmp(event->name, "sched_process_fork")) 1589 if (!strcmp(event->name, "sched_process_fork"))
1592 process_sched_fork_event(raw, event, cpu, timestamp, thread); 1590 process_sched_fork_event(data, event, cpu, timestamp, thread);
1593 if (!strcmp(event->name, "sched_process_exit")) 1591 if (!strcmp(event->name, "sched_process_exit"))
1594 process_sched_exit_event(event, cpu, timestamp, thread); 1592 process_sched_exit_event(event, cpu, timestamp, thread);
1595 if (!strcmp(event->name, "sched_migrate_task")) 1593 if (!strcmp(event->name, "sched_migrate_task"))
1596 process_sched_migrate_task_event(raw, event, cpu, timestamp, thread); 1594 process_sched_migrate_task_event(data, event, cpu, timestamp, thread);
1597} 1595}
1598 1596
1599static int process_sample_event(event_t *event) 1597static int process_sample_event(event_t *event)
1600{ 1598{
1599 struct sample_data data;
1601 struct thread *thread; 1600 struct thread *thread;
1602 u64 ip = event->ip.ip;
1603 u64 timestamp = -1;
1604 u32 cpu = -1;
1605 u64 period = 1;
1606 void *more_data = event->ip.__more_data;
1607 1601
1608 if (!(sample_type & PERF_SAMPLE_RAW)) 1602 if (!(sample_type & PERF_SAMPLE_RAW))
1609 return 0; 1603 return 0;
1610 1604
1611 thread = threads__findnew(event->ip.pid); 1605 memset(&data, 0, sizeof(data));
1606 data.time = -1;
1607 data.cpu = -1;
1608 data.period = -1;
1612 1609
1613 if (sample_type & PERF_SAMPLE_TIME) { 1610 event__parse_sample(event, sample_type, &data);
1614 timestamp = *(u64 *)more_data;
1615 more_data += sizeof(u64);
1616 }
1617
1618 if (sample_type & PERF_SAMPLE_CPU) {
1619 cpu = *(u32 *)more_data;
1620 more_data += sizeof(u32);
1621 more_data += sizeof(u32); /* reserved */
1622 }
1623
1624 if (sample_type & PERF_SAMPLE_PERIOD) {
1625 period = *(u64 *)more_data;
1626 more_data += sizeof(u64);
1627 }
1628 1611
1629 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 1612 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1630 event->header.misc, 1613 event->header.misc,
1631 event->ip.pid, event->ip.tid, 1614 data.pid, data.tid,
1632 (void *)(long)ip, 1615 (void *)(long)data.ip,
1633 (long long)period); 1616 (long long)data.period);
1634 1617
1618 thread = threads__findnew(data.pid);
1635 if (thread == NULL) { 1619 if (thread == NULL) {
1636 pr_debug("problem processing %d event, skipping it.\n", 1620 pr_debug("problem processing %d event, skipping it.\n",
1637 event->header.type); 1621 event->header.type);
@@ -1640,10 +1624,10 @@ static int process_sample_event(event_t *event)
1640 1624
1641 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1625 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1642 1626
1643 if (profile_cpu != -1 && profile_cpu != (int) cpu) 1627 if (profile_cpu != -1 && profile_cpu != (int)data.cpu)
1644 return 0; 1628 return 0;
1645 1629
1646 process_raw_event(event, more_data, cpu, timestamp, thread); 1630 process_raw_event(event, data.raw_data, data.cpu, data.time, thread);
1647 1631
1648 return 0; 1632 return 0;
1649} 1633}
@@ -1679,11 +1663,18 @@ static struct perf_file_handler file_handler = {
1679 1663
1680static int read_events(void) 1664static int read_events(void)
1681{ 1665{
1666 int err;
1667 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1668
1669 if (session == NULL)
1670 return -ENOMEM;
1671
1682 register_idle_thread(); 1672 register_idle_thread();
1683 register_perf_file_handler(&file_handler); 1673 register_perf_file_handler(&file_handler);
1684 1674
1685 return mmap_dispatch_perf_file(&header, input_name, 0, 0, 1675 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
1686 &event__cwdlen, &event__cwd); 1676 perf_session__delete(session);
1677 return err;
1687} 1678}
1688 1679
1689static void print_bad_events(void) 1680static void print_bad_events(void)
@@ -1724,9 +1715,9 @@ static void __cmd_lat(void)
1724 read_events(); 1715 read_events();
1725 sort_lat(); 1716 sort_lat();
1726 1717
1727 printf("\n -----------------------------------------------------------------------------------------\n"); 1718 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
1728 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); 1719 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
1729 printf(" -----------------------------------------------------------------------------------------\n"); 1720 printf(" ---------------------------------------------------------------------------------------------------------------\n");
1730 1721
1731 next = rb_first(&sorted_atom_root); 1722 next = rb_first(&sorted_atom_root);
1732 1723
@@ -1902,13 +1893,18 @@ static int __cmd_record(int argc, const char **argv)
1902 1893
1903int cmd_sched(int argc, const char **argv, const char *prefix __used) 1894int cmd_sched(int argc, const char **argv, const char *prefix __used)
1904{ 1895{
1905 symbol__init(0);
1906
1907 argc = parse_options(argc, argv, sched_options, sched_usage, 1896 argc = parse_options(argc, argv, sched_options, sched_usage,
1908 PARSE_OPT_STOP_AT_NON_OPTION); 1897 PARSE_OPT_STOP_AT_NON_OPTION);
1909 if (!argc) 1898 if (!argc)
1910 usage_with_options(sched_usage, sched_options); 1899 usage_with_options(sched_usage, sched_options);
1911 1900
1901 /*
1902 * Aliased to 'perf trace' for now:
1903 */
1904 if (!strcmp(argv[0], "trace"))
1905 return cmd_trace(argc, argv, prefix);
1906
1907 symbol__init(0);
1912 if (!strncmp(argv[0], "rec", 3)) { 1908 if (!strncmp(argv[0], "rec", 3)) {
1913 return __cmd_record(argc, argv); 1909 return __cmd_record(argc, argv);
1914 } else if (!strncmp(argv[0], "lat", 3)) { 1910 } else if (!strncmp(argv[0], "lat", 3)) {
@@ -1932,11 +1928,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1932 usage_with_options(replay_usage, replay_options); 1928 usage_with_options(replay_usage, replay_options);
1933 } 1929 }
1934 __cmd_replay(); 1930 __cmd_replay();
1935 } else if (!strcmp(argv[0], "trace")) {
1936 /*
1937 * Aliased to 'perf trace' for now:
1938 */
1939 return cmd_trace(argc, argv, prefix);
1940 } else { 1931 } else {
1941 usage_with_options(sched_usage, sched_options); 1932 usage_with_options(sched_usage, sched_options);
1942 } 1933 }
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index cb58b6605fcc..759dd2b35fdb 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -302,12 +302,11 @@ process_exit_event(event_t *event)
302} 302}
303 303
304struct trace_entry { 304struct trace_entry {
305 u32 size;
306 unsigned short type; 305 unsigned short type;
307 unsigned char flags; 306 unsigned char flags;
308 unsigned char preempt_count; 307 unsigned char preempt_count;
309 int pid; 308 int pid;
310 int tgid; 309 int lock_depth;
311}; 310};
312 311
313struct power_entry { 312struct power_entry {
@@ -484,43 +483,22 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
484static int 483static int
485process_sample_event(event_t *event) 484process_sample_event(event_t *event)
486{ 485{
487 int cursor = 0; 486 struct sample_data data;
488 u64 addr = 0;
489 u64 stamp = 0;
490 u32 cpu = 0;
491 u32 pid = 0;
492 struct trace_entry *te; 487 struct trace_entry *te;
493 488
494 if (sample_type & PERF_SAMPLE_IP) 489 memset(&data, 0, sizeof(data));
495 cursor++;
496 490
497 if (sample_type & PERF_SAMPLE_TID) { 491 event__parse_sample(event, sample_type, &data);
498 pid = event->sample.array[cursor]>>32;
499 cursor++;
500 }
501 if (sample_type & PERF_SAMPLE_TIME) {
502 stamp = event->sample.array[cursor++];
503
504 if (!first_time || first_time > stamp)
505 first_time = stamp;
506 if (last_time < stamp)
507 last_time = stamp;
508 492
493 if (sample_type & PERF_SAMPLE_TIME) {
494 if (!first_time || first_time > data.time)
495 first_time = data.time;
496 if (last_time < data.time)
497 last_time = data.time;
509 } 498 }
510 if (sample_type & PERF_SAMPLE_ADDR)
511 addr = event->sample.array[cursor++];
512 if (sample_type & PERF_SAMPLE_ID)
513 cursor++;
514 if (sample_type & PERF_SAMPLE_STREAM_ID)
515 cursor++;
516 if (sample_type & PERF_SAMPLE_CPU)
517 cpu = event->sample.array[cursor++] & 0xFFFFFFFF;
518 if (sample_type & PERF_SAMPLE_PERIOD)
519 cursor++;
520 499
521 te = (void *)&event->sample.array[cursor]; 500 te = (void *)data.raw_data;
522 501 if (sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) {
523 if (sample_type & PERF_SAMPLE_RAW && te->size > 0) {
524 char *event_str; 502 char *event_str;
525 struct power_entry *pe; 503 struct power_entry *pe;
526 504
@@ -532,19 +510,19 @@ process_sample_event(event_t *event)
532 return 0; 510 return 0;
533 511
534 if (strcmp(event_str, "power:power_start") == 0) 512 if (strcmp(event_str, "power:power_start") == 0)
535 c_state_start(cpu, stamp, pe->value); 513 c_state_start(data.cpu, data.time, pe->value);
536 514
537 if (strcmp(event_str, "power:power_end") == 0) 515 if (strcmp(event_str, "power:power_end") == 0)
538 c_state_end(cpu, stamp); 516 c_state_end(data.cpu, data.time);
539 517
540 if (strcmp(event_str, "power:power_frequency") == 0) 518 if (strcmp(event_str, "power:power_frequency") == 0)
541 p_state_change(cpu, stamp, pe->value); 519 p_state_change(data.cpu, data.time, pe->value);
542 520
543 if (strcmp(event_str, "sched:sched_wakeup") == 0) 521 if (strcmp(event_str, "sched:sched_wakeup") == 0)
544 sched_wakeup(cpu, stamp, pid, te); 522 sched_wakeup(data.cpu, data.time, data.pid, te);
545 523
546 if (strcmp(event_str, "sched:sched_switch") == 0) 524 if (strcmp(event_str, "sched:sched_switch") == 0)
547 sched_switch(cpu, stamp, te); 525 sched_switch(data.cpu, data.time, te);
548 } 526 }
549 return 0; 527 return 0;
550} 528}
@@ -1081,15 +1059,17 @@ static struct perf_file_handler file_handler = {
1081 1059
1082static int __cmd_timechart(void) 1060static int __cmd_timechart(void)
1083{ 1061{
1084 struct perf_header *header; 1062 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1085 int ret; 1063 int ret;
1086 1064
1065 if (session == NULL)
1066 return -ENOMEM;
1067
1087 register_perf_file_handler(&file_handler); 1068 register_perf_file_handler(&file_handler);
1088 1069
1089 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0, 1070 ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
1090 &event__cwdlen, &event__cwd);
1091 if (ret) 1071 if (ret)
1092 return EXIT_FAILURE; 1072 goto out_delete;
1093 1073
1094 process_samples(); 1074 process_samples();
1095 1075
@@ -1101,8 +1081,9 @@ static int __cmd_timechart(void)
1101 1081
1102 pr_info("Written %2.1f seconds of trace to %s.\n", 1082 pr_info("Written %2.1f seconds of trace to %s.\n",
1103 (last_time - first_time) / 1000000000.0, output_name); 1083 (last_time - first_time) / 1000000000.0, output_name);
1104 1084out_delete:
1105 return EXIT_SUCCESS; 1085 perf_session__delete(session);
1086 return ret;
1106} 1087}
1107 1088
1108static const char * const timechart_usage[] = { 1089static const char * const timechart_usage[] = {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index abb914aa7be6..0756664666f1 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -7,6 +7,7 @@
7#include "util/header.h" 7#include "util/header.h"
8#include "util/exec_cmd.h" 8#include "util/exec_cmd.h"
9#include "util/trace-event.h" 9#include "util/trace-event.h"
10#include "util/session.h"
10 11
11static char const *script_name; 12static char const *script_name;
12static char const *generate_script_lang; 13static char const *generate_script_lang;
@@ -61,63 +62,45 @@ static int cleanup_scripting(void)
61 62
62static char const *input_name = "perf.data"; 63static char const *input_name = "perf.data";
63 64
64static struct perf_header *header; 65static struct perf_session *session;
65static u64 sample_type; 66static u64 sample_type;
66 67
67static int process_sample_event(event_t *event) 68static int process_sample_event(event_t *event)
68{ 69{
69 u64 ip = event->ip.ip; 70 struct sample_data data;
70 u64 timestamp = -1; 71 struct thread *thread;
71 u32 cpu = -1;
72 u64 period = 1;
73 void *more_data = event->ip.__more_data;
74 struct thread *thread = threads__findnew(event->ip.pid);
75
76 if (sample_type & PERF_SAMPLE_TIME) {
77 timestamp = *(u64 *)more_data;
78 more_data += sizeof(u64);
79 }
80 72
81 if (sample_type & PERF_SAMPLE_CPU) { 73 memset(&data, 0, sizeof(data));
82 cpu = *(u32 *)more_data; 74 data.time = -1;
83 more_data += sizeof(u32); 75 data.cpu = -1;
84 more_data += sizeof(u32); /* reserved */ 76 data.period = 1;
85 }
86 77
87 if (sample_type & PERF_SAMPLE_PERIOD) { 78 event__parse_sample(event, sample_type, &data);
88 period = *(u64 *)more_data;
89 more_data += sizeof(u64);
90 }
91 79
92 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 80 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
93 event->header.misc, 81 event->header.misc,
94 event->ip.pid, event->ip.tid, 82 data.pid, data.tid,
95 (void *)(long)ip, 83 (void *)(long)data.ip,
96 (long long)period); 84 (long long)data.period);
97 85
86 thread = threads__findnew(event->ip.pid);
98 if (thread == NULL) { 87 if (thread == NULL) {
99 pr_debug("problem processing %d event, skipping it.\n", 88 pr_debug("problem processing %d event, skipping it.\n",
100 event->header.type); 89 event->header.type);
101 return -1; 90 return -1;
102 } 91 }
103 92
104 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
105
106 if (sample_type & PERF_SAMPLE_RAW) { 93 if (sample_type & PERF_SAMPLE_RAW) {
107 struct {
108 u32 size;
109 char data[0];
110 } *raw = more_data;
111
112 /* 94 /*
113 * FIXME: better resolve from pid from the struct trace_entry 95 * FIXME: better resolve from pid from the struct trace_entry
114 * field, although it should be the same than this perf 96 * field, although it should be the same than this perf
115 * event pid 97 * event pid
116 */ 98 */
117 scripting_ops->process_event(cpu, raw->data, raw->size, 99 scripting_ops->process_event(data.cpu, data.raw_data,
118 timestamp, thread->comm); 100 data.raw_size,
101 data.time, thread->comm);
119 } 102 }
120 event__stats.total += period; 103 event__stats.total += data.period;
121 104
122 return 0; 105 return 0;
123} 106}
@@ -144,11 +127,18 @@ static struct perf_file_handler file_handler = {
144 127
145static int __cmd_trace(void) 128static int __cmd_trace(void)
146{ 129{
130 int err;
131
132 session = perf_session__new(input_name, O_RDONLY, 0);
133 if (session == NULL)
134 return -ENOMEM;
135
147 register_idle_thread(); 136 register_idle_thread();
148 register_perf_file_handler(&file_handler); 137 register_perf_file_handler(&file_handler);
149 138
150 return mmap_dispatch_perf_file(&header, input_name, 139 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
151 0, 0, &event__cwdlen, &event__cwd); 140 perf_session__delete(session);
141 return err;
152} 142}
153 143
154struct script_spec { 144struct script_spec {
@@ -366,11 +356,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
366 return -1; 356 return -1;
367 } 357 }
368 358
369 header = perf_header__new(); 359 perf_header__read(&session->header, input);
370 if (header == NULL)
371 return -1;
372
373 perf_header__read(header, input);
374 err = scripting_ops->generate_script("perf-trace"); 360 err = scripting_ops->generate_script("perf-trace");
375 goto out; 361 goto out;
376 } 362 }
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 454d5d55f32d..75f941bfba9e 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -59,6 +59,18 @@
59#define cpu_relax() asm volatile ("hint @pause" ::: "memory") 59#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
60#endif 60#endif
61 61
62#ifdef __arm__
63#include "../../arch/arm/include/asm/unistd.h"
64/*
65 * Use the __kuser_memory_barrier helper in the CPU helper page. See
66 * arch/arm/kernel/entry-armv.S in the kernel source for details.
67 */
68#define rmb() asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \
69 "sub pc, r0, #95" ::: "r0", "lr", "cc", \
70 "memory")
71#define cpu_relax() asm volatile("":::"memory")
72#endif
73
62#include <time.h> 74#include <time.h>
63#include <unistd.h> 75#include <unistd.h>
64#include <sys/types.h> 76#include <sys/types.h>
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index ca0bedf637c2..6d46dda53a29 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -100,11 +100,11 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
100 } 100 }
101} 101}
102 102
103int perf_header__read_build_ids(int input, off_t offset, off_t size) 103int perf_header__read_build_ids(int input, u64 offset, u64 size)
104{ 104{
105 struct build_id_event bev; 105 struct build_id_event bev;
106 char filename[PATH_MAX]; 106 char filename[PATH_MAX];
107 off_t limit = offset + size; 107 u64 limit = offset + size;
108 int err = -1; 108 int err = -1;
109 109
110 while (offset < limit) { 110 while (offset < limit) {
@@ -129,23 +129,16 @@ out:
129 return err; 129 return err;
130} 130}
131 131
132int mmap_dispatch_perf_file(struct perf_header **pheader, 132int perf_session__process_events(struct perf_session *self,
133 const char *input_name, 133 int full_paths, int *cwdlen, char **cwd)
134 int force,
135 int full_paths,
136 int *cwdlen,
137 char **cwd)
138{ 134{
139 int err; 135 int err;
140 struct perf_header *header;
141 unsigned long head, shift; 136 unsigned long head, shift;
142 unsigned long offset = 0; 137 unsigned long offset = 0;
143 struct stat input_stat;
144 size_t page_size; 138 size_t page_size;
145 u64 sample_type; 139 u64 sample_type;
146 event_t *event; 140 event_t *event;
147 uint32_t size; 141 uint32_t size;
148 int input;
149 char *buf; 142 char *buf;
150 143
151 if (curr_handler == NULL) { 144 if (curr_handler == NULL) {
@@ -155,56 +148,19 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
155 148
156 page_size = getpagesize(); 149 page_size = getpagesize();
157 150
158 input = open(input_name, O_RDONLY); 151 head = self->header.data_offset;
159 if (input < 0) { 152 sample_type = perf_header__sample_type(&self->header);
160 pr_err("Failed to open file: %s", input_name);
161 if (!strcmp(input_name, "perf.data"))
162 pr_err(" (try 'perf record' first)");
163 pr_err("\n");
164 return -errno;
165 }
166
167 if (fstat(input, &input_stat) < 0) {
168 pr_err("failed to stat file");
169 err = -errno;
170 goto out_close;
171 }
172
173 err = -EACCES;
174 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
175 pr_err("file: %s not owned by current user or root\n",
176 input_name);
177 goto out_close;
178 }
179
180 if (input_stat.st_size == 0) {
181 pr_info("zero-sized file, nothing to do!\n");
182 goto done;
183 }
184
185 err = -ENOMEM;
186 header = perf_header__new();
187 if (header == NULL)
188 goto out_close;
189
190 err = perf_header__read(header, input);
191 if (err < 0)
192 goto out_delete;
193 *pheader = header;
194 head = header->data_offset;
195
196 sample_type = perf_header__sample_type(header);
197 153
198 err = -EINVAL; 154 err = -EINVAL;
199 if (curr_handler->sample_type_check && 155 if (curr_handler->sample_type_check &&
200 curr_handler->sample_type_check(sample_type) < 0) 156 curr_handler->sample_type_check(sample_type) < 0)
201 goto out_delete; 157 goto out_err;
202 158
203 if (!full_paths) { 159 if (!full_paths) {
204 if (getcwd(__cwd, sizeof(__cwd)) == NULL) { 160 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
205 pr_err("failed to get the current directory\n"); 161 pr_err("failed to get the current directory\n");
206 err = -errno; 162 err = -errno;
207 goto out_delete; 163 goto out_err;
208 } 164 }
209 *cwd = __cwd; 165 *cwd = __cwd;
210 *cwdlen = strlen(*cwd); 166 *cwdlen = strlen(*cwd);
@@ -219,11 +175,11 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
219 175
220remap: 176remap:
221 buf = mmap(NULL, page_size * mmap_window, PROT_READ, 177 buf = mmap(NULL, page_size * mmap_window, PROT_READ,
222 MAP_SHARED, input, offset); 178 MAP_SHARED, self->fd, offset);
223 if (buf == MAP_FAILED) { 179 if (buf == MAP_FAILED) {
224 pr_err("failed to mmap file\n"); 180 pr_err("failed to mmap file\n");
225 err = -errno; 181 err = -errno;
226 goto out_delete; 182 goto out_err;
227 } 183 }
228 184
229more: 185more:
@@ -273,19 +229,14 @@ more:
273 229
274 head += size; 230 head += size;
275 231
276 if (offset + head >= header->data_offset + header->data_size) 232 if (offset + head >= self->header.data_offset + self->header.data_size)
277 goto done; 233 goto done;
278 234
279 if (offset + head < (unsigned long)input_stat.st_size) 235 if (offset + head < self->size)
280 goto more; 236 goto more;
281 237
282done: 238done:
283 err = 0; 239 err = 0;
284out_close: 240out_err:
285 close(input);
286
287 return err; 241 return err;
288out_delete:
289 perf_header__delete(header);
290 goto out_close;
291} 242}
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
index 3180ff7e3633..98c5b823388c 100644
--- a/tools/perf/util/data_map.h
+++ b/tools/perf/util/data_map.h
@@ -3,6 +3,7 @@
3 3
4#include "event.h" 4#include "event.h"
5#include "header.h" 5#include "header.h"
6#include "session.h"
6 7
7typedef int (*event_type_handler_t)(event_t *); 8typedef int (*event_type_handler_t)(event_t *);
8 9
@@ -21,12 +22,8 @@ struct perf_file_handler {
21}; 22};
22 23
23void register_perf_file_handler(struct perf_file_handler *handler); 24void register_perf_file_handler(struct perf_file_handler *handler);
24int mmap_dispatch_perf_file(struct perf_header **pheader, 25int perf_session__process_events(struct perf_session *self,
25 const char *input_name, 26 int full_paths, int *cwdlen, char **cwd);
26 int force, 27int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
27 int full_paths,
28 int *cwdlen,
29 char **cwd);
30int perf_header__read_build_ids(int input, off_t offset, off_t file_size);
31 28
32#endif 29#endif
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 414b89d1bde9..ba0de90cd3d4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -254,13 +254,14 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
254 struct addr_location *al, 254 struct addr_location *al,
255 symbol_filter_t filter) 255 symbol_filter_t filter)
256{ 256{
257 struct thread *thread = al->thread = self; 257 struct map_groups *mg = &self->mg;
258 258
259 al->thread = self;
259 al->addr = addr; 260 al->addr = addr;
260 261
261 if (cpumode & PERF_RECORD_MISC_KERNEL) { 262 if (cpumode & PERF_RECORD_MISC_KERNEL) {
262 al->level = 'k'; 263 al->level = 'k';
263 thread = kthread; 264 mg = kmaps;
264 } else if (cpumode & PERF_RECORD_MISC_USER) 265 } else if (cpumode & PERF_RECORD_MISC_USER)
265 al->level = '.'; 266 al->level = '.';
266 else { 267 else {
@@ -270,7 +271,7 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
270 return; 271 return;
271 } 272 }
272try_again: 273try_again:
273 al->map = thread__find_map(thread, type, al->addr); 274 al->map = map_groups__find(mg, type, al->addr);
274 if (al->map == NULL) { 275 if (al->map == NULL) {
275 /* 276 /*
276 * If this is outside of all known maps, and is a negative 277 * If this is outside of all known maps, and is a negative
@@ -281,8 +282,8 @@ try_again:
281 * "[vdso]" dso, but for now lets use the old trick of looking 282 * "[vdso]" dso, but for now lets use the old trick of looking
282 * in the whole kernel symbol list. 283 * in the whole kernel symbol list.
283 */ 284 */
284 if ((long long)al->addr < 0 && thread != kthread) { 285 if ((long long)al->addr < 0 && mg != kmaps) {
285 thread = kthread; 286 mg = kmaps;
286 goto try_again; 287 goto try_again;
287 } 288 }
288 al->sym = NULL; 289 al->sym = NULL;
@@ -310,3 +311,70 @@ int event__preprocess_sample(const event_t *self, struct addr_location *al,
310 al->level == 'H' ? "[hypervisor]" : "<not found>"); 311 al->level == 'H' ? "[hypervisor]" : "<not found>");
311 return 0; 312 return 0;
312} 313}
314
315int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
316{
317 u64 *array = event->sample.array;
318
319 if (type & PERF_SAMPLE_IP) {
320 data->ip = event->ip.ip;
321 array++;
322 }
323
324 if (type & PERF_SAMPLE_TID) {
325 u32 *p = (u32 *)array;
326 data->pid = p[0];
327 data->tid = p[1];
328 array++;
329 }
330
331 if (type & PERF_SAMPLE_TIME) {
332 data->time = *array;
333 array++;
334 }
335
336 if (type & PERF_SAMPLE_ADDR) {
337 data->addr = *array;
338 array++;
339 }
340
341 if (type & PERF_SAMPLE_ID) {
342 data->id = *array;
343 array++;
344 }
345
346 if (type & PERF_SAMPLE_STREAM_ID) {
347 data->stream_id = *array;
348 array++;
349 }
350
351 if (type & PERF_SAMPLE_CPU) {
352 u32 *p = (u32 *)array;
353 data->cpu = *p;
354 array++;
355 }
356
357 if (type & PERF_SAMPLE_PERIOD) {
358 data->period = *array;
359 array++;
360 }
361
362 if (type & PERF_SAMPLE_READ) {
363 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
364 return -1;
365 }
366
367 if (type & PERF_SAMPLE_CALLCHAIN) {
368 data->callchain = (struct ip_callchain *)array;
369 array += 1 + data->callchain->nr;
370 }
371
372 if (type & PERF_SAMPLE_RAW) {
373 u32 *p = (u32 *)array;
374 data->raw_size = *p;
375 p++;
376 data->raw_data = p;
377 }
378
379 return 0;
380}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index a4cc8105cf67..51a96c2effde 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -56,11 +56,25 @@ struct read_event {
56 u64 id; 56 u64 id;
57}; 57};
58 58
59struct sample_event{ 59struct sample_event {
60 struct perf_event_header header; 60 struct perf_event_header header;
61 u64 array[]; 61 u64 array[];
62}; 62};
63 63
64struct sample_data {
65 u64 ip;
66 u32 pid, tid;
67 u64 time;
68 u64 addr;
69 u64 id;
70 u64 stream_id;
71 u32 cpu;
72 u64 period;
73 struct ip_callchain *callchain;
74 u32 raw_size;
75 void *raw_data;
76};
77
64#define BUILD_ID_SIZE 20 78#define BUILD_ID_SIZE 20
65 79
66struct build_id_event { 80struct build_id_event {
@@ -89,10 +103,11 @@ void event__print_totals(void);
89 103
90enum map_type { 104enum map_type {
91 MAP__FUNCTION = 0, 105 MAP__FUNCTION = 0,
92 106 MAP__VARIABLE,
93 MAP__NR_TYPES,
94}; 107};
95 108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
96struct map { 111struct map {
97 union { 112 union {
98 struct rb_node rb_node; 113 struct rb_node rb_node;
@@ -136,6 +151,8 @@ int map__overlap(struct map *l, struct map *r);
136size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
137struct symbol *map__find_symbol(struct map *self, u64 addr, 152struct symbol *map__find_symbol(struct map *self, u64 addr,
138 symbol_filter_t filter); 153 symbol_filter_t filter);
154struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
155 symbol_filter_t filter);
139void map__fixup_start(struct map *self); 156void map__fixup_start(struct map *self);
140void map__fixup_end(struct map *self); 157void map__fixup_end(struct map *self);
141 158
@@ -155,5 +172,6 @@ int event__process_task(event_t *self);
155struct addr_location; 172struct addr_location;
156int event__preprocess_sample(const event_t *self, struct addr_location *al, 173int event__preprocess_sample(const event_t *self, struct addr_location *al,
157 symbol_filter_t filter); 174 symbol_filter_t filter);
175int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
158 176
159#endif /* __PERF_RECORD_H */ 177#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4805e6dfd23c..f2e8d8715111 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -58,35 +58,19 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
58 return 0; 58 return 0;
59} 59}
60 60
61/* 61int perf_header__init(struct perf_header *self)
62 * Create new perf.data header:
63 */
64struct perf_header *perf_header__new(void)
65{ 62{
66 struct perf_header *self = zalloc(sizeof(*self)); 63 self->size = 1;
67 64 self->attr = malloc(sizeof(void *));
68 if (self != NULL) { 65 return self->attr == NULL ? -ENOMEM : 0;
69 self->size = 1;
70 self->attr = malloc(sizeof(void *));
71
72 if (self->attr == NULL) {
73 free(self);
74 self = NULL;
75 }
76 }
77
78 return self;
79} 66}
80 67
81void perf_header__delete(struct perf_header *self) 68void perf_header__exit(struct perf_header *self)
82{ 69{
83 int i; 70 int i;
84
85 for (i = 0; i < self->attrs; ++i) 71 for (i = 0; i < self->attrs; ++i)
86 perf_header_attr__delete(self->attr[i]); 72 perf_header_attr__delete(self->attr[i]);
87
88 free(self->attr); 73 free(self->attr);
89 free(self);
90} 74}
91 75
92int perf_header__add_attr(struct perf_header *self, 76int perf_header__add_attr(struct perf_header *self,
@@ -187,7 +171,9 @@ static int do_write(int fd, const void *buf, size_t size)
187 171
188static int __dsos__write_buildid_table(struct list_head *head, int fd) 172static int __dsos__write_buildid_table(struct list_head *head, int fd)
189{ 173{
174#define NAME_ALIGN 64
190 struct dso *pos; 175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN];
191 177
192 list_for_each_entry(pos, head, node) { 178 list_for_each_entry(pos, head, node) {
193 int err; 179 int err;
@@ -197,14 +183,17 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
197 if (!pos->has_build_id) 183 if (!pos->has_build_id)
198 continue; 184 continue;
199 len = pos->long_name_len + 1; 185 len = pos->long_name_len + 1;
200 len = ALIGN(len, 64); 186 len = ALIGN(len, NAME_ALIGN);
201 memset(&b, 0, sizeof(b)); 187 memset(&b, 0, sizeof(b));
202 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
203 b.header.size = sizeof(b) + len; 189 b.header.size = sizeof(b) + len;
204 err = do_write(fd, &b, sizeof(b)); 190 err = do_write(fd, &b, sizeof(b));
205 if (err < 0) 191 if (err < 0)
206 return err; 192 return err;
207 err = do_write(fd, pos->long_name, len); 193 err = do_write(fd, pos->long_name, pos->long_name_len + 1);
194 if (err < 0)
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
208 if (err < 0) 197 if (err < 0)
209 return err; 198 return err;
210 } 199 }
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d1dbe2b79c42..d118d05d3abe 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -55,8 +55,8 @@ struct perf_header {
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
56}; 56};
57 57
58struct perf_header *perf_header__new(void); 58int perf_header__init(struct perf_header *self);
59void perf_header__delete(struct perf_header *self); 59void perf_header__exit(struct perf_header *self);
60 60
61int perf_header__read(struct perf_header *self, int fd); 61int perf_header__read(struct perf_header *self, int fd);
62int perf_header__write(struct perf_header *self, int fd, bool at_exit); 62int perf_header__write(struct perf_header *self, int fd, bool at_exit);
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 69f94fe9db20..76bdca640a9b 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -104,43 +104,64 @@ void map__fixup_end(struct map *self)
104 104
105#define DSO__DELETED "(deleted)" 105#define DSO__DELETED "(deleted)"
106 106
107struct symbol *map__find_symbol(struct map *self, u64 addr, 107static int map__load(struct map *self, symbol_filter_t filter)
108 symbol_filter_t filter)
109{ 108{
110 if (!dso__loaded(self->dso, self->type)) { 109 const char *name = self->dso->long_name;
111 int nr = dso__load(self->dso, self, filter); 110 int nr = dso__load(self->dso, self, filter);
112 111
113 if (nr < 0) { 112 if (nr < 0) {
114 if (self->dso->has_build_id) { 113 if (self->dso->has_build_id) {
115 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 114 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
116 115
117 build_id__sprintf(self->dso->build_id, 116 build_id__sprintf(self->dso->build_id,
118 sizeof(self->dso->build_id), 117 sizeof(self->dso->build_id),
119 sbuild_id); 118 sbuild_id);
120 pr_warning("%s with build id %s not found", 119 pr_warning("%s with build id %s not found",
121 self->dso->long_name, sbuild_id); 120 name, sbuild_id);
122 } else 121 } else
123 pr_warning("Failed to open %s", 122 pr_warning("Failed to open %s", name);
124 self->dso->long_name); 123
125 pr_warning(", continuing without symbols\n"); 124 pr_warning(", continuing without symbols\n");
126 return NULL; 125 return -1;
127 } else if (nr == 0) { 126 } else if (nr == 0) {
128 const char *name = self->dso->long_name; 127 const size_t len = strlen(name);
129 const size_t len = strlen(name); 128 const size_t real_len = len - sizeof(DSO__DELETED);
130 const size_t real_len = len - sizeof(DSO__DELETED); 129
131 130 if (len > sizeof(DSO__DELETED) &&
132 if (len > sizeof(DSO__DELETED) && 131 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
133 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 132 pr_warning("%.*s was updated, restart the long "
134 pr_warning("%.*s was updated, restart the long running apps that use it!\n", 133 "running apps that use it!\n",
135 (int)real_len, name); 134 (int)real_len, name);
136 } else { 135 } else {
137 pr_warning("no symbols found in %s, maybe install a debug package?\n", name); 136 pr_warning("no symbols found in %s, maybe install "
138 } 137 "a debug package?\n", name);
139 return NULL;
140 } 138 }
139
140 return -1;
141 } 141 }
142 142
143 return self->dso->find_symbol(self->dso, self->type, addr); 143 return 0;
144}
145
146struct symbol *map__find_symbol(struct map *self, u64 addr,
147 symbol_filter_t filter)
148{
149 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
150 return NULL;
151
152 return dso__find_symbol(self->dso, self->type, addr);
153}
154
155struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
156 symbol_filter_t filter)
157{
158 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
159 return NULL;
160
161 if (!dso__sorted_by_name(self->dso, self->type))
162 dso__sort_by_name(self->dso, self->type);
163
164 return dso__find_symbol_by_name(self->dso, self->type, name);
144} 165}
145 166
146struct map *map__clone(struct map *self) 167struct map *map__clone(struct map *self)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9e5dbd66d34d..e5bc0fb016b2 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -197,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
197 if (id == config) { 197 if (id == config) {
198 closedir(evt_dir); 198 closedir(evt_dir);
199 closedir(sys_dir); 199 closedir(sys_dir);
200 path = zalloc(sizeof(path)); 200 path = zalloc(sizeof(*path));
201 path->system = malloc(MAX_EVENT_LENGTH); 201 path->system = malloc(MAX_EVENT_LENGTH);
202 if (!path->system) { 202 if (!path->system) {
203 free(path); 203 free(path);
@@ -467,7 +467,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
467 while ((evt_ent = readdir(evt_dir))) { 467 while ((evt_ent = readdir(evt_dir))) {
468 char event_opt[MAX_EVOPT_LEN + 1]; 468 char event_opt[MAX_EVOPT_LEN + 1];
469 int len; 469 int len;
470 unsigned int rem = MAX_EVOPT_LEN;
471 470
472 if (!strcmp(evt_ent->d_name, ".") 471 if (!strcmp(evt_ent->d_name, ".")
473 || !strcmp(evt_ent->d_name, "..") 472 || !strcmp(evt_ent->d_name, "..")
@@ -475,20 +474,12 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
475 || !strcmp(evt_ent->d_name, "filter")) 474 || !strcmp(evt_ent->d_name, "filter"))
476 continue; 475 continue;
477 476
478 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, 477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
479 evt_ent->d_name); 478 evt_ent->d_name, flags ? ":" : "",
479 flags ?: "");
480 if (len < 0) 480 if (len < 0)
481 return EVT_FAILED; 481 return EVT_FAILED;
482 482
483 rem -= len;
484 if (flags) {
485 if (rem < strlen(flags) + 1)
486 return EVT_FAILED;
487
488 strcat(event_opt, ":");
489 strcat(event_opt, flags);
490 }
491
492 if (parse_events(NULL, event_opt, 0)) 483 if (parse_events(NULL, event_opt, 0))
493 return EVT_FAILED; 484 return EVT_FAILED;
494 } 485 }
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 6d8af48c925e..efebd5b476b3 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -430,6 +430,9 @@ int usage_with_options_internal(const char * const *usagestr,
430 pos = fprintf(stderr, " "); 430 pos = fprintf(stderr, " ");
431 if (opts->short_name) 431 if (opts->short_name)
432 pos += fprintf(stderr, "-%c", opts->short_name); 432 pos += fprintf(stderr, "-%c", opts->short_name);
433 else
434 pos += fprintf(stderr, " ");
435
433 if (opts->long_name && opts->short_name) 436 if (opts->long_name && opts->short_name)
434 pos += fprintf(stderr, ", "); 437 pos += fprintf(stderr, ", ");
435 if (opts->long_name) 438 if (opts->long_name)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index cd7fbda5e2a5..d14a4585bcaf 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -48,6 +48,9 @@
48 48
49/* If there is no space to write, returns -E2BIG. */ 49/* If there is no space to write, returns -E2BIG. */
50static int e_snprintf(char *str, size_t size, const char *format, ...) 50static int e_snprintf(char *str, size_t size, const char *format, ...)
51 __attribute__((format(printf, 3, 4)));
52
53static int e_snprintf(char *str, size_t size, const char *format, ...)
51{ 54{
52 int ret; 55 int ret;
53 va_list ap; 56 va_list ap;
@@ -258,7 +261,7 @@ int synthesize_perf_probe_event(struct probe_point *pp)
258 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 261 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
259 offs, pp->retprobe ? "%return" : "", line); 262 offs, pp->retprobe ? "%return" : "", line);
260 else 263 else
261 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line); 264 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
262 if (ret <= 0) 265 if (ret <= 0)
263 goto error; 266 goto error;
264 len = ret; 267 len = ret;
@@ -373,14 +376,32 @@ static void clear_probe_point(struct probe_point *pp)
373 free(pp->args); 376 free(pp->args);
374 for (i = 0; i < pp->found; i++) 377 for (i = 0; i < pp->found; i++)
375 free(pp->probes[i]); 378 free(pp->probes[i]);
376 memset(pp, 0, sizeof(pp)); 379 memset(pp, 0, sizeof(*pp));
380}
381
382/* Show an event */
383static void show_perf_probe_event(const char *group, const char *event,
384 const char *place, struct probe_point *pp)
385{
386 int i;
387 char buf[128];
388
389 e_snprintf(buf, 128, "%s:%s", group, event);
390 printf(" %-40s (on %s", buf, place);
391
392 if (pp->nr_args > 0) {
393 printf(" with");
394 for (i = 0; i < pp->nr_args; i++)
395 printf(" %s", pp->args[i]);
396 }
397 printf(")\n");
377} 398}
378 399
379/* List up current perf-probe events */ 400/* List up current perf-probe events */
380void show_perf_probe_events(void) 401void show_perf_probe_events(void)
381{ 402{
382 unsigned int i; 403 unsigned int i;
383 int fd; 404 int fd, nr;
384 char *group, *event; 405 char *group, *event;
385 struct probe_point pp; 406 struct probe_point pp;
386 struct strlist *rawlist; 407 struct strlist *rawlist;
@@ -393,8 +414,13 @@ void show_perf_probe_events(void)
393 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 414 for (i = 0; i < strlist__nr_entries(rawlist); i++) {
394 ent = strlist__entry(rawlist, i); 415 ent = strlist__entry(rawlist, i);
395 parse_trace_kprobe_event(ent->s, &group, &event, &pp); 416 parse_trace_kprobe_event(ent->s, &group, &event, &pp);
417 /* Synthesize only event probe point */
418 nr = pp.nr_args;
419 pp.nr_args = 0;
396 synthesize_perf_probe_event(&pp); 420 synthesize_perf_probe_event(&pp);
397 printf("[%s:%s]\t%s\n", group, event, pp.probes[0]); 421 pp.nr_args = nr;
422 /* Show an event */
423 show_perf_probe_event(group, event, pp.probes[0], &pp);
398 free(group); 424 free(group);
399 free(event); 425 free(event);
400 clear_probe_point(&pp); 426 clear_probe_point(&pp);
@@ -404,21 +430,28 @@ void show_perf_probe_events(void)
404} 430}
405 431
406/* Get current perf-probe event names */ 432/* Get current perf-probe event names */
407static struct strlist *get_perf_event_names(int fd) 433static struct strlist *get_perf_event_names(int fd, bool include_group)
408{ 434{
409 unsigned int i; 435 unsigned int i;
410 char *group, *event; 436 char *group, *event;
437 char buf[128];
411 struct strlist *sl, *rawlist; 438 struct strlist *sl, *rawlist;
412 struct str_node *ent; 439 struct str_node *ent;
413 440
414 rawlist = get_trace_kprobe_event_rawlist(fd); 441 rawlist = get_trace_kprobe_event_rawlist(fd);
415 442
416 sl = strlist__new(false, NULL); 443 sl = strlist__new(true, NULL);
417 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 444 for (i = 0; i < strlist__nr_entries(rawlist); i++) {
418 ent = strlist__entry(rawlist, i); 445 ent = strlist__entry(rawlist, i);
419 parse_trace_kprobe_event(ent->s, &group, &event, NULL); 446 parse_trace_kprobe_event(ent->s, &group, &event, NULL);
420 strlist__add(sl, event); 447 if (include_group) {
448 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
449 die("Failed to copy group:event name.");
450 strlist__add(sl, buf);
451 } else
452 strlist__add(sl, event);
421 free(group); 453 free(group);
454 free(event);
422 } 455 }
423 456
424 strlist__delete(rawlist); 457 strlist__delete(rawlist);
@@ -426,24 +459,30 @@ static struct strlist *get_perf_event_names(int fd)
426 return sl; 459 return sl;
427} 460}
428 461
429static int write_trace_kprobe_event(int fd, const char *buf) 462static void write_trace_kprobe_event(int fd, const char *buf)
430{ 463{
431 int ret; 464 int ret;
432 465
466 pr_debug("Writing event: %s\n", buf);
433 ret = write(fd, buf, strlen(buf)); 467 ret = write(fd, buf, strlen(buf));
434 if (ret <= 0) 468 if (ret <= 0)
435 die("Failed to create event."); 469 die("Failed to write event: %s", strerror(errno));
436 else
437 printf("Added new event: %s\n", buf);
438
439 return ret;
440} 470}
441 471
442static void get_new_event_name(char *buf, size_t len, const char *base, 472static void get_new_event_name(char *buf, size_t len, const char *base,
443 struct strlist *namelist) 473 struct strlist *namelist)
444{ 474{
445 int i, ret; 475 int i, ret;
446 for (i = 0; i < MAX_EVENT_INDEX; i++) { 476
477 /* Try no suffix */
478 ret = e_snprintf(buf, len, "%s", base);
479 if (ret < 0)
480 die("snprintf() failed: %s", strerror(-ret));
481 if (!strlist__has_entry(namelist, buf))
482 return;
483
484 /* Try to add suffix */
485 for (i = 1; i < MAX_EVENT_INDEX; i++) {
447 ret = e_snprintf(buf, len, "%s_%d", base, i); 486 ret = e_snprintf(buf, len, "%s_%d", base, i);
448 if (ret < 0) 487 if (ret < 0)
449 die("snprintf() failed: %s", strerror(-ret)); 488 die("snprintf() failed: %s", strerror(-ret));
@@ -464,7 +503,7 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
464 503
465 fd = open_kprobe_events(O_RDWR, O_APPEND); 504 fd = open_kprobe_events(O_RDWR, O_APPEND);
466 /* Get current event names */ 505 /* Get current event names */
467 namelist = get_perf_event_names(fd); 506 namelist = get_perf_event_names(fd, false);
468 507
469 for (j = 0; j < nr_probes; j++) { 508 for (j = 0; j < nr_probes; j++) {
470 pp = probes + j; 509 pp = probes + j;
@@ -476,9 +515,73 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
476 PERFPROBE_GROUP, event, 515 PERFPROBE_GROUP, event,
477 pp->probes[i]); 516 pp->probes[i]);
478 write_trace_kprobe_event(fd, buf); 517 write_trace_kprobe_event(fd, buf);
518 printf("Added new event:\n");
519 /* Get the first parameter (probe-point) */
520 sscanf(pp->probes[i], "%s", buf);
521 show_perf_probe_event(PERFPROBE_GROUP, event,
522 buf, pp);
479 /* Add added event name to namelist */ 523 /* Add added event name to namelist */
480 strlist__add(namelist, event); 524 strlist__add(namelist, event);
481 } 525 }
482 } 526 }
527 /* Show how to use the event. */
528 printf("\nYou can now use it on all perf tools, such as:\n\n");
529 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
530
531 strlist__delete(namelist);
532 close(fd);
533}
534
535static void del_trace_kprobe_event(int fd, const char *group,
536 const char *event, struct strlist *namelist)
537{
538 char buf[128];
539
540 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
541 die("Failed to copy event.");
542 if (!strlist__has_entry(namelist, buf)) {
543 pr_warning("Warning: event \"%s\" is not found.\n", buf);
544 return;
545 }
546 /* Convert from perf-probe event to trace-kprobe event */
547 if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0)
548 die("Failed to copy event.");
549
550 write_trace_kprobe_event(fd, buf);
551 printf("Remove event: %s:%s\n", group, event);
552}
553
554void del_trace_kprobe_events(struct strlist *dellist)
555{
556 int fd;
557 unsigned int i;
558 const char *group, *event;
559 char *p, *str;
560 struct str_node *ent;
561 struct strlist *namelist;
562
563 fd = open_kprobe_events(O_RDWR, O_APPEND);
564 /* Get current event names */
565 namelist = get_perf_event_names(fd, true);
566
567 for (i = 0; i < strlist__nr_entries(dellist); i++) {
568 ent = strlist__entry(dellist, i);
569 str = strdup(ent->s);
570 if (!str)
571 die("Failed to copy event.");
572 p = strchr(str, ':');
573 if (p) {
574 group = str;
575 *p = '\0';
576 event = p + 1;
577 } else {
578 group = PERFPROBE_GROUP;
579 event = str;
580 }
581 del_trace_kprobe_event(fd, group, event, namelist);
582 free(str);
583 }
584 strlist__delete(namelist);
483 close(fd); 585 close(fd);
484} 586}
587
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 0c6fe56fe38a..f752159124ae 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -10,6 +10,7 @@ extern void parse_trace_kprobe_event(const char *str, char **group,
10 char **event, struct probe_point *pp); 10 char **event, struct probe_point *pp);
11extern int synthesize_trace_kprobe_event(struct probe_point *pp); 11extern int synthesize_trace_kprobe_event(struct probe_point *pp);
12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); 12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes);
13extern void del_trace_kprobe_events(struct strlist *dellist);
13extern void show_perf_probe_events(void); 14extern void show_perf_probe_events(void);
14 15
15/* Maximum index number of event-name postfix */ 16/* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 293cdfc1b8ca..4585f1d86792 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -106,7 +106,7 @@ static int strtailcmp(const char *s1, const char *s2)
106{ 106{
107 int i1 = strlen(s1); 107 int i1 = strlen(s1);
108 int i2 = strlen(s2); 108 int i2 = strlen(s2);
109 while (--i1 > 0 && --i2 > 0) { 109 while (--i1 >= 0 && --i2 >= 0) {
110 if (s1[i1] != s2[i2]) 110 if (s1[i1] != s2[i2])
111 return s1[i1] - s2[i2]; 111 return s1[i1] - s2[i2];
112 } 112 }
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
new file mode 100644
index 000000000000..707ce1cb1621
--- /dev/null
+++ b/tools/perf/util/session.c
@@ -0,0 +1,80 @@
1#include <linux/kernel.h>
2
3#include <unistd.h>
4#include <sys/types.h>
5
6#include "session.h"
7#include "util.h"
8
9static int perf_session__open(struct perf_session *self, bool force)
10{
11 struct stat input_stat;
12
13 self->fd = open(self->filename, O_RDONLY);
14 if (self->fd < 0) {
15 pr_err("failed to open file: %s", self->filename);
16 if (!strcmp(self->filename, "perf.data"))
17 pr_err(" (try 'perf record' first)");
18 pr_err("\n");
19 return -errno;
20 }
21
22 if (fstat(self->fd, &input_stat) < 0)
23 goto out_close;
24
25 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
26 pr_err("file %s not owned by current user or root\n",
27 self->filename);
28 goto out_close;
29 }
30
31 if (!input_stat.st_size) {
32 pr_info("zero-sized file (%s), nothing to do!\n",
33 self->filename);
34 goto out_close;
35 }
36
37 if (perf_header__read(&self->header, self->fd) < 0) {
38 pr_err("incompatible file format");
39 goto out_close;
40 }
41
42 self->size = input_stat.st_size;
43 return 0;
44
45out_close:
46 close(self->fd);
47 self->fd = -1;
48 return -1;
49}
50
51struct perf_session *perf_session__new(const char *filename, int mode, bool force)
52{
53 size_t len = strlen(filename) + 1;
54 struct perf_session *self = zalloc(sizeof(*self) + len);
55
56 if (self == NULL)
57 goto out;
58
59 if (perf_header__init(&self->header) < 0)
60 goto out_delete;
61
62 memcpy(self->filename, filename, len);
63
64 if (mode == O_RDONLY && perf_session__open(self, force) < 0) {
65 perf_session__delete(self);
66 self = NULL;
67 }
68out:
69 return self;
70out_delete:
71 free(self);
72 return NULL;
73}
74
75void perf_session__delete(struct perf_session *self)
76{
77 perf_header__exit(&self->header);
78 close(self->fd);
79 free(self);
80}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644
index 000000000000..f3699c8c8ed4
--- /dev/null
+++ b/tools/perf/util/session.h
@@ -0,0 +1,16 @@
1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H
3
4#include "header.h"
5
6struct perf_session {
7 struct perf_header header;
8 unsigned long size;
9 int fd;
10 char filename[0];
11};
12
13struct perf_session *perf_session__new(const char *filename, int mode, bool force);
14void perf_session__delete(struct perf_session *self);
15
16#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index fffcb937cdcb..d3d9fed74f1d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,11 +29,9 @@ enum dso_origin {
29}; 29};
30 30
31static void dsos__add(struct list_head *head, struct dso *dso); 31static void dsos__add(struct list_head *head, struct dso *dso);
32static struct map *thread__find_map_by_name(struct thread *self, char *name);
33static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 32static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
34struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
35static int dso__load_kernel_sym(struct dso *self, struct map *map, 33static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct thread *thread, symbol_filter_t filter); 34 struct map_groups *mg, symbol_filter_t filter);
37unsigned int symbol__priv_size; 35unsigned int symbol__priv_size;
38static int vmlinux_path__nr_entries; 36static int vmlinux_path__nr_entries;
39static char **vmlinux_path; 37static char **vmlinux_path;
@@ -43,19 +41,41 @@ static struct symbol_conf symbol_conf__defaults = {
43 .try_vmlinux_path = true, 41 .try_vmlinux_path = true,
44}; 42};
45 43
46static struct thread kthread_mem; 44static struct map_groups kmaps_mem;
47struct thread *kthread = &kthread_mem; 45struct map_groups *kmaps = &kmaps_mem;
48 46
49bool dso__loaded(const struct dso *self, enum map_type type) 47bool dso__loaded(const struct dso *self, enum map_type type)
50{ 48{
51 return self->loaded & (1 << type); 49 return self->loaded & (1 << type);
52} 50}
53 51
52bool dso__sorted_by_name(const struct dso *self, enum map_type type)
53{
54 return self->sorted_by_name & (1 << type);
55}
56
54static void dso__set_loaded(struct dso *self, enum map_type type) 57static void dso__set_loaded(struct dso *self, enum map_type type)
55{ 58{
56 self->loaded |= (1 << type); 59 self->loaded |= (1 << type);
57} 60}
58 61
62static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
63{
64 self->sorted_by_name |= (1 << type);
65}
66
67static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
68{
69 switch (map_type) {
70 case MAP__FUNCTION:
71 return symbol_type == 'T' || symbol_type == 'W';
72 case MAP__VARIABLE:
73 return symbol_type == 'D' || symbol_type == 'd';
74 default:
75 return false;
76 }
77}
78
59static void symbols__fixup_end(struct rb_root *self) 79static void symbols__fixup_end(struct rb_root *self)
60{ 80{
61 struct rb_node *nd, *prevnd = rb_first(self); 81 struct rb_node *nd, *prevnd = rb_first(self);
@@ -79,7 +99,7 @@ static void symbols__fixup_end(struct rb_root *self)
79 curr->end = roundup(curr->start, 4096); 99 curr->end = roundup(curr->start, 4096);
80} 100}
81 101
82static void __thread__fixup_maps_end(struct thread *self, enum map_type type) 102static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
83{ 103{
84 struct map *prev, *curr; 104 struct map *prev, *curr;
85 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 105 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
@@ -102,11 +122,11 @@ static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
102 curr->end = ~0UL; 122 curr->end = ~0UL;
103} 123}
104 124
105static void thread__fixup_maps_end(struct thread *self) 125static void map_groups__fixup_end(struct map_groups *self)
106{ 126{
107 int i; 127 int i;
108 for (i = 0; i < MAP__NR_TYPES; ++i) 128 for (i = 0; i < MAP__NR_TYPES; ++i)
109 __thread__fixup_maps_end(self, i); 129 __map_groups__fixup_end(self, i);
110} 130}
111 131
112static struct symbol *symbol__new(u64 start, u64 len, const char *name) 132static struct symbol *symbol__new(u64 start, u64 len, const char *name)
@@ -164,11 +184,11 @@ struct dso *dso__new(const char *name)
164 dso__set_long_name(self, self->name); 184 dso__set_long_name(self, self->name);
165 self->short_name = self->name; 185 self->short_name = self->name;
166 for (i = 0; i < MAP__NR_TYPES; ++i) 186 for (i = 0; i < MAP__NR_TYPES; ++i)
167 self->symbols[i] = RB_ROOT; 187 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
168 self->find_symbol = dso__find_symbol;
169 self->slen_calculated = 0; 188 self->slen_calculated = 0;
170 self->origin = DSO__ORIG_NOT_FOUND; 189 self->origin = DSO__ORIG_NOT_FOUND;
171 self->loaded = 0; 190 self->loaded = 0;
191 self->sorted_by_name = 0;
172 self->has_build_id = 0; 192 self->has_build_id = 0;
173 } 193 }
174 194
@@ -246,11 +266,85 @@ static struct symbol *symbols__find(struct rb_root *self, u64 ip)
246 return NULL; 266 return NULL;
247} 267}
248 268
249struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) 269struct symbol_name_rb_node {
270 struct rb_node rb_node;
271 struct symbol sym;
272};
273
274static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
275{
276 struct rb_node **p = &self->rb_node;
277 struct rb_node *parent = NULL;
278 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
279
280 while (*p != NULL) {
281 parent = *p;
282 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
283 if (strcmp(sym->name, s->sym.name) < 0)
284 p = &(*p)->rb_left;
285 else
286 p = &(*p)->rb_right;
287 }
288 rb_link_node(&symn->rb_node, parent, p);
289 rb_insert_color(&symn->rb_node, self);
290}
291
292static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
293{
294 struct rb_node *nd;
295
296 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
297 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
298 symbols__insert_by_name(self, pos);
299 }
300}
301
302static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
303{
304 struct rb_node *n;
305
306 if (self == NULL)
307 return NULL;
308
309 n = self->rb_node;
310
311 while (n) {
312 struct symbol_name_rb_node *s;
313 int cmp;
314
315 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
316 cmp = strcmp(name, s->sym.name);
317
318 if (cmp < 0)
319 n = n->rb_left;
320 else if (cmp > 0)
321 n = n->rb_right;
322 else
323 return &s->sym;
324 }
325
326 return NULL;
327}
328
329struct symbol *dso__find_symbol(struct dso *self,
330 enum map_type type, u64 addr)
250{ 331{
251 return symbols__find(&self->symbols[type], addr); 332 return symbols__find(&self->symbols[type], addr);
252} 333}
253 334
335struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
336 const char *name)
337{
338 return symbols__find_by_name(&self->symbol_names[type], name);
339}
340
341void dso__sort_by_name(struct dso *self, enum map_type type)
342{
343 dso__set_sorted_by_name(self, type);
344 return symbols__sort_by_name(&self->symbol_names[type],
345 &self->symbols[type]);
346}
347
254int build_id__sprintf(u8 *self, int len, char *bf) 348int build_id__sprintf(u8 *self, int len, char *bf)
255{ 349{
256 char *bid = bf; 350 char *bid = bf;
@@ -327,10 +421,7 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
327 continue; 421 continue;
328 422
329 symbol_type = toupper(line[len]); 423 symbol_type = toupper(line[len]);
330 /* 424 if (!symbol_type__is_a(symbol_type, map->type))
331 * We're interested only in code ('T'ext)
332 */
333 if (symbol_type != 'T' && symbol_type != 'W')
334 continue; 425 continue;
335 426
336 symbol_name = line + len + 2; 427 symbol_name = line + len + 2;
@@ -364,8 +455,8 @@ out_failure:
364 * kernel range is broken in several maps, named [kernel].N, as we don't have 455 * kernel range is broken in several maps, named [kernel].N, as we don't have
365 * the original ELF section names vmlinux have. 456 * the original ELF section names vmlinux have.
366 */ 457 */
367static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread, 458static int dso__split_kallsyms(struct dso *self, struct map *map,
368 symbol_filter_t filter) 459 struct map_groups *mg, symbol_filter_t filter)
369{ 460{
370 struct map *curr_map = map; 461 struct map *curr_map = map;
371 struct symbol *pos; 462 struct symbol *pos;
@@ -382,13 +473,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
382 473
383 module = strchr(pos->name, '\t'); 474 module = strchr(pos->name, '\t');
384 if (module) { 475 if (module) {
385 if (!thread->use_modules) 476 if (!mg->use_modules)
386 goto discard_symbol; 477 goto discard_symbol;
387 478
388 *module++ = '\0'; 479 *module++ = '\0';
389 480
390 if (strcmp(self->name, module)) { 481 if (strcmp(self->name, module)) {
391 curr_map = thread__find_map_by_name(thread, module); 482 curr_map = map_groups__find_by_name(mg, map->type, module);
392 if (curr_map == NULL) { 483 if (curr_map == NULL) {
393 pr_debug("/proc/{kallsyms,modules} " 484 pr_debug("/proc/{kallsyms,modules} "
394 "inconsistency!\n"); 485 "inconsistency!\n");
@@ -419,7 +510,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
419 } 510 }
420 511
421 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 512 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
422 __thread__insert_map(thread, curr_map); 513 map_groups__insert(mg, curr_map);
423 ++kernel_range; 514 ++kernel_range;
424 } 515 }
425 516
@@ -440,7 +531,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
440 531
441 532
442static int dso__load_kallsyms(struct dso *self, struct map *map, 533static int dso__load_kallsyms(struct dso *self, struct map *map,
443 struct thread *thread, symbol_filter_t filter) 534 struct map_groups *mg, symbol_filter_t filter)
444{ 535{
445 if (dso__load_all_kallsyms(self, map) < 0) 536 if (dso__load_all_kallsyms(self, map) < 0)
446 return -1; 537 return -1;
@@ -448,13 +539,13 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
448 symbols__fixup_end(&self->symbols[map->type]); 539 symbols__fixup_end(&self->symbols[map->type]);
449 self->origin = DSO__ORIG_KERNEL; 540 self->origin = DSO__ORIG_KERNEL;
450 541
451 return dso__split_kallsyms(self, map, thread, filter); 542 return dso__split_kallsyms(self, map, mg, filter);
452} 543}
453 544
454size_t kernel_maps__fprintf(FILE *fp) 545size_t kernel_maps__fprintf(FILE *fp)
455{ 546{
456 size_t printed = fprintf(fp, "Kernel maps:\n"); 547 size_t printed = fprintf(fp, "Kernel maps:\n");
457 printed += thread__fprintf_maps(kthread, fp); 548 printed += map_groups__fprintf_maps(kmaps, fp);
458 return printed + fprintf(fp, "END kernel maps\n"); 549 return printed + fprintf(fp, "END kernel maps\n");
459} 550}
460 551
@@ -544,6 +635,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
544 sym->st_shndx != SHN_UNDEF; 635 sym->st_shndx != SHN_UNDEF;
545} 636}
546 637
638static inline bool elf_sym__is_object(const GElf_Sym *sym)
639{
640 return elf_sym__type(sym) == STT_OBJECT &&
641 sym->st_name != 0 &&
642 sym->st_shndx != SHN_UNDEF;
643}
644
547static inline int elf_sym__is_label(const GElf_Sym *sym) 645static inline int elf_sym__is_label(const GElf_Sym *sym)
548{ 646{
549 return elf_sym__type(sym) == STT_NOTYPE && 647 return elf_sym__type(sym) == STT_NOTYPE &&
@@ -564,6 +662,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
564 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 662 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
565} 663}
566 664
665static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
666 const Elf_Data *secstrs)
667{
668 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
669}
670
567static inline const char *elf_sym__name(const GElf_Sym *sym, 671static inline const char *elf_sym__name(const GElf_Sym *sym,
568 const Elf_Data *symstrs) 672 const Elf_Data *symstrs)
569{ 673{
@@ -744,8 +848,32 @@ out:
744 return 0; 848 return 0;
745} 849}
746 850
851static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
852{
853 switch (type) {
854 case MAP__FUNCTION:
855 return elf_sym__is_function(self);
856 case MAP__VARIABLE:
857 return elf_sym__is_object(self);
858 default:
859 return false;
860 }
861}
862
863static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
864{
865 switch (type) {
866 case MAP__FUNCTION:
867 return elf_sec__is_text(self, secstrs);
868 case MAP__VARIABLE:
869 return elf_sec__is_data(self, secstrs);
870 default:
871 return false;
872 }
873}
874
747static int dso__load_sym(struct dso *self, struct map *map, 875static int dso__load_sym(struct dso *self, struct map *map,
748 struct thread *thread, const char *name, int fd, 876 struct map_groups *mg, const char *name, int fd,
749 symbol_filter_t filter, int kernel, int kmodule) 877 symbol_filter_t filter, int kernel, int kmodule)
750{ 878{
751 struct map *curr_map = map; 879 struct map *curr_map = map;
@@ -818,7 +946,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
818 int is_label = elf_sym__is_label(&sym); 946 int is_label = elf_sym__is_label(&sym);
819 const char *section_name; 947 const char *section_name;
820 948
821 if (!is_label && !elf_sym__is_function(&sym)) 949 if (!is_label && !elf_sym__is_a(&sym, map->type))
822 continue; 950 continue;
823 951
824 sec = elf_getscn(elf, sym.st_shndx); 952 sec = elf_getscn(elf, sym.st_shndx);
@@ -827,7 +955,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
827 955
828 gelf_getshdr(sec, &shdr); 956 gelf_getshdr(sec, &shdr);
829 957
830 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 958 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
831 continue; 959 continue;
832 960
833 elf_name = elf_sym__name(&sym, symstrs); 961 elf_name = elf_sym__name(&sym, symstrs);
@@ -849,7 +977,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
849 snprintf(dso_name, sizeof(dso_name), 977 snprintf(dso_name, sizeof(dso_name),
850 "%s%s", self->short_name, section_name); 978 "%s%s", self->short_name, section_name);
851 979
852 curr_map = thread__find_map_by_name(thread, dso_name); 980 curr_map = map_groups__find_by_name(mg, map->type, dso_name);
853 if (curr_map == NULL) { 981 if (curr_map == NULL) {
854 u64 start = sym.st_value; 982 u64 start = sym.st_value;
855 983
@@ -868,7 +996,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
868 curr_map->map_ip = identity__map_ip; 996 curr_map->map_ip = identity__map_ip;
869 curr_map->unmap_ip = identity__map_ip; 997 curr_map->unmap_ip = identity__map_ip;
870 curr_dso->origin = DSO__ORIG_KERNEL; 998 curr_dso->origin = DSO__ORIG_KERNEL;
871 __thread__insert_map(kthread, curr_map); 999 map_groups__insert(kmaps, curr_map);
872 dsos__add(&dsos__kernel, curr_dso); 1000 dsos__add(&dsos__kernel, curr_dso);
873 } else 1001 } else
874 curr_dso = curr_map->dso; 1002 curr_dso = curr_map->dso;
@@ -938,8 +1066,9 @@ static bool __dsos__read_build_ids(struct list_head *head)
938 1066
939bool dsos__read_build_ids(void) 1067bool dsos__read_build_ids(void)
940{ 1068{
941 return __dsos__read_build_ids(&dsos__kernel) || 1069 bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
942 __dsos__read_build_ids(&dsos__user); 1070 ubuildids = __dsos__read_build_ids(&dsos__user);
1071 return kbuildids || ubuildids;
943} 1072}
944 1073
945/* 1074/*
@@ -1093,7 +1222,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1093 dso__set_loaded(self, map->type); 1222 dso__set_loaded(self, map->type);
1094 1223
1095 if (self->kernel) 1224 if (self->kernel)
1096 return dso__load_kernel_sym(self, map, kthread, filter); 1225 return dso__load_kernel_sym(self, map, kmaps, filter);
1097 1226
1098 name = malloc(size); 1227 name = malloc(size);
1099 if (!name) 1228 if (!name)
@@ -1179,11 +1308,12 @@ out:
1179 return ret; 1308 return ret;
1180} 1309}
1181 1310
1182static struct map *thread__find_map_by_name(struct thread *self, char *name) 1311struct map *map_groups__find_by_name(struct map_groups *self,
1312 enum map_type type, const char *name)
1183{ 1313{
1184 struct rb_node *nd; 1314 struct rb_node *nd;
1185 1315
1186 for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 1316 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1187 struct map *map = rb_entry(nd, struct map, rb_node); 1317 struct map *map = rb_entry(nd, struct map, rb_node);
1188 1318
1189 if (map->dso && strcmp(map->dso->name, name) == 0) 1319 if (map->dso && strcmp(map->dso->name, name) == 0)
@@ -1227,7 +1357,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1227 (int)(dot - dent->d_name), dent->d_name); 1357 (int)(dot - dent->d_name), dent->d_name);
1228 1358
1229 strxfrchar(dso_name, '-', '_'); 1359 strxfrchar(dso_name, '-', '_');
1230 map = thread__find_map_by_name(kthread, dso_name); 1360 map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name);
1231 if (map == NULL) 1361 if (map == NULL)
1232 continue; 1362 continue;
1233 1363
@@ -1280,7 +1410,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1280 return self; 1410 return self;
1281} 1411}
1282 1412
1283static int thread__create_module_maps(struct thread *self) 1413static int map_groups__create_module_maps(struct map_groups *self)
1284{ 1414{
1285 char *line = NULL; 1415 char *line = NULL;
1286 size_t n; 1416 size_t n;
@@ -1337,7 +1467,7 @@ static int thread__create_module_maps(struct thread *self)
1337 dso->has_build_id = true; 1467 dso->has_build_id = true;
1338 1468
1339 dso->origin = DSO__ORIG_KMODULE; 1469 dso->origin = DSO__ORIG_KMODULE;
1340 __thread__insert_map(self, map); 1470 map_groups__insert(self, map);
1341 dsos__add(&dsos__kernel, dso); 1471 dsos__add(&dsos__kernel, dso);
1342 } 1472 }
1343 1473
@@ -1352,7 +1482,8 @@ out_failure:
1352 return -1; 1482 return -1;
1353} 1483}
1354 1484
1355static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread, 1485static int dso__load_vmlinux(struct dso *self, struct map *map,
1486 struct map_groups *mg,
1356 const char *vmlinux, symbol_filter_t filter) 1487 const char *vmlinux, symbol_filter_t filter)
1357{ 1488{
1358 int err = -1, fd; 1489 int err = -1, fd;
@@ -1386,14 +1517,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *t
1386 return -1; 1517 return -1;
1387 1518
1388 dso__set_loaded(self, map->type); 1519 dso__set_loaded(self, map->type);
1389 err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0); 1520 err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0);
1390 close(fd); 1521 close(fd);
1391 1522
1392 return err; 1523 return err;
1393} 1524}
1394 1525
1395static int dso__load_kernel_sym(struct dso *self, struct map *map, 1526static int dso__load_kernel_sym(struct dso *self, struct map *map,
1396 struct thread *thread, symbol_filter_t filter) 1527 struct map_groups *mg, symbol_filter_t filter)
1397{ 1528{
1398 int err; 1529 int err;
1399 bool is_kallsyms; 1530 bool is_kallsyms;
@@ -1403,7 +1534,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1403 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1534 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1404 vmlinux_path__nr_entries); 1535 vmlinux_path__nr_entries);
1405 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1536 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1406 err = dso__load_vmlinux(self, map, thread, 1537 err = dso__load_vmlinux(self, map, mg,
1407 vmlinux_path[i], filter); 1538 vmlinux_path[i], filter);
1408 if (err > 0) { 1539 if (err > 0) {
1409 pr_debug("Using %s for symbols\n", 1540 pr_debug("Using %s for symbols\n",
@@ -1419,12 +1550,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1419 if (is_kallsyms) 1550 if (is_kallsyms)
1420 goto do_kallsyms; 1551 goto do_kallsyms;
1421 1552
1422 err = dso__load_vmlinux(self, map, thread, self->long_name, filter); 1553 err = dso__load_vmlinux(self, map, mg, self->long_name, filter);
1423 if (err <= 0) { 1554 if (err <= 0) {
1424 pr_info("The file %s cannot be used, " 1555 pr_info("The file %s cannot be used, "
1425 "trying to use /proc/kallsyms...", self->long_name); 1556 "trying to use /proc/kallsyms...", self->long_name);
1426do_kallsyms: 1557do_kallsyms:
1427 err = dso__load_kallsyms(self, map, thread, filter); 1558 err = dso__load_kallsyms(self, map, mg, filter);
1428 if (err > 0 && !is_kallsyms) 1559 if (err > 0 && !is_kallsyms)
1429 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1560 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1430 } 1561 }
@@ -1507,42 +1638,59 @@ size_t dsos__fprintf_buildid(FILE *fp)
1507 __dsos__fprintf_buildid(&dsos__user, fp)); 1638 __dsos__fprintf_buildid(&dsos__user, fp));
1508} 1639}
1509 1640
1510static int thread__create_kernel_map(struct thread *self, const char *vmlinux) 1641static struct dso *dsos__create_kernel( const char *vmlinux)
1511{ 1642{
1512 struct map *kmap;
1513 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1643 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1514 1644
1515 if (kernel == NULL) 1645 if (kernel == NULL)
1516 return -1; 1646 return NULL;
1517
1518 kmap = map__new2(0, kernel, MAP__FUNCTION);
1519 if (kmap == NULL)
1520 goto out_delete_kernel_dso;
1521 1647
1522 kmap->map_ip = kmap->unmap_ip = identity__map_ip;
1523 kernel->short_name = "[kernel]"; 1648 kernel->short_name = "[kernel]";
1524 kernel->kernel = 1; 1649 kernel->kernel = 1;
1525 1650
1526 vdso = dso__new("[vdso]"); 1651 vdso = dso__new("[vdso]");
1527 if (vdso == NULL) 1652 if (vdso == NULL)
1528 goto out_delete_kernel_map; 1653 goto out_delete_kernel_dso;
1529 dso__set_loaded(vdso, MAP__FUNCTION); 1654 dso__set_loaded(vdso, MAP__FUNCTION);
1530 1655
1531 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 1656 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1532 sizeof(kernel->build_id)) == 0) 1657 sizeof(kernel->build_id)) == 0)
1533 kernel->has_build_id = true; 1658 kernel->has_build_id = true;
1534 1659
1535 __thread__insert_map(self, kmap);
1536 dsos__add(&dsos__kernel, kernel); 1660 dsos__add(&dsos__kernel, kernel);
1537 dsos__add(&dsos__user, vdso); 1661 dsos__add(&dsos__user, vdso);
1538 1662
1539 return 0; 1663 return kernel;
1540 1664
1541out_delete_kernel_map:
1542 map__delete(kmap);
1543out_delete_kernel_dso: 1665out_delete_kernel_dso:
1544 dso__delete(kernel); 1666 dso__delete(kernel);
1545 return -1; 1667 return NULL;
1668}
1669
1670static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux)
1671{
1672 struct map *functions, *variables;
1673 struct dso *kernel = dsos__create_kernel(vmlinux);
1674
1675 if (kernel == NULL)
1676 return -1;
1677
1678 functions = map__new2(0, kernel, MAP__FUNCTION);
1679 if (functions == NULL)
1680 return -1;
1681
1682 variables = map__new2(0, kernel, MAP__VARIABLE);
1683 if (variables == NULL) {
1684 map__delete(functions);
1685 return -1;
1686 }
1687
1688 functions->map_ip = functions->unmap_ip =
1689 variables->map_ip = variables->unmap_ip = identity__map_ip;
1690 map_groups__insert(self, functions);
1691 map_groups__insert(self, variables);
1692
1693 return 0;
1546} 1694}
1547 1695
1548static void vmlinux_path__exit(void) 1696static void vmlinux_path__exit(void)
@@ -1606,23 +1754,26 @@ int symbol__init(struct symbol_conf *conf)
1606 1754
1607 elf_version(EV_CURRENT); 1755 elf_version(EV_CURRENT);
1608 symbol__priv_size = pconf->priv_size; 1756 symbol__priv_size = pconf->priv_size;
1609 thread__init(kthread, 0); 1757 if (pconf->sort_by_name)
1758 symbol__priv_size += (sizeof(struct symbol_name_rb_node) -
1759 sizeof(struct symbol));
1760 map_groups__init(kmaps);
1610 1761
1611 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1762 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
1612 return -1; 1763 return -1;
1613 1764
1614 if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) { 1765 if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) {
1615 vmlinux_path__exit(); 1766 vmlinux_path__exit();
1616 return -1; 1767 return -1;
1617 } 1768 }
1618 1769
1619 kthread->use_modules = pconf->use_modules; 1770 kmaps->use_modules = pconf->use_modules;
1620 if (pconf->use_modules && thread__create_module_maps(kthread) < 0) 1771 if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0)
1621 pr_debug("Failed to load list of modules in use, " 1772 pr_debug("Failed to load list of modules in use, "
1622 "continuing...\n"); 1773 "continuing...\n");
1623 /* 1774 /*
1624 * Now that we have all the maps created, just set the ->end of them: 1775 * Now that we have all the maps created, just set the ->end of them:
1625 */ 1776 */
1626 thread__fixup_maps_end(kthread); 1777 map_groups__fixup_end(kmaps);
1627 return 0; 1778 return 0;
1628} 1779}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 17003efa0b39..cf99f88adf39 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -52,7 +52,8 @@ struct symbol {
52struct symbol_conf { 52struct symbol_conf {
53 unsigned short priv_size; 53 unsigned short priv_size;
54 bool try_vmlinux_path, 54 bool try_vmlinux_path,
55 use_modules; 55 use_modules,
56 sort_by_name;
56 const char *vmlinux_name; 57 const char *vmlinux_name;
57}; 58};
58 59
@@ -74,13 +75,13 @@ struct addr_location {
74struct dso { 75struct dso {
75 struct list_head node; 76 struct list_head node;
76 struct rb_root symbols[MAP__NR_TYPES]; 77 struct rb_root symbols[MAP__NR_TYPES];
77 struct symbol *(*find_symbol)(struct dso *self, 78 struct rb_root symbol_names[MAP__NR_TYPES];
78 enum map_type type, u64 addr);
79 u8 adjust_symbols:1; 79 u8 adjust_symbols:1;
80 u8 slen_calculated:1; 80 u8 slen_calculated:1;
81 u8 has_build_id:1; 81 u8 has_build_id:1;
82 u8 kernel:1; 82 u8 kernel:1;
83 unsigned char origin; 83 unsigned char origin;
84 u8 sorted_by_name;
84 u8 loaded; 85 u8 loaded;
85 u8 build_id[BUILD_ID_SIZE]; 86 u8 build_id[BUILD_ID_SIZE];
86 u16 long_name_len; 87 u16 long_name_len;
@@ -93,6 +94,9 @@ struct dso *dso__new(const char *name);
93void dso__delete(struct dso *self); 94void dso__delete(struct dso *self);
94 95
95bool dso__loaded(const struct dso *self, enum map_type type); 96bool dso__loaded(const struct dso *self, enum map_type type);
97bool dso__sorted_by_name(const struct dso *self, enum map_type type);
98
99void dso__sort_by_name(struct dso *self, enum map_type type);
96 100
97struct dso *dsos__findnew(const char *name); 101struct dso *dsos__findnew(const char *name);
98int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 102int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
@@ -103,6 +107,9 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
103size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 107size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
104char dso__symtab_origin(const struct dso *self); 108char dso__symtab_origin(const struct dso *self);
105void dso__set_build_id(struct dso *self, void *build_id); 109void dso__set_build_id(struct dso *self, void *build_id);
110struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
111struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
112 const char *name);
106 113
107int filename__read_build_id(const char *filename, void *bf, size_t size); 114int filename__read_build_id(const char *filename, void *bf, size_t size);
108int sysfs__read_build_id(const char *filename, void *bf, size_t size); 115int sysfs__read_build_id(const char *filename, void *bf, size_t size);
@@ -113,8 +120,8 @@ size_t kernel_maps__fprintf(FILE *fp);
113 120
114int symbol__init(struct symbol_conf *conf); 121int symbol__init(struct symbol_conf *conf);
115 122
116struct thread; 123struct map_groups;
117struct thread *kthread; 124struct map_groups *kmaps;
118extern struct list_head dsos__user, dsos__kernel; 125extern struct list_head dsos__user, dsos__kernel;
119extern struct dso *vdso; 126extern struct dso *vdso;
120#endif /* __PERF_SYMBOL */ 127#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 603f5610861b..b68a00ea4121 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -9,11 +9,9 @@
9static struct rb_root threads; 9static struct rb_root threads;
10static struct thread *last_match; 10static struct thread *last_match;
11 11
12void thread__init(struct thread *self, pid_t pid) 12void map_groups__init(struct map_groups *self)
13{ 13{
14 int i; 14 int i;
15 self->pid = pid;
16 self->comm = NULL;
17 for (i = 0; i < MAP__NR_TYPES; ++i) { 15 for (i = 0; i < MAP__NR_TYPES; ++i) {
18 self->maps[i] = RB_ROOT; 16 self->maps[i] = RB_ROOT;
19 INIT_LIST_HEAD(&self->removed_maps[i]); 17 INIT_LIST_HEAD(&self->removed_maps[i]);
@@ -25,7 +23,8 @@ static struct thread *thread__new(pid_t pid)
25 struct thread *self = zalloc(sizeof(*self)); 23 struct thread *self = zalloc(sizeof(*self));
26 24
27 if (self != NULL) { 25 if (self != NULL) {
28 thread__init(self, pid); 26 map_groups__init(&self->mg);
27 self->pid = pid;
29 self->comm = malloc(32); 28 self->comm = malloc(32);
30 if (self->comm) 29 if (self->comm)
31 snprintf(self->comm, 32, ":%d", self->pid); 30 snprintf(self->comm, 32, ":%d", self->pid);
@@ -55,10 +54,11 @@ int thread__comm_len(struct thread *self)
55 54
56static const char *map_type__name[MAP__NR_TYPES] = { 55static const char *map_type__name[MAP__NR_TYPES] = {
57 [MAP__FUNCTION] = "Functions", 56 [MAP__FUNCTION] = "Functions",
57 [MAP__VARIABLE] = "Variables",
58}; 58};
59 59
60static size_t __thread__fprintf_maps(struct thread *self, 60static size_t __map_groups__fprintf_maps(struct map_groups *self,
61 enum map_type type, FILE *fp) 61 enum map_type type, FILE *fp)
62{ 62{
63 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 63 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
64 struct rb_node *nd; 64 struct rb_node *nd;
@@ -76,16 +76,16 @@ static size_t __thread__fprintf_maps(struct thread *self,
76 return printed; 76 return printed;
77} 77}
78 78
79size_t thread__fprintf_maps(struct thread *self, FILE *fp) 79size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
80{ 80{
81 size_t printed = 0, i; 81 size_t printed = 0, i;
82 for (i = 0; i < MAP__NR_TYPES; ++i) 82 for (i = 0; i < MAP__NR_TYPES; ++i)
83 printed += __thread__fprintf_maps(self, i, fp); 83 printed += __map_groups__fprintf_maps(self, i, fp);
84 return printed; 84 return printed;
85} 85}
86 86
87static size_t __thread__fprintf_removed_maps(struct thread *self, 87static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
88 enum map_type type, FILE *fp) 88 enum map_type type, FILE *fp)
89{ 89{
90 struct map *pos; 90 struct map *pos;
91 size_t printed = 0; 91 size_t printed = 0;
@@ -101,20 +101,25 @@ static size_t __thread__fprintf_removed_maps(struct thread *self,
101 return printed; 101 return printed;
102} 102}
103 103
104static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp) 104static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
105{ 105{
106 size_t printed = 0, i; 106 size_t printed = 0, i;
107 for (i = 0; i < MAP__NR_TYPES; ++i) 107 for (i = 0; i < MAP__NR_TYPES; ++i)
108 printed += __thread__fprintf_removed_maps(self, i, fp); 108 printed += __map_groups__fprintf_removed_maps(self, i, fp);
109 return printed; 109 return printed;
110} 110}
111 111
112static size_t thread__fprintf(struct thread *self, FILE *fp) 112static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
113{ 113{
114 size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 114 size_t printed = map_groups__fprintf_maps(self, fp);
115 printed += thread__fprintf_removed_maps(self, fp);
116 printed += fprintf(fp, "Removed maps:\n"); 115 printed += fprintf(fp, "Removed maps:\n");
117 return printed + thread__fprintf_removed_maps(self, fp); 116 return printed + map_groups__fprintf_removed_maps(self, fp);
117}
118
119static size_t thread__fprintf(struct thread *self, FILE *fp)
120{
121 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
122 map_groups__fprintf(&self->mg, fp);
118} 123}
119 124
120struct thread *threads__findnew(pid_t pid) 125struct thread *threads__findnew(pid_t pid)
@@ -168,7 +173,8 @@ struct thread *register_idle_thread(void)
168 return thread; 173 return thread;
169} 174}
170 175
171static void thread__remove_overlappings(struct thread *self, struct map *map) 176static void map_groups__remove_overlappings(struct map_groups *self,
177 struct map *map)
172{ 178{
173 struct rb_root *root = &self->maps[map->type]; 179 struct rb_root *root = &self->maps[map->type];
174 struct rb_node *next = rb_first(root); 180 struct rb_node *next = rb_first(root);
@@ -238,12 +244,15 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
238 244
239void thread__insert_map(struct thread *self, struct map *map) 245void thread__insert_map(struct thread *self, struct map *map)
240{ 246{
241 thread__remove_overlappings(self, map); 247 map_groups__remove_overlappings(&self->mg, map);
242 maps__insert(&self->maps[map->type], map); 248 map_groups__insert(&self->mg, map);
243} 249}
244 250
245static int thread__clone_maps(struct thread *self, struct thread *parent, 251/*
246 enum map_type type) 252 * XXX This should not really _copy_ te maps, but refcount them.
253 */
254static int map_groups__clone(struct map_groups *self,
255 struct map_groups *parent, enum map_type type)
247{ 256{
248 struct rb_node *nd; 257 struct rb_node *nd;
249 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { 258 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
@@ -251,7 +260,7 @@ static int thread__clone_maps(struct thread *self, struct thread *parent,
251 struct map *new = map__clone(map); 260 struct map *new = map__clone(map);
252 if (new == NULL) 261 if (new == NULL)
253 return -ENOMEM; 262 return -ENOMEM;
254 thread__insert_map(self, new); 263 map_groups__insert(self, new);
255 } 264 }
256 return 0; 265 return 0;
257} 266}
@@ -267,7 +276,7 @@ int thread__fork(struct thread *self, struct thread *parent)
267 return -ENOMEM; 276 return -ENOMEM;
268 277
269 for (i = 0; i < MAP__NR_TYPES; ++i) 278 for (i = 0; i < MAP__NR_TYPES; ++i)
270 if (thread__clone_maps(self, parent, i) < 0) 279 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
271 return -ENOMEM; 280 return -ENOMEM;
272 return 0; 281 return 0;
273} 282}
@@ -286,11 +295,11 @@ size_t threads__fprintf(FILE *fp)
286 return ret; 295 return ret;
287} 296}
288 297
289struct symbol *thread__find_symbol(struct thread *self, 298struct symbol *map_groups__find_symbol(struct map_groups *self,
290 enum map_type type, u64 addr, 299 enum map_type type, u64 addr,
291 symbol_filter_t filter) 300 symbol_filter_t filter)
292{ 301{
293 struct map *map = thread__find_map(self, type, addr); 302 struct map *map = map_groups__find(self, type, addr);
294 303
295 if (map != NULL) 304 if (map != NULL)
296 return map__find_symbol(map, map->map_ip(map, addr), filter); 305 return map__find_symbol(map, map->map_ip(map, addr), filter);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 686d6e914d9e..1751802a09ba 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -5,52 +5,66 @@
5#include <unistd.h> 5#include <unistd.h>
6#include "symbol.h" 6#include "symbol.h"
7 7
8struct thread { 8struct map_groups {
9 struct rb_node rb_node;
10 struct rb_root maps[MAP__NR_TYPES]; 9 struct rb_root maps[MAP__NR_TYPES];
11 struct list_head removed_maps[MAP__NR_TYPES]; 10 struct list_head removed_maps[MAP__NR_TYPES];
12 pid_t pid;
13 bool use_modules; 11 bool use_modules;
12};
13
14struct thread {
15 struct rb_node rb_node;
16 struct map_groups mg;
17 pid_t pid;
14 char shortname[3]; 18 char shortname[3];
15 char *comm; 19 char *comm;
16 int comm_len; 20 int comm_len;
17}; 21};
18 22
19void thread__init(struct thread *self, pid_t pid); 23void map_groups__init(struct map_groups *self);
20int thread__set_comm(struct thread *self, const char *comm); 24int thread__set_comm(struct thread *self, const char *comm);
21int thread__comm_len(struct thread *self); 25int thread__comm_len(struct thread *self);
22struct thread *threads__findnew(pid_t pid); 26struct thread *threads__findnew(pid_t pid);
23struct thread *register_idle_thread(void); 27struct thread *register_idle_thread(void);
24void thread__insert_map(struct thread *self, struct map *map); 28void thread__insert_map(struct thread *self, struct map *map);
25int thread__fork(struct thread *self, struct thread *parent); 29int thread__fork(struct thread *self, struct thread *parent);
26size_t thread__fprintf_maps(struct thread *self, FILE *fp); 30size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
27size_t threads__fprintf(FILE *fp); 31size_t threads__fprintf(FILE *fp);
28 32
29void maps__insert(struct rb_root *maps, struct map *map); 33void maps__insert(struct rb_root *maps, struct map *map);
30struct map *maps__find(struct rb_root *maps, u64 addr); 34struct map *maps__find(struct rb_root *maps, u64 addr);
31 35
32static inline struct map *thread__find_map(struct thread *self, 36static inline void map_groups__insert(struct map_groups *self, struct map *map)
37{
38 maps__insert(&self->maps[map->type], map);
39}
40
41static inline struct map *map_groups__find(struct map_groups *self,
33 enum map_type type, u64 addr) 42 enum map_type type, u64 addr)
34{ 43{
35 return self ? maps__find(&self->maps[type], addr) : NULL; 44 return maps__find(&self->maps[type], addr);
36} 45}
37 46
38static inline void __thread__insert_map(struct thread *self, struct map *map) 47static inline struct map *thread__find_map(struct thread *self,
48 enum map_type type, u64 addr)
39{ 49{
40 maps__insert(&self->maps[map->type], map); 50 return self ? map_groups__find(&self->mg, type, addr) : NULL;
41} 51}
42 52
43void thread__find_addr_location(struct thread *self, u8 cpumode, 53void thread__find_addr_location(struct thread *self, u8 cpumode,
44 enum map_type type, u64 addr, 54 enum map_type type, u64 addr,
45 struct addr_location *al, 55 struct addr_location *al,
46 symbol_filter_t filter); 56 symbol_filter_t filter);
47struct symbol *thread__find_symbol(struct thread *self, 57struct symbol *map_groups__find_symbol(struct map_groups *self,
48 enum map_type type, u64 addr, 58 enum map_type type, u64 addr,
49 symbol_filter_t filter); 59 symbol_filter_t filter);
50 60
51static inline struct symbol * 61static inline struct symbol *
52thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) 62map_groups__find_function(struct map_groups *self, u64 addr,
63 symbol_filter_t filter)
53{ 64{
54 return thread__find_symbol(self, MAP__FUNCTION, addr, filter); 65 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
55} 66}
67
68struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name);
56#endif /* __PERF_THREAD_H */ 70#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 0302405aa2ca..c5c32be040bf 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -177,7 +177,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
177 func_count++; 177 func_count++;
178 } 178 }
179 179
180 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1); 180 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
181 181
182 i = 0; 182 i = 0;
183 while (list) { 183 while (list) {
@@ -1477,7 +1477,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1477 goto out_free; 1477 goto out_free;
1478 1478
1479 field = malloc_or_die(sizeof(*field)); 1479 field = malloc_or_die(sizeof(*field));
1480 memset(field, 0, sizeof(field)); 1480 memset(field, 0, sizeof(*field));
1481 1481
1482 value = arg_eval(arg); 1482 value = arg_eval(arg);
1483 field->value = strdup(value); 1483 field->value = strdup(value);
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
index 51e833fd58c3..a5ffe60db5d6 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/trace-event-perl.c
@@ -32,9 +32,6 @@
32 32
33void xs_init(pTHX); 33void xs_init(pTHX);
34 34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37
38void xs_init(pTHX) 35void xs_init(pTHX)
39{ 36{
40 const char *file = __FILE__; 37 const char *file = __FILE__;
@@ -573,26 +570,72 @@ struct scripting_ops perl_scripting_ops = {
573 .generate_script = perl_generate_script, 570 .generate_script = perl_generate_script,
574}; 571};
575 572
576#ifdef NO_LIBPERL 573static void print_unsupported_msg(void)
577void setup_perl_scripting(void)
578{ 574{
579 fprintf(stderr, "Perl scripting not supported." 575 fprintf(stderr, "Perl scripting not supported."
580 " Install libperl and rebuild perf to enable it. e.g. " 576 " Install libperl and rebuild perf to enable it.\n"
581 "apt-get install libperl-dev (ubuntu), yum install " 577 "For example:\n # apt-get install libperl-dev (ubuntu)"
582 "perl-ExtUtils-Embed (Fedora), etc.\n"); 578 "\n # yum install perl-ExtUtils-Embed (Fedora)"
579 "\n etc.\n");
583} 580}
584#else 581
585void setup_perl_scripting(void) 582static int perl_start_script_unsupported(const char *script __unused)
583{
584 print_unsupported_msg();
585
586 return -1;
587}
588
589static int perl_stop_script_unsupported(void)
590{
591 return 0;
592}
593
594static void perl_process_event_unsupported(int cpu __unused,
595 void *data __unused,
596 int size __unused,
597 unsigned long long nsecs __unused,
598 char *comm __unused)
599{
600}
601
602static int perl_generate_script_unsupported(const char *outfile __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609struct scripting_ops perl_scripting_unsupported_ops = {
610 .name = "Perl",
611 .start_script = perl_start_script_unsupported,
612 .stop_script = perl_stop_script_unsupported,
613 .process_event = perl_process_event_unsupported,
614 .generate_script = perl_generate_script_unsupported,
615};
616
617static void register_perl_scripting(struct scripting_ops *scripting_ops)
586{ 618{
587 int err; 619 int err;
588 err = script_spec_register("Perl", &perl_scripting_ops); 620 err = script_spec_register("Perl", scripting_ops);
589 if (err) 621 if (err)
590 die("error registering Perl script extension"); 622 die("error registering Perl script extension");
591 623
592 err = script_spec_register("pl", &perl_scripting_ops); 624 err = script_spec_register("pl", scripting_ops);
593 if (err) 625 if (err)
594 die("error registering pl script extension"); 626 die("error registering pl script extension");
595 627
596 scripting_context = malloc(sizeof(struct scripting_context)); 628 scripting_context = malloc(sizeof(struct scripting_context));
597} 629}
630
631#ifdef NO_LIBPERL
632void setup_perl_scripting(void)
633{
634 register_perl_scripting(&perl_scripting_unsupported_ops);
635}
636#else
637void setup_perl_scripting(void)
638{
639 register_perl_scripting(&perl_scripting_ops);
640}
598#endif 641#endif
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
index 8fe0d866fe1a..e88fb26137bb 100644
--- a/tools/perf/util/trace-event-perl.h
+++ b/tools/perf/util/trace-event-perl.h
@@ -34,9 +34,13 @@ typedef int INTERP;
34#define dXSUB_SYS 34#define dXSUB_SYS
35#define pTHX_ 35#define pTHX_
36static inline void newXS(const char *a, void *b, const char *c) {} 36static inline void newXS(const char *a, void *b, const char *c) {}
37static void boot_Perf__Trace__Context(pTHX_ CV *cv) {}
38static void boot_DynaLoader(pTHX_ CV *cv) {}
37#else 39#else
38#include <EXTERN.h> 40#include <EXTERN.h>
39#include <perl.h> 41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
40typedef PerlInterpreter * INTERP; 44typedef PerlInterpreter * INTERP;
41#endif 45#endif
42 46
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 342dfdd43f87..1744422cafcb 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -145,8 +145,9 @@ static void read_proc_kallsyms(void)
145 if (!size) 145 if (!size)
146 return; 146 return;
147 147
148 buf = malloc_or_die(size); 148 buf = malloc_or_die(size + 1);
149 read_or_die(buf, size); 149 read_or_die(buf, size);
150 buf[size] = '\0';
150 151
151 parse_proc_kallsyms(buf, size); 152 parse_proc_kallsyms(buf, size);
152 153