diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-14 13:13:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-14 13:13:22 -0500 |
commit | 2205afa7d13ec716935dfd4b8ff71059ee7aeb0c (patch) | |
tree | 19e63ed8040e8a82c3cdd331458d246247466a28 | |
parent | 491424c0f46c282a854b88830212bdb0763e93dc (diff) | |
parent | 2cd9046cc53dd2625e2cf5854d6cbb1ba61de914 (diff) |
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
perf sched: Fix build failure on sparc
perf bench: Add "all" pseudo subsystem and "all" pseudo suite
perf tools: Introduce perf_session class
perf symbols: Ditch dso->find_symbol
perf symbols: Allow lookups by symbol name too
perf symbols: Add missing "Variables" entry to map_type__name
perf symbols: Add support for 'variable' symtabs
perf symbols: Introduce ELF counterparts to symbol_type__is_a
perf symbols: Introduce symbol_type__is_a
perf symbols: Rename kthreads to kmaps, using another abstraction for it
perf tools: Allow building for ARM
hw-breakpoints: Handle bad modify_user_hw_breakpoint off-case return value
perf tools: Allow cross compiling
tracing, slab: Fix no callsite ifndef CONFIG_KMEMTRACE
tracing, slab: Define kmem_cache_alloc_notrace ifdef CONFIG_TRACING
Trivial conflict due to different fixes to modify_user_hw_breakpoint()
in include/linux/hw_breakpoint.h
31 files changed, 651 insertions, 353 deletions
diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h index e268388146e8..41235c93e4e9 100644 --- a/include/linux/hw_breakpoint.h +++ b/include/linux/hw_breakpoint.h | |||
@@ -93,7 +93,7 @@ register_user_hw_breakpoint(struct perf_event_attr *attr, | |||
93 | struct task_struct *tsk) { return NULL; } | 93 | struct task_struct *tsk) { return NULL; } |
94 | static inline int | 94 | static inline int |
95 | modify_user_hw_breakpoint(struct perf_event *bp, | 95 | modify_user_hw_breakpoint(struct perf_event *bp, |
96 | struct perf_event_attr *attr) { return 0; } | 96 | struct perf_event_attr *attr) { return -ENOSYS; } |
97 | static inline struct perf_event * | 97 | static inline struct perf_event * |
98 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, | 98 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, |
99 | perf_overflow_handler_t triggered, | 99 | perf_overflow_handler_t triggered, |
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h index 850d057500de..ca6b2b317991 100644 --- a/include/linux/slab_def.h +++ b/include/linux/slab_def.h | |||
@@ -110,7 +110,7 @@ extern struct cache_sizes malloc_sizes[]; | |||
110 | void *kmem_cache_alloc(struct kmem_cache *, gfp_t); | 110 | void *kmem_cache_alloc(struct kmem_cache *, gfp_t); |
111 | void *__kmalloc(size_t size, gfp_t flags); | 111 | void *__kmalloc(size_t size, gfp_t flags); |
112 | 112 | ||
113 | #ifdef CONFIG_KMEMTRACE | 113 | #ifdef CONFIG_TRACING |
114 | extern void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags); | 114 | extern void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags); |
115 | extern size_t slab_buffer_size(struct kmem_cache *cachep); | 115 | extern size_t slab_buffer_size(struct kmem_cache *cachep); |
116 | #else | 116 | #else |
@@ -166,7 +166,7 @@ found: | |||
166 | extern void *__kmalloc_node(size_t size, gfp_t flags, int node); | 166 | extern void *__kmalloc_node(size_t size, gfp_t flags, int node); |
167 | extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); | 167 | extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); |
168 | 168 | ||
169 | #ifdef CONFIG_KMEMTRACE | 169 | #ifdef CONFIG_TRACING |
170 | extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep, | 170 | extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep, |
171 | gfp_t flags, | 171 | gfp_t flags, |
172 | int nodeid); | 172 | int nodeid); |
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index 5ad70a60fd74..1e14beb23f9b 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h | |||
@@ -217,7 +217,7 @@ static __always_inline struct kmem_cache *kmalloc_slab(size_t size) | |||
217 | void *kmem_cache_alloc(struct kmem_cache *, gfp_t); | 217 | void *kmem_cache_alloc(struct kmem_cache *, gfp_t); |
218 | void *__kmalloc(size_t size, gfp_t flags); | 218 | void *__kmalloc(size_t size, gfp_t flags); |
219 | 219 | ||
220 | #ifdef CONFIG_KMEMTRACE | 220 | #ifdef CONFIG_TRACING |
221 | extern void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags); | 221 | extern void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags); |
222 | #else | 222 | #else |
223 | static __always_inline void * | 223 | static __always_inline void * |
@@ -266,7 +266,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags) | |||
266 | void *__kmalloc_node(size_t size, gfp_t flags, int node); | 266 | void *__kmalloc_node(size_t size, gfp_t flags, int node); |
267 | void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); | 267 | void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); |
268 | 268 | ||
269 | #ifdef CONFIG_KMEMTRACE | 269 | #ifdef CONFIG_TRACING |
270 | extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *s, | 270 | extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *s, |
271 | gfp_t gfpflags, | 271 | gfp_t gfpflags, |
272 | int node); | 272 | int node); |
@@ -490,7 +490,7 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp) | |||
490 | 490 | ||
491 | #endif | 491 | #endif |
492 | 492 | ||
493 | #ifdef CONFIG_KMEMTRACE | 493 | #ifdef CONFIG_TRACING |
494 | size_t slab_buffer_size(struct kmem_cache *cachep) | 494 | size_t slab_buffer_size(struct kmem_cache *cachep) |
495 | { | 495 | { |
496 | return cachep->buffer_size; | 496 | return cachep->buffer_size; |
@@ -3578,7 +3578,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) | |||
3578 | } | 3578 | } |
3579 | EXPORT_SYMBOL(kmem_cache_alloc); | 3579 | EXPORT_SYMBOL(kmem_cache_alloc); |
3580 | 3580 | ||
3581 | #ifdef CONFIG_KMEMTRACE | 3581 | #ifdef CONFIG_TRACING |
3582 | void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags) | 3582 | void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags) |
3583 | { | 3583 | { |
3584 | return __cache_alloc(cachep, flags, __builtin_return_address(0)); | 3584 | return __cache_alloc(cachep, flags, __builtin_return_address(0)); |
@@ -3641,7 +3641,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) | |||
3641 | } | 3641 | } |
3642 | EXPORT_SYMBOL(kmem_cache_alloc_node); | 3642 | EXPORT_SYMBOL(kmem_cache_alloc_node); |
3643 | 3643 | ||
3644 | #ifdef CONFIG_KMEMTRACE | 3644 | #ifdef CONFIG_TRACING |
3645 | void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep, | 3645 | void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep, |
3646 | gfp_t flags, | 3646 | gfp_t flags, |
3647 | int nodeid) | 3647 | int nodeid) |
@@ -3669,7 +3669,7 @@ __do_kmalloc_node(size_t size, gfp_t flags, int node, void *caller) | |||
3669 | return ret; | 3669 | return ret; |
3670 | } | 3670 | } |
3671 | 3671 | ||
3672 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_KMEMTRACE) | 3672 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_TRACING) |
3673 | void *__kmalloc_node(size_t size, gfp_t flags, int node) | 3673 | void *__kmalloc_node(size_t size, gfp_t flags, int node) |
3674 | { | 3674 | { |
3675 | return __do_kmalloc_node(size, flags, node, | 3675 | return __do_kmalloc_node(size, flags, node, |
@@ -3689,7 +3689,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node) | |||
3689 | return __do_kmalloc_node(size, flags, node, NULL); | 3689 | return __do_kmalloc_node(size, flags, node, NULL); |
3690 | } | 3690 | } |
3691 | EXPORT_SYMBOL(__kmalloc_node); | 3691 | EXPORT_SYMBOL(__kmalloc_node); |
3692 | #endif /* CONFIG_DEBUG_SLAB */ | 3692 | #endif /* CONFIG_DEBUG_SLAB || CONFIG_TRACING */ |
3693 | #endif /* CONFIG_NUMA */ | 3693 | #endif /* CONFIG_NUMA */ |
3694 | 3694 | ||
3695 | /** | 3695 | /** |
@@ -3721,7 +3721,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, | |||
3721 | } | 3721 | } |
3722 | 3722 | ||
3723 | 3723 | ||
3724 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_KMEMTRACE) | 3724 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_TRACING) |
3725 | void *__kmalloc(size_t size, gfp_t flags) | 3725 | void *__kmalloc(size_t size, gfp_t flags) |
3726 | { | 3726 | { |
3727 | return __do_kmalloc(size, flags, __builtin_return_address(0)); | 3727 | return __do_kmalloc(size, flags, __builtin_return_address(0)); |
@@ -1754,7 +1754,7 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) | |||
1754 | } | 1754 | } |
1755 | EXPORT_SYMBOL(kmem_cache_alloc); | 1755 | EXPORT_SYMBOL(kmem_cache_alloc); |
1756 | 1756 | ||
1757 | #ifdef CONFIG_KMEMTRACE | 1757 | #ifdef CONFIG_TRACING |
1758 | void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags) | 1758 | void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags) |
1759 | { | 1759 | { |
1760 | return slab_alloc(s, gfpflags, -1, _RET_IP_); | 1760 | return slab_alloc(s, gfpflags, -1, _RET_IP_); |
@@ -1775,7 +1775,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node) | |||
1775 | EXPORT_SYMBOL(kmem_cache_alloc_node); | 1775 | EXPORT_SYMBOL(kmem_cache_alloc_node); |
1776 | #endif | 1776 | #endif |
1777 | 1777 | ||
1778 | #ifdef CONFIG_KMEMTRACE | 1778 | #ifdef CONFIG_TRACING |
1779 | void *kmem_cache_alloc_node_notrace(struct kmem_cache *s, | 1779 | void *kmem_cache_alloc_node_notrace(struct kmem_cache *s, |
1780 | gfp_t gfpflags, | 1780 | gfp_t gfpflags, |
1781 | int node) | 1781 | int node) |
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 dcb6143a0002..bfd16a1594e4 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
@@ -11,8 +11,8 @@ | |||
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"; |
@@ -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 5f209514f657..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; |
@@ -367,11 +367,18 @@ static struct perf_file_handler file_handler = { | |||
367 | 367 | ||
368 | static int read_events(void) | 368 | static int read_events(void) |
369 | { | 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 | |||
370 | register_idle_thread(); | 376 | register_idle_thread(); |
371 | register_perf_file_handler(&file_handler); | 377 | register_perf_file_handler(&file_handler); |
372 | 378 | ||
373 | return mmap_dispatch_perf_file(&header, input_name, 0, 0, | 379 | err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd); |
374 | &event__cwdlen, &event__cwd); | 380 | perf_session__delete(session); |
381 | return err; | ||
375 | } | 382 | } |
376 | 383 | ||
377 | static double fragmentation(unsigned long n_req, unsigned long n_alloc) | 384 | static double fragmentation(unsigned long n_req, unsigned long n_alloc) |
@@ -403,7 +410,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller) | |||
403 | if (is_caller) { | 410 | if (is_caller) { |
404 | addr = data->call_site; | 411 | addr = data->call_site; |
405 | if (!raw_ip) | 412 | if (!raw_ip) |
406 | sym = thread__find_function(kthread, addr, NULL); | 413 | sym = map_groups__find_function(kmaps, addr, NULL); |
407 | } else | 414 | } else |
408 | addr = data->ptr; | 415 | addr = data->ptr; |
409 | 416 | ||
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 2b9eb3a553ed..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 | ||
@@ -701,7 +702,7 @@ static int process_read_event(event_t *event) | |||
701 | { | 702 | { |
702 | struct perf_event_attr *attr; | 703 | struct perf_event_attr *attr; |
703 | 704 | ||
704 | attr = perf_header__find_attr(event->read.id, header); | 705 | attr = perf_header__find_attr(event->read.id, &session->header); |
705 | 706 | ||
706 | if (show_threads) { | 707 | if (show_threads) { |
707 | const char *name = attr ? __event_name(attr->type, attr->config) | 708 | const char *name = attr ? __event_name(attr->type, attr->config) |
@@ -766,6 +767,10 @@ static int __cmd_report(void) | |||
766 | struct thread *idle; | 767 | struct thread *idle; |
767 | int ret; | 768 | int ret; |
768 | 769 | ||
770 | session = perf_session__new(input_name, O_RDONLY, force); | ||
771 | if (session == NULL) | ||
772 | return -ENOMEM; | ||
773 | |||
769 | idle = register_idle_thread(); | 774 | idle = register_idle_thread(); |
770 | thread__comm_adjust(idle); | 775 | thread__comm_adjust(idle); |
771 | 776 | ||
@@ -774,14 +779,14 @@ static int __cmd_report(void) | |||
774 | 779 | ||
775 | register_perf_file_handler(&file_handler); | 780 | register_perf_file_handler(&file_handler); |
776 | 781 | ||
777 | ret = mmap_dispatch_perf_file(&header, input_name, force, | 782 | ret = perf_session__process_events(session, full_paths, |
778 | full_paths, &event__cwdlen, &event__cwd); | 783 | &event__cwdlen, &event__cwd); |
779 | if (ret) | 784 | if (ret) |
780 | return ret; | 785 | goto out_delete; |
781 | 786 | ||
782 | if (dump_trace) { | 787 | if (dump_trace) { |
783 | event__print_totals(); | 788 | event__print_totals(); |
784 | return 0; | 789 | goto out_delete; |
785 | } | 790 | } |
786 | 791 | ||
787 | if (verbose > 3) | 792 | if (verbose > 3) |
@@ -796,7 +801,8 @@ static int __cmd_report(void) | |||
796 | 801 | ||
797 | if (show_threads) | 802 | if (show_threads) |
798 | perf_read_values_destroy(&show_threads_values); | 803 | perf_read_values_destroy(&show_threads_values); |
799 | 804 | out_delete: | |
805 | perf_session__delete(session); | ||
800 | return ret; | 806 | return ret; |
801 | } | 807 | } |
802 | 808 | ||
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 7cca7c15b40a..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" |
@@ -21,7 +22,6 @@ | |||
21 | 22 | ||
22 | static char const *input_name = "perf.data"; | 23 | static char const *input_name = "perf.data"; |
23 | 24 | ||
24 | static struct perf_header *header; | ||
25 | static u64 sample_type; | 25 | static u64 sample_type; |
26 | 26 | ||
27 | static char default_sort_order[] = "avg, max, switch, runtime"; | 27 | static char default_sort_order[] = "avg, max, switch, runtime"; |
@@ -1663,11 +1663,18 @@ static struct perf_file_handler file_handler = { | |||
1663 | 1663 | ||
1664 | static int read_events(void) | 1664 | static int read_events(void) |
1665 | { | 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 | |||
1666 | register_idle_thread(); | 1672 | register_idle_thread(); |
1667 | register_perf_file_handler(&file_handler); | 1673 | register_perf_file_handler(&file_handler); |
1668 | 1674 | ||
1669 | return mmap_dispatch_perf_file(&header, input_name, 0, 0, | 1675 | err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd); |
1670 | &event__cwdlen, &event__cwd); | 1676 | perf_session__delete(session); |
1677 | return err; | ||
1671 | } | 1678 | } |
1672 | 1679 | ||
1673 | static void print_bad_events(void) | 1680 | static void print_bad_events(void) |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index f472df9561ee..759dd2b35fdb 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -1059,15 +1059,17 @@ static struct perf_file_handler file_handler = { | |||
1059 | 1059 | ||
1060 | static int __cmd_timechart(void) | 1060 | static int __cmd_timechart(void) |
1061 | { | 1061 | { |
1062 | struct perf_header *header; | 1062 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); |
1063 | int ret; | 1063 | int ret; |
1064 | 1064 | ||
1065 | if (session == NULL) | ||
1066 | return -ENOMEM; | ||
1067 | |||
1065 | register_perf_file_handler(&file_handler); | 1068 | register_perf_file_handler(&file_handler); |
1066 | 1069 | ||
1067 | ret = mmap_dispatch_perf_file(&header, input_name, 0, 0, | 1070 | ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd); |
1068 | &event__cwdlen, &event__cwd); | ||
1069 | if (ret) | 1071 | if (ret) |
1070 | return EXIT_FAILURE; | 1072 | goto out_delete; |
1071 | 1073 | ||
1072 | process_samples(); | 1074 | process_samples(); |
1073 | 1075 | ||
@@ -1079,8 +1081,9 @@ static int __cmd_timechart(void) | |||
1079 | 1081 | ||
1080 | pr_info("Written %2.1f seconds of trace to %s.\n", | 1082 | pr_info("Written %2.1f seconds of trace to %s.\n", |
1081 | (last_time - first_time) / 1000000000.0, output_name); | 1083 | (last_time - first_time) / 1000000000.0, output_name); |
1082 | 1084 | out_delete: | |
1083 | return EXIT_SUCCESS; | 1085 | perf_session__delete(session); |
1086 | return ret; | ||
1084 | } | 1087 | } |
1085 | 1088 | ||
1086 | 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 c2fcc34486f5..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,7 +62,7 @@ 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) |
@@ -126,11 +127,18 @@ static struct perf_file_handler file_handler = { | |||
126 | 127 | ||
127 | static int __cmd_trace(void) | 128 | static int __cmd_trace(void) |
128 | { | 129 | { |
130 | int err; | ||
131 | |||
132 | session = perf_session__new(input_name, O_RDONLY, 0); | ||
133 | if (session == NULL) | ||
134 | return -ENOMEM; | ||
135 | |||
129 | register_idle_thread(); | 136 | register_idle_thread(); |
130 | register_perf_file_handler(&file_handler); | 137 | register_perf_file_handler(&file_handler); |
131 | 138 | ||
132 | return mmap_dispatch_perf_file(&header, input_name, | 139 | err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd); |
133 | 0, 0, &event__cwdlen, &event__cwd); | 140 | perf_session__delete(session); |
141 | return err; | ||
134 | } | 142 | } |
135 | 143 | ||
136 | struct script_spec { | 144 | struct script_spec { |
@@ -348,11 +356,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
348 | return -1; | 356 | return -1; |
349 | } | 357 | } |
350 | 358 | ||
351 | header = perf_header__new(); | 359 | perf_header__read(&session->header, input); |
352 | if (header == NULL) | ||
353 | return -1; | ||
354 | |||
355 | perf_header__read(header, input); | ||
356 | err = scripting_ops->generate_script("perf-trace"); | 360 | err = scripting_ops->generate_script("perf-trace"); |
357 | goto out; | 361 | goto out; |
358 | } | 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 59b65d0bd7c1..6d46dda53a29 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c | |||
@@ -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 258a87bcc4fb..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 full_paths, | ||
28 | int *cwdlen, | ||
29 | char **cwd); | ||
30 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); | 27 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); |
31 | 28 | ||
32 | #endif | 29 | #endif |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 4dcecafa85dc..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; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index c7a78eef8e52..51a96c2effde 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -103,10 +103,11 @@ void event__print_totals(void); | |||
103 | 103 | ||
104 | enum map_type { | 104 | enum map_type { |
105 | MAP__FUNCTION = 0, | 105 | MAP__FUNCTION = 0, |
106 | 106 | MAP__VARIABLE, | |
107 | MAP__NR_TYPES, | ||
108 | }; | 107 | }; |
109 | 108 | ||
109 | #define MAP__NR_TYPES (MAP__VARIABLE + 1) | ||
110 | |||
110 | struct map { | 111 | struct map { |
111 | union { | 112 | union { |
112 | struct rb_node rb_node; | 113 | struct rb_node rb_node; |
@@ -150,6 +151,8 @@ int map__overlap(struct map *l, struct map *r); | |||
150 | size_t map__fprintf(struct map *self, FILE *fp); | 151 | size_t map__fprintf(struct map *self, FILE *fp); |
151 | struct symbol *map__find_symbol(struct map *self, u64 addr, | 152 | struct symbol *map__find_symbol(struct map *self, u64 addr, |
152 | 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); | ||
153 | void map__fixup_start(struct map *self); | 156 | void map__fixup_start(struct map *self); |
154 | void map__fixup_end(struct map *self); | 157 | void map__fixup_end(struct map *self); |
155 | 158 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 59a9c0b3033e..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, |
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/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 e7508ad3450f..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; |
@@ -1094,7 +1222,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1094 | dso__set_loaded(self, map->type); | 1222 | dso__set_loaded(self, map->type); |
1095 | 1223 | ||
1096 | if (self->kernel) | 1224 | if (self->kernel) |
1097 | return dso__load_kernel_sym(self, map, kthread, filter); | 1225 | return dso__load_kernel_sym(self, map, kmaps, filter); |
1098 | 1226 | ||
1099 | name = malloc(size); | 1227 | name = malloc(size); |
1100 | if (!name) | 1228 | if (!name) |
@@ -1180,11 +1308,12 @@ out: | |||
1180 | return ret; | 1308 | return ret; |
1181 | } | 1309 | } |
1182 | 1310 | ||
1183 | 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) | ||
1184 | { | 1313 | { |
1185 | struct rb_node *nd; | 1314 | struct rb_node *nd; |
1186 | 1315 | ||
1187 | 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)) { |
1188 | struct map *map = rb_entry(nd, struct map, rb_node); | 1317 | struct map *map = rb_entry(nd, struct map, rb_node); |
1189 | 1318 | ||
1190 | if (map->dso && strcmp(map->dso->name, name) == 0) | 1319 | if (map->dso && strcmp(map->dso->name, name) == 0) |
@@ -1228,7 +1357,7 @@ static int dsos__set_modules_path_dir(char *dirname) | |||
1228 | (int)(dot - dent->d_name), dent->d_name); | 1357 | (int)(dot - dent->d_name), dent->d_name); |
1229 | 1358 | ||
1230 | strxfrchar(dso_name, '-', '_'); | 1359 | strxfrchar(dso_name, '-', '_'); |
1231 | map = thread__find_map_by_name(kthread, dso_name); | 1360 | map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name); |
1232 | if (map == NULL) | 1361 | if (map == NULL) |
1233 | continue; | 1362 | continue; |
1234 | 1363 | ||
@@ -1281,7 +1410,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | |||
1281 | return self; | 1410 | return self; |
1282 | } | 1411 | } |
1283 | 1412 | ||
1284 | static int thread__create_module_maps(struct thread *self) | 1413 | static int map_groups__create_module_maps(struct map_groups *self) |
1285 | { | 1414 | { |
1286 | char *line = NULL; | 1415 | char *line = NULL; |
1287 | size_t n; | 1416 | size_t n; |
@@ -1338,7 +1467,7 @@ static int thread__create_module_maps(struct thread *self) | |||
1338 | dso->has_build_id = true; | 1467 | dso->has_build_id = true; |
1339 | 1468 | ||
1340 | dso->origin = DSO__ORIG_KMODULE; | 1469 | dso->origin = DSO__ORIG_KMODULE; |
1341 | __thread__insert_map(self, map); | 1470 | map_groups__insert(self, map); |
1342 | dsos__add(&dsos__kernel, dso); | 1471 | dsos__add(&dsos__kernel, dso); |
1343 | } | 1472 | } |
1344 | 1473 | ||
@@ -1353,7 +1482,8 @@ out_failure: | |||
1353 | return -1; | 1482 | return -1; |
1354 | } | 1483 | } |
1355 | 1484 | ||
1356 | 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, | ||
1357 | const char *vmlinux, symbol_filter_t filter) | 1487 | const char *vmlinux, symbol_filter_t filter) |
1358 | { | 1488 | { |
1359 | int err = -1, fd; | 1489 | int err = -1, fd; |
@@ -1387,14 +1517,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *t | |||
1387 | return -1; | 1517 | return -1; |
1388 | 1518 | ||
1389 | dso__set_loaded(self, map->type); | 1519 | dso__set_loaded(self, map->type); |
1390 | 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); |
1391 | close(fd); | 1521 | close(fd); |
1392 | 1522 | ||
1393 | return err; | 1523 | return err; |
1394 | } | 1524 | } |
1395 | 1525 | ||
1396 | 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, |
1397 | struct thread *thread, symbol_filter_t filter) | 1527 | struct map_groups *mg, symbol_filter_t filter) |
1398 | { | 1528 | { |
1399 | int err; | 1529 | int err; |
1400 | bool is_kallsyms; | 1530 | bool is_kallsyms; |
@@ -1404,7 +1534,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1404 | pr_debug("Looking at the vmlinux_path (%d entries long)\n", | 1534 | pr_debug("Looking at the vmlinux_path (%d entries long)\n", |
1405 | vmlinux_path__nr_entries); | 1535 | vmlinux_path__nr_entries); |
1406 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { | 1536 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { |
1407 | err = dso__load_vmlinux(self, map, thread, | 1537 | err = dso__load_vmlinux(self, map, mg, |
1408 | vmlinux_path[i], filter); | 1538 | vmlinux_path[i], filter); |
1409 | if (err > 0) { | 1539 | if (err > 0) { |
1410 | pr_debug("Using %s for symbols\n", | 1540 | pr_debug("Using %s for symbols\n", |
@@ -1420,12 +1550,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1420 | if (is_kallsyms) | 1550 | if (is_kallsyms) |
1421 | goto do_kallsyms; | 1551 | goto do_kallsyms; |
1422 | 1552 | ||
1423 | err = dso__load_vmlinux(self, map, thread, self->long_name, filter); | 1553 | err = dso__load_vmlinux(self, map, mg, self->long_name, filter); |
1424 | if (err <= 0) { | 1554 | if (err <= 0) { |
1425 | pr_info("The file %s cannot be used, " | 1555 | pr_info("The file %s cannot be used, " |
1426 | "trying to use /proc/kallsyms...", self->long_name); | 1556 | "trying to use /proc/kallsyms...", self->long_name); |
1427 | do_kallsyms: | 1557 | do_kallsyms: |
1428 | err = dso__load_kallsyms(self, map, thread, filter); | 1558 | err = dso__load_kallsyms(self, map, mg, filter); |
1429 | if (err > 0 && !is_kallsyms) | 1559 | if (err > 0 && !is_kallsyms) |
1430 | dso__set_long_name(self, strdup("[kernel.kallsyms]")); | 1560 | dso__set_long_name(self, strdup("[kernel.kallsyms]")); |
1431 | } | 1561 | } |
@@ -1508,42 +1638,59 @@ size_t dsos__fprintf_buildid(FILE *fp) | |||
1508 | __dsos__fprintf_buildid(&dsos__user, fp)); | 1638 | __dsos__fprintf_buildid(&dsos__user, fp)); |
1509 | } | 1639 | } |
1510 | 1640 | ||
1511 | static int thread__create_kernel_map(struct thread *self, const char *vmlinux) | 1641 | static struct dso *dsos__create_kernel( const char *vmlinux) |
1512 | { | 1642 | { |
1513 | struct map *kmap; | ||
1514 | struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); | 1643 | struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); |
1515 | 1644 | ||
1516 | if (kernel == NULL) | 1645 | if (kernel == NULL) |
1517 | return -1; | 1646 | return NULL; |
1518 | |||
1519 | kmap = map__new2(0, kernel, MAP__FUNCTION); | ||
1520 | if (kmap == NULL) | ||
1521 | goto out_delete_kernel_dso; | ||
1522 | 1647 | ||
1523 | kmap->map_ip = kmap->unmap_ip = identity__map_ip; | ||
1524 | kernel->short_name = "[kernel]"; | 1648 | kernel->short_name = "[kernel]"; |
1525 | kernel->kernel = 1; | 1649 | kernel->kernel = 1; |
1526 | 1650 | ||
1527 | vdso = dso__new("[vdso]"); | 1651 | vdso = dso__new("[vdso]"); |
1528 | if (vdso == NULL) | 1652 | if (vdso == NULL) |
1529 | goto out_delete_kernel_map; | 1653 | goto out_delete_kernel_dso; |
1530 | dso__set_loaded(vdso, MAP__FUNCTION); | 1654 | dso__set_loaded(vdso, MAP__FUNCTION); |
1531 | 1655 | ||
1532 | if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, | 1656 | if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, |
1533 | sizeof(kernel->build_id)) == 0) | 1657 | sizeof(kernel->build_id)) == 0) |
1534 | kernel->has_build_id = true; | 1658 | kernel->has_build_id = true; |
1535 | 1659 | ||
1536 | __thread__insert_map(self, kmap); | ||
1537 | dsos__add(&dsos__kernel, kernel); | 1660 | dsos__add(&dsos__kernel, kernel); |
1538 | dsos__add(&dsos__user, vdso); | 1661 | dsos__add(&dsos__user, vdso); |
1539 | 1662 | ||
1540 | return 0; | 1663 | return kernel; |
1541 | 1664 | ||
1542 | out_delete_kernel_map: | ||
1543 | map__delete(kmap); | ||
1544 | out_delete_kernel_dso: | 1665 | out_delete_kernel_dso: |
1545 | dso__delete(kernel); | 1666 | dso__delete(kernel); |
1546 | 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; | ||
1547 | } | 1694 | } |
1548 | 1695 | ||
1549 | static void vmlinux_path__exit(void) | 1696 | static void vmlinux_path__exit(void) |
@@ -1607,23 +1754,26 @@ int symbol__init(struct symbol_conf *conf) | |||
1607 | 1754 | ||
1608 | elf_version(EV_CURRENT); | 1755 | elf_version(EV_CURRENT); |
1609 | symbol__priv_size = pconf->priv_size; | 1756 | symbol__priv_size = pconf->priv_size; |
1610 | 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); | ||
1611 | 1761 | ||
1612 | if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) | 1762 | if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) |
1613 | return -1; | 1763 | return -1; |
1614 | 1764 | ||
1615 | if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) { | 1765 | if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) { |
1616 | vmlinux_path__exit(); | 1766 | vmlinux_path__exit(); |
1617 | return -1; | 1767 | return -1; |
1618 | } | 1768 | } |
1619 | 1769 | ||
1620 | kthread->use_modules = pconf->use_modules; | 1770 | kmaps->use_modules = pconf->use_modules; |
1621 | if (pconf->use_modules && thread__create_module_maps(kthread) < 0) | 1771 | if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0) |
1622 | pr_debug("Failed to load list of modules in use, " | 1772 | pr_debug("Failed to load list of modules in use, " |
1623 | "continuing...\n"); | 1773 | "continuing...\n"); |
1624 | /* | 1774 | /* |
1625 | * 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: |
1626 | */ | 1776 | */ |
1627 | thread__fixup_maps_end(kthread); | 1777 | map_groups__fixup_end(kmaps); |
1628 | return 0; | 1778 | return 0; |
1629 | } | 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 */ |