diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-12-14 22:10:10 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-12-14 22:10:10 -0500 |
commit | e0aa51f54faa0659b529143de6c608e76675326f (patch) | |
tree | 22fc566b74bfe6bd612a858ba354818900cdc394 /tools/perf | |
parent | 9f815a1765b0ce766ab1d26ef192d30410f70b2b (diff) | |
parent | 3ea6b3d0e6d0ffd91c0f8cadeb69b7133c038b32 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'tools/perf')
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 | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf kmem' {record} [<options>] | 11 | 'perf kmem' {record|stat} [<options>] |
12 | 12 | ||
13 | DESCRIPTION | 13 | DESCRIPTION |
14 | ----------- | 14 | ----------- |
15 | There's two variants of perf kmem: | 15 | There 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 | ||
22 | OPTIONS | 22 | OPTIONS |
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 | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf probe' [options] --add 'PROBE' [--add 'PROBE' ...] | 11 | 'perf probe' [options] --add='PROBE' [...] |
12 | or | 12 | or |
13 | 'perf probe' [options] 'PROBE' ['PROBE' ...] | 13 | 'perf probe' [options] PROBE |
14 | 14 | or | |
15 | 'perf probe' [options] --del='[GROUP:]EVENT' [...] | ||
16 | or | ||
17 | 'perf probe' --list | ||
15 | 18 | ||
16 | DESCRIPTION | 19 | DESCRIPTION |
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 | ||
37 | PROBE SYNTAX | 48 | PROBE 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 | ||
238 | export prefix bindir sharedir sysconfdir | 238 | export prefix bindir sharedir sysconfdir |
239 | 239 | ||
240 | CC = gcc | 240 | CC = $(CROSS_COMPILE)gcc |
241 | AR = ar | 241 | AR = $(CROSS_COMPILE)ar |
242 | RM = rm -f | 242 | RM = rm -f |
243 | TAR = tar | 243 | TAR = tar |
244 | FIND = find | 244 | FIND = find |
@@ -356,7 +356,9 @@ LIB_H += util/parse-options.h | |||
356 | LIB_H += util/parse-events.h | 356 | LIB_H += util/parse-events.h |
357 | LIB_H += util/quote.h | 357 | LIB_H += util/quote.h |
358 | LIB_H += util/util.h | 358 | LIB_H += util/util.h |
359 | LIB_H += util/header.h | ||
359 | LIB_H += util/help.h | 360 | LIB_H += util/help.h |
361 | LIB_H += util/session.h | ||
360 | LIB_H += util/strbuf.h | 362 | LIB_H += util/strbuf.h |
361 | LIB_H += util/string.h | 363 | LIB_H += util/string.h |
362 | LIB_H += util/strlist.h | 364 | LIB_H += util/strlist.h |
@@ -405,6 +407,7 @@ LIB_OBJS += util/callchain.o | |||
405 | LIB_OBJS += util/values.o | 407 | LIB_OBJS += util/values.o |
406 | LIB_OBJS += util/debug.o | 408 | LIB_OBJS += util/debug.o |
407 | LIB_OBJS += util/map.o | 409 | LIB_OBJS += util/map.o |
410 | LIB_OBJS += util/session.o | ||
408 | LIB_OBJS += util/thread.o | 411 | LIB_OBJS += util/thread.o |
409 | LIB_OBJS += util/trace-event-parse.o | 412 | LIB_OBJS += util/trace-event-parse.o |
410 | LIB_OBJS += util/trace-event-read.o | 413 | LIB_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 |
493 | endif | 496 | endif |
494 | 497 | ||
498 | ifndef NO_LIBPERL | ||
495 | PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` | 499 | PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` |
496 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | 500 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` |
501 | endif | ||
497 | 502 | ||
498 | ifneq ($(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) | 503 | ifneq ($(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 | ||
30 | static char const *input_name = "perf.data"; | 31 | static char const *input_name = "perf.data"; |
@@ -462,21 +463,23 @@ static struct perf_file_handler file_handler = { | |||
462 | 463 | ||
463 | static int __cmd_annotate(void) | 464 | static 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(); |
495 | out_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 | ||
35 | static struct bench_suite sched_suites[] = { | 38 | static 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 | ||
142 | static 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 | |||
166 | static void all_subsystem(void) | ||
167 | { | ||
168 | int i; | ||
169 | for (i = 0; subsystems[i].suites; i++) | ||
170 | all_suite(&subsystems[i]); | ||
171 | } | ||
172 | |||
134 | int cmd_bench(int argc, const char **argv, const char *prefix __used) | 173 | int 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 | ||
18 | static char const *input_name = "perf.data"; | 18 | static char const *input_name = "perf.data"; |
19 | static int force; | 19 | static int force; |
20 | 20 | ||
21 | static const char *const buildid_list_usage[] = { | 21 | static 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, | |||
55 | static int __cmd_buildid_list(void) | 55 | static 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); | ||
105 | out_close: | ||
106 | close(input); | ||
107 | out: | ||
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 | ||
21 | static char const *input_name = "perf.data"; | 22 | static char const *input_name = "perf.data"; |
22 | 23 | ||
23 | static struct perf_header *header; | ||
24 | static u64 sample_type; | 24 | static u64 sample_type; |
25 | 25 | ||
26 | static int alloc_flag; | 26 | static int alloc_flag; |
@@ -57,11 +57,6 @@ static struct rb_root root_caller_sorted; | |||
57 | static unsigned long total_requested, total_allocated; | 57 | static unsigned long total_requested, total_allocated; |
58 | static unsigned long nr_allocs, nr_cross_allocs; | 58 | static unsigned long nr_allocs, nr_cross_allocs; |
59 | 59 | ||
60 | struct 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 | ||
67 | static void init_cpunode_map(void) | 62 | static void init_cpunode_map(void) |
@@ -201,7 +196,7 @@ static void insert_caller_stat(unsigned long call_site, | |||
201 | } | 196 | } |
202 | } | 197 | } |
203 | 198 | ||
204 | static void process_alloc_event(struct raw_event_sample *raw, | 199 | static 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 | ||
265 | static void process_free_event(struct raw_event_sample *raw, | 260 | static 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 | ||
291 | static void | 286 | static void |
292 | process_raw_event(event_t *raw_event __used, void *more_data, | 287 | process_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 | ||
321 | static int process_sample_event(event_t *event) | 315 | static 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 | ||
385 | static int read_events(void) | 368 | static 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 | ||
394 | static double fragmentation(unsigned long n_req, unsigned long n_alloc) | 384 | static 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 | ||
545 | static const char * const kmem_usage[] = { | 535 | static 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 | ||
706 | static int parse_stat_opt(const struct option *opt __used, | 696 | static 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) | 703 | static 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, | |||
739 | static const struct option kmem_options[] = { | 728 | static 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 |
47 | const char *default_search_path[NR_SEARCH_PATH] = { | 48 | const 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 | ||
65 | static bool listing; | 68 | static 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 | ||
85 | static 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 | |||
82 | static int opt_add_probe_event(const struct option *opt __used, | 104 | static 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 | ||
112 | static 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 |
91 | static int open_default_vmlinux(void) | 124 | static int open_default_vmlinux(void) |
92 | { | 125 | { |
@@ -121,6 +154,7 @@ static int open_default_vmlinux(void) | |||
121 | static const char * const probe_usage[] = { | 154 | static 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 | ||
161 | int cmd_probe(int argc, const char **argv, const char *prefix __used) | 197 | int 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 | ||
63 | static int file_new = 1; | 64 | static int file_new = 1; |
64 | 65 | ||
65 | struct perf_header *header = NULL; | 66 | static struct perf_session *session; |
66 | 67 | ||
67 | struct mmap_data { | 68 | struct 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 | ||
396 | static void atexit_header(void) | 397 | static 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 | ||
403 | static int __cmd_record(int argc, const char **argv) | 404 | static 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 | ||
53 | static char callchain_default_opt[] = "fractal,0.5"; | 54 | static char callchain_default_opt[] = "fractal,0.5"; |
54 | 55 | ||
55 | static struct perf_header *header; | 56 | static struct perf_session *session; |
56 | 57 | ||
57 | static u64 sample_type; | 58 | static u64 sample_type; |
58 | 59 | ||
@@ -605,44 +606,41 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) | |||
605 | 606 | ||
606 | static int process_sample_event(event_t *event) | 607 | static 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 | 804 | out_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 | ||
23 | static char const *input_name = "perf.data"; | 23 | static char const *input_name = "perf.data"; |
24 | 24 | ||
25 | static struct perf_header *header; | ||
26 | static u64 sample_type; | 25 | static u64 sample_type; |
27 | 26 | ||
28 | static char default_sort_order[] = "avg, max, switch, runtime"; | 27 | static 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 | ||
417 | static u64 get_cpu_usage_nsec_self(void) | 417 | static 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 | |||
435 | static 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 | ||
447 | static void *thread_func(void *ctx) | 446 | static 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 | ||
457 | again: | 458 | again: |
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 | ||
631 | struct 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 | ||
1225 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) | 1223 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) |
@@ -1356,7 +1354,7 @@ static void sort_lat(void) | |||
1356 | static struct trace_sched_handler *trace_handler; | 1354 | static struct trace_sched_handler *trace_handler; |
1357 | 1355 | ||
1358 | static void | 1356 | static void |
1359 | process_sched_wakeup_event(struct raw_event_sample *raw, | 1357 | process_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 | ||
1471 | static void | 1469 | static void |
1472 | process_sched_switch_event(struct raw_event_sample *raw, | 1470 | process_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 | ||
1504 | static void | 1502 | static void |
1505 | process_sched_runtime_event(struct raw_event_sample *raw, | 1503 | process_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 | ||
1522 | static void | 1520 | static void |
1523 | process_sched_fork_event(struct raw_event_sample *raw, | 1521 | process_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 | ||
1552 | static void | 1550 | static void |
1553 | process_sched_migrate_task_event(struct raw_event_sample *raw, | 1551 | process_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 | ||
1572 | static void | 1570 | static void |
1573 | process_raw_event(event_t *raw_event __used, void *more_data, | 1571 | process_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 | ||
1599 | static int process_sample_event(event_t *event) | 1597 | static 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 | ||
1680 | static int read_events(void) | 1664 | static 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 | ||
1689 | static void print_bad_events(void) | 1680 | static 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 | ||
1903 | int cmd_sched(int argc, const char **argv, const char *prefix __used) | 1894 | int 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 | ||
304 | struct trace_entry { | 304 | struct 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 | ||
313 | struct power_entry { | 312 | struct power_entry { |
@@ -484,43 +483,22 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
484 | static int | 483 | static int |
485 | process_sample_event(event_t *event) | 484 | process_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 | ||
1082 | static int __cmd_timechart(void) | 1060 | static 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 | 1084 | out_delete: | |
1105 | return EXIT_SUCCESS; | 1085 | perf_session__delete(session); |
1086 | return ret; | ||
1106 | } | 1087 | } |
1107 | 1088 | ||
1108 | static const char * const timechart_usage[] = { | 1089 | static 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 | ||
11 | static char const *script_name; | 12 | static char const *script_name; |
12 | static char const *generate_script_lang; | 13 | static char const *generate_script_lang; |
@@ -61,63 +62,45 @@ static int cleanup_scripting(void) | |||
61 | 62 | ||
62 | static char const *input_name = "perf.data"; | 63 | static char const *input_name = "perf.data"; |
63 | 64 | ||
64 | static struct perf_header *header; | 65 | static struct perf_session *session; |
65 | static u64 sample_type; | 66 | static u64 sample_type; |
66 | 67 | ||
67 | static int process_sample_event(event_t *event) | 68 | static 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 | ||
145 | static int __cmd_trace(void) | 128 | static 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 | ||
154 | struct script_spec { | 144 | struct 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 | ||
103 | int perf_header__read_build_ids(int input, off_t offset, off_t size) | 103 | int 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 | ||
132 | int mmap_dispatch_perf_file(struct perf_header **pheader, | 132 | int 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 | ||
220 | remap: | 176 | remap: |
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 | ||
229 | more: | 185 | more: |
@@ -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 | ||
282 | done: | 238 | done: |
283 | err = 0; | 239 | err = 0; |
284 | out_close: | 240 | out_err: |
285 | close(input); | ||
286 | |||
287 | return err; | 241 | return err; |
288 | out_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 | ||
7 | typedef int (*event_type_handler_t)(event_t *); | 8 | typedef int (*event_type_handler_t)(event_t *); |
8 | 9 | ||
@@ -21,12 +22,8 @@ struct perf_file_handler { | |||
21 | }; | 22 | }; |
22 | 23 | ||
23 | void register_perf_file_handler(struct perf_file_handler *handler); | 24 | void register_perf_file_handler(struct perf_file_handler *handler); |
24 | int mmap_dispatch_perf_file(struct perf_header **pheader, | 25 | int perf_session__process_events(struct perf_session *self, |
25 | const char *input_name, | 26 | int full_paths, int *cwdlen, char **cwd); |
26 | int force, | 27 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); |
27 | int full_paths, | ||
28 | int *cwdlen, | ||
29 | char **cwd); | ||
30 | int 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 | } |
272 | try_again: | 273 | try_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 | |||
315 | int 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 | ||
59 | struct sample_event{ | 59 | struct sample_event { |
60 | struct perf_event_header header; | 60 | struct perf_event_header header; |
61 | u64 array[]; | 61 | u64 array[]; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | struct 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 | ||
66 | struct build_id_event { | 80 | struct build_id_event { |
@@ -89,10 +103,11 @@ void event__print_totals(void); | |||
89 | 103 | ||
90 | enum map_type { | 104 | enum 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 | |||
96 | struct map { | 111 | struct 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); | |||
136 | size_t map__fprintf(struct map *self, FILE *fp); | 151 | size_t map__fprintf(struct map *self, FILE *fp); |
137 | struct symbol *map__find_symbol(struct map *self, u64 addr, | 152 | struct symbol *map__find_symbol(struct map *self, u64 addr, |
138 | symbol_filter_t filter); | 153 | symbol_filter_t filter); |
154 | struct symbol *map__find_symbol_by_name(struct map *self, const char *name, | ||
155 | symbol_filter_t filter); | ||
139 | void map__fixup_start(struct map *self); | 156 | void map__fixup_start(struct map *self); |
140 | void map__fixup_end(struct map *self); | 157 | void map__fixup_end(struct map *self); |
141 | 158 | ||
@@ -155,5 +172,6 @@ int event__process_task(event_t *self); | |||
155 | struct addr_location; | 172 | struct addr_location; |
156 | int event__preprocess_sample(const event_t *self, struct addr_location *al, | 173 | int event__preprocess_sample(const event_t *self, struct addr_location *al, |
157 | symbol_filter_t filter); | 174 | symbol_filter_t filter); |
175 | int 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 | /* | 61 | int perf_header__init(struct perf_header *self) |
62 | * Create new perf.data header: | ||
63 | */ | ||
64 | struct 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 | ||
81 | void perf_header__delete(struct perf_header *self) | 68 | void 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 | ||
92 | int perf_header__add_attr(struct perf_header *self, | 76 | int 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 | ||
188 | static int __dsos__write_buildid_table(struct list_head *head, int fd) | 172 | static 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 | ||
58 | struct perf_header *perf_header__new(void); | 58 | int perf_header__init(struct perf_header *self); |
59 | void perf_header__delete(struct perf_header *self); | 59 | void perf_header__exit(struct perf_header *self); |
60 | 60 | ||
61 | int perf_header__read(struct perf_header *self, int fd); | 61 | int perf_header__read(struct perf_header *self, int fd); |
62 | int perf_header__write(struct perf_header *self, int fd, bool at_exit); | 62 | int 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 | ||
107 | struct symbol *map__find_symbol(struct map *self, u64 addr, | 107 | static 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 | |||
146 | struct 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 | |||
155 | struct 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 | ||
146 | struct map *map__clone(struct map *self) | 167 | struct 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. */ |
50 | static int e_snprintf(char *str, size_t size, const char *format, ...) | 50 | static int e_snprintf(char *str, size_t size, const char *format, ...) |
51 | __attribute__((format(printf, 3, 4))); | ||
52 | |||
53 | static 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 */ | ||
383 | static 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 */ |
380 | void show_perf_probe_events(void) | 401 | void 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 */ |
407 | static struct strlist *get_perf_event_names(int fd) | 433 | static 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 | ||
429 | static int write_trace_kprobe_event(int fd, const char *buf) | 462 | static 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 | ||
442 | static void get_new_event_name(char *buf, size_t len, const char *base, | 472 | static 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 | |||
535 | static 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 | |||
554 | void 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); |
11 | extern int synthesize_trace_kprobe_event(struct probe_point *pp); | 11 | extern int synthesize_trace_kprobe_event(struct probe_point *pp); |
12 | extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); | 12 | extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); |
13 | extern void del_trace_kprobe_events(struct strlist *dellist); | ||
13 | extern void show_perf_probe_events(void); | 14 | extern 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 | |||
9 | static 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 | |||
45 | out_close: | ||
46 | close(self->fd); | ||
47 | self->fd = -1; | ||
48 | return -1; | ||
49 | } | ||
50 | |||
51 | struct 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 | } | ||
68 | out: | ||
69 | return self; | ||
70 | out_delete: | ||
71 | free(self); | ||
72 | return NULL; | ||
73 | } | ||
74 | |||
75 | void 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 | |||
6 | struct perf_session { | ||
7 | struct perf_header header; | ||
8 | unsigned long size; | ||
9 | int fd; | ||
10 | char filename[0]; | ||
11 | }; | ||
12 | |||
13 | struct perf_session *perf_session__new(const char *filename, int mode, bool force); | ||
14 | void 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 | ||
31 | static void dsos__add(struct list_head *head, struct dso *dso); | 31 | static void dsos__add(struct list_head *head, struct dso *dso); |
32 | static struct map *thread__find_map_by_name(struct thread *self, char *name); | ||
33 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 32 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
34 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); | ||
35 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 33 | static 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); |
37 | unsigned int symbol__priv_size; | 35 | unsigned int symbol__priv_size; |
38 | static int vmlinux_path__nr_entries; | 36 | static int vmlinux_path__nr_entries; |
39 | static char **vmlinux_path; | 37 | static 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 | ||
46 | static struct thread kthread_mem; | 44 | static struct map_groups kmaps_mem; |
47 | struct thread *kthread = &kthread_mem; | 45 | struct map_groups *kmaps = &kmaps_mem; |
48 | 46 | ||
49 | bool dso__loaded(const struct dso *self, enum map_type type) | 47 | bool 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 | ||
52 | bool dso__sorted_by_name(const struct dso *self, enum map_type type) | ||
53 | { | ||
54 | return self->sorted_by_name & (1 << type); | ||
55 | } | ||
56 | |||
54 | static void dso__set_loaded(struct dso *self, enum map_type type) | 57 | static 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 | ||
62 | static void dso__set_sorted_by_name(struct dso *self, enum map_type type) | ||
63 | { | ||
64 | self->sorted_by_name |= (1 << type); | ||
65 | } | ||
66 | |||
67 | static 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 | |||
59 | static void symbols__fixup_end(struct rb_root *self) | 79 | static 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 | ||
82 | static void __thread__fixup_maps_end(struct thread *self, enum map_type type) | 102 | static 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 | ||
105 | static void thread__fixup_maps_end(struct thread *self) | 125 | static 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 | ||
112 | static struct symbol *symbol__new(u64 start, u64 len, const char *name) | 132 | static 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 | ||
249 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) | 269 | struct symbol_name_rb_node { |
270 | struct rb_node rb_node; | ||
271 | struct symbol sym; | ||
272 | }; | ||
273 | |||
274 | static 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 | |||
292 | static 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 | |||
302 | static 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 | |||
329 | struct 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 | ||
335 | struct 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 | |||
341 | void 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 | |||
254 | int build_id__sprintf(u8 *self, int len, char *bf) | 348 | int 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 | */ |
367 | static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread, | 458 | static 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 | ||
442 | static int dso__load_kallsyms(struct dso *self, struct map *map, | 533 | static 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 | ||
454 | size_t kernel_maps__fprintf(FILE *fp) | 545 | size_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 | ||
638 | static 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 | |||
547 | static inline int elf_sym__is_label(const GElf_Sym *sym) | 645 | static 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 | ||
665 | static 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 | |||
567 | static inline const char *elf_sym__name(const GElf_Sym *sym, | 671 | static 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 | ||
851 | static 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 | |||
863 | static 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 | |||
747 | static int dso__load_sym(struct dso *self, struct map *map, | 875 | static 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 | ||
939 | bool dsos__read_build_ids(void) | 1067 | bool 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 | ||
1182 | static struct map *thread__find_map_by_name(struct thread *self, char *name) | 1311 | struct 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 | ||
1283 | static int thread__create_module_maps(struct thread *self) | 1413 | static 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 | ||
1355 | static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread, | 1485 | static 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 | ||
1395 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 1526 | static 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); |
1426 | do_kallsyms: | 1557 | do_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 | ||
1510 | static int thread__create_kernel_map(struct thread *self, const char *vmlinux) | 1641 | static 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 | ||
1541 | out_delete_kernel_map: | ||
1542 | map__delete(kmap); | ||
1543 | out_delete_kernel_dso: | 1665 | out_delete_kernel_dso: |
1544 | dso__delete(kernel); | 1666 | dso__delete(kernel); |
1545 | return -1; | 1667 | return NULL; |
1668 | } | ||
1669 | |||
1670 | static 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 | ||
1548 | static void vmlinux_path__exit(void) | 1696 | static 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 { | |||
52 | struct symbol_conf { | 52 | struct 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 { | |||
74 | struct dso { | 75 | struct 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); | |||
93 | void dso__delete(struct dso *self); | 94 | void dso__delete(struct dso *self); |
94 | 95 | ||
95 | bool dso__loaded(const struct dso *self, enum map_type type); | 96 | bool dso__loaded(const struct dso *self, enum map_type type); |
97 | bool dso__sorted_by_name(const struct dso *self, enum map_type type); | ||
98 | |||
99 | void dso__sort_by_name(struct dso *self, enum map_type type); | ||
96 | 100 | ||
97 | struct dso *dsos__findnew(const char *name); | 101 | struct dso *dsos__findnew(const char *name); |
98 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); | 102 | int 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); | |||
103 | size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); | 107 | size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); |
104 | char dso__symtab_origin(const struct dso *self); | 108 | char dso__symtab_origin(const struct dso *self); |
105 | void dso__set_build_id(struct dso *self, void *build_id); | 109 | void dso__set_build_id(struct dso *self, void *build_id); |
110 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); | ||
111 | struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, | ||
112 | const char *name); | ||
106 | 113 | ||
107 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 114 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
108 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 115 | int 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 | ||
114 | int symbol__init(struct symbol_conf *conf); | 121 | int symbol__init(struct symbol_conf *conf); |
115 | 122 | ||
116 | struct thread; | 123 | struct map_groups; |
117 | struct thread *kthread; | 124 | struct map_groups *kmaps; |
118 | extern struct list_head dsos__user, dsos__kernel; | 125 | extern struct list_head dsos__user, dsos__kernel; |
119 | extern struct dso *vdso; | 126 | extern 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 @@ | |||
9 | static struct rb_root threads; | 9 | static struct rb_root threads; |
10 | static struct thread *last_match; | 10 | static struct thread *last_match; |
11 | 11 | ||
12 | void thread__init(struct thread *self, pid_t pid) | 12 | void 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 | ||
56 | static const char *map_type__name[MAP__NR_TYPES] = { | 55 | static const char *map_type__name[MAP__NR_TYPES] = { |
57 | [MAP__FUNCTION] = "Functions", | 56 | [MAP__FUNCTION] = "Functions", |
57 | [MAP__VARIABLE] = "Variables", | ||
58 | }; | 58 | }; |
59 | 59 | ||
60 | static size_t __thread__fprintf_maps(struct thread *self, | 60 | static 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 | ||
79 | size_t thread__fprintf_maps(struct thread *self, FILE *fp) | 79 | size_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 | ||
87 | static size_t __thread__fprintf_removed_maps(struct thread *self, | 87 | static 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 | ||
104 | static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp) | 104 | static 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 | ||
112 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 112 | static 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 | |||
119 | static 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 | ||
120 | struct thread *threads__findnew(pid_t pid) | 125 | struct 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 | ||
171 | static void thread__remove_overlappings(struct thread *self, struct map *map) | 176 | static 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 | ||
239 | void thread__insert_map(struct thread *self, struct map *map) | 245 | void 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 | ||
245 | static 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 | */ | ||
254 | static 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 | ||
289 | struct symbol *thread__find_symbol(struct thread *self, | 298 | struct 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 | ||
8 | struct thread { | 8 | struct 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 | |||
14 | struct 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 | ||
19 | void thread__init(struct thread *self, pid_t pid); | 23 | void map_groups__init(struct map_groups *self); |
20 | int thread__set_comm(struct thread *self, const char *comm); | 24 | int thread__set_comm(struct thread *self, const char *comm); |
21 | int thread__comm_len(struct thread *self); | 25 | int thread__comm_len(struct thread *self); |
22 | struct thread *threads__findnew(pid_t pid); | 26 | struct thread *threads__findnew(pid_t pid); |
23 | struct thread *register_idle_thread(void); | 27 | struct thread *register_idle_thread(void); |
24 | void thread__insert_map(struct thread *self, struct map *map); | 28 | void thread__insert_map(struct thread *self, struct map *map); |
25 | int thread__fork(struct thread *self, struct thread *parent); | 29 | int thread__fork(struct thread *self, struct thread *parent); |
26 | size_t thread__fprintf_maps(struct thread *self, FILE *fp); | 30 | size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp); |
27 | size_t threads__fprintf(FILE *fp); | 31 | size_t threads__fprintf(FILE *fp); |
28 | 32 | ||
29 | void maps__insert(struct rb_root *maps, struct map *map); | 33 | void maps__insert(struct rb_root *maps, struct map *map); |
30 | struct map *maps__find(struct rb_root *maps, u64 addr); | 34 | struct map *maps__find(struct rb_root *maps, u64 addr); |
31 | 35 | ||
32 | static inline struct map *thread__find_map(struct thread *self, | 36 | static inline void map_groups__insert(struct map_groups *self, struct map *map) |
37 | { | ||
38 | maps__insert(&self->maps[map->type], map); | ||
39 | } | ||
40 | |||
41 | static 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 | ||
38 | static inline void __thread__insert_map(struct thread *self, struct map *map) | 47 | static 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 | ||
43 | void thread__find_addr_location(struct thread *self, u8 cpumode, | 53 | void 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); |
47 | struct symbol *thread__find_symbol(struct thread *self, | 57 | struct 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 | ||
51 | static inline struct symbol * | 61 | static inline struct symbol * |
52 | thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) | 62 | map_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 | |||
68 | struct 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 | ||
33 | void xs_init(pTHX); | 33 | void xs_init(pTHX); |
34 | 34 | ||
35 | void boot_Perf__Trace__Context(pTHX_ CV *cv); | ||
36 | void boot_DynaLoader(pTHX_ CV *cv); | ||
37 | |||
38 | void xs_init(pTHX) | 35 | void 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 | 573 | static void print_unsupported_msg(void) |
577 | void 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 | |
585 | void setup_perl_scripting(void) | 582 | static int perl_start_script_unsupported(const char *script __unused) |
583 | { | ||
584 | print_unsupported_msg(); | ||
585 | |||
586 | return -1; | ||
587 | } | ||
588 | |||
589 | static int perl_stop_script_unsupported(void) | ||
590 | { | ||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | static 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 | |||
602 | static int perl_generate_script_unsupported(const char *outfile __unused) | ||
603 | { | ||
604 | print_unsupported_msg(); | ||
605 | |||
606 | return -1; | ||
607 | } | ||
608 | |||
609 | struct 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 | |||
617 | static 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 | ||
632 | void setup_perl_scripting(void) | ||
633 | { | ||
634 | register_perl_scripting(&perl_scripting_unsupported_ops); | ||
635 | } | ||
636 | #else | ||
637 | void 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_ |
36 | static inline void newXS(const char *a, void *b, const char *c) {} | 36 | static inline void newXS(const char *a, void *b, const char *c) {} |
37 | static void boot_Perf__Trace__Context(pTHX_ CV *cv) {} | ||
38 | static 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> |
42 | void boot_Perf__Trace__Context(pTHX_ CV *cv); | ||
43 | void boot_DynaLoader(pTHX_ CV *cv); | ||
40 | typedef PerlInterpreter * INTERP; | 44 | typedef 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 | ||