aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-14 13:13:22 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-14 13:13:22 -0500
commit2205afa7d13ec716935dfd4b8ff71059ee7aeb0c (patch)
tree19e63ed8040e8a82c3cdd331458d246247466a28
parent491424c0f46c282a854b88830212bdb0763e93dc (diff)
parent2cd9046cc53dd2625e2cf5854d6cbb1ba61de914 (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
-rw-r--r--include/linux/hw_breakpoint.h2
-rw-r--r--include/linux/slab_def.h4
-rw-r--r--include/linux/slub_def.h4
-rw-r--r--mm/slab.c12
-rw-r--r--mm/slub.c4
-rw-r--r--tools/perf/Makefile9
-rw-r--r--tools/perf/bench/sched-messaging.c8
-rw-r--r--tools/perf/bench/sched-pipe.c11
-rw-r--r--tools/perf/builtin-annotate.c15
-rw-r--r--tools/perf/builtin-bench.c57
-rw-r--r--tools/perf/builtin-buildid-list.c55
-rw-r--r--tools/perf/builtin-kmem.c15
-rw-r--r--tools/perf/builtin-record.c25
-rw-r--r--tools/perf/builtin-report.c20
-rw-r--r--tools/perf/builtin-sched.c13
-rw-r--r--tools/perf/builtin-timechart.c15
-rw-r--r--tools/perf/builtin-trace.c20
-rw-r--r--tools/perf/perf.h12
-rw-r--r--tools/perf/util/data_map.c71
-rw-r--r--tools/perf/util/data_map.h9
-rw-r--r--tools/perf/util/event.c11
-rw-r--r--tools/perf/util/event.h7
-rw-r--r--tools/perf/util/header.c28
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/map.c87
-rw-r--r--tools/perf/util/session.c80
-rw-r--r--tools/perf/util/session.h16
-rw-r--r--tools/perf/util/symbol.c268
-rw-r--r--tools/perf/util/symbol.h17
-rw-r--r--tools/perf/util/thread.c63
-rw-r--r--tools/perf/util/thread.h42
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; }
94static inline int 94static inline int
95modify_user_hw_breakpoint(struct perf_event *bp, 95modify_user_hw_breakpoint(struct perf_event *bp,
96 struct perf_event_attr *attr) { return 0; } 96 struct perf_event_attr *attr) { return -ENOSYS; }
97static inline struct perf_event * 97static inline struct perf_event *
98register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, 98register_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[];
110void *kmem_cache_alloc(struct kmem_cache *, gfp_t); 110void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
111void *__kmalloc(size_t size, gfp_t flags); 111void *__kmalloc(size_t size, gfp_t flags);
112 112
113#ifdef CONFIG_KMEMTRACE 113#ifdef CONFIG_TRACING
114extern void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags); 114extern void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags);
115extern size_t slab_buffer_size(struct kmem_cache *cachep); 115extern size_t slab_buffer_size(struct kmem_cache *cachep);
116#else 116#else
@@ -166,7 +166,7 @@ found:
166extern void *__kmalloc_node(size_t size, gfp_t flags, int node); 166extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
167extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); 167extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
168 168
169#ifdef CONFIG_KMEMTRACE 169#ifdef CONFIG_TRACING
170extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep, 170extern 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)
217void *kmem_cache_alloc(struct kmem_cache *, gfp_t); 217void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
218void *__kmalloc(size_t size, gfp_t flags); 218void *__kmalloc(size_t size, gfp_t flags);
219 219
220#ifdef CONFIG_KMEMTRACE 220#ifdef CONFIG_TRACING
221extern void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags); 221extern void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags);
222#else 222#else
223static __always_inline void * 223static __always_inline void *
@@ -266,7 +266,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
266void *__kmalloc_node(size_t size, gfp_t flags, int node); 266void *__kmalloc_node(size_t size, gfp_t flags, int node);
267void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); 267void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
268 268
269#ifdef CONFIG_KMEMTRACE 269#ifdef CONFIG_TRACING
270extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *s, 270extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
271 gfp_t gfpflags, 271 gfp_t gfpflags,
272 int node); 272 int node);
diff --git a/mm/slab.c b/mm/slab.c
index 29b09599af7c..3f4822938f46 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -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
494size_t slab_buffer_size(struct kmem_cache *cachep) 494size_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}
3579EXPORT_SYMBOL(kmem_cache_alloc); 3579EXPORT_SYMBOL(kmem_cache_alloc);
3580 3580
3581#ifdef CONFIG_KMEMTRACE 3581#ifdef CONFIG_TRACING
3582void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags) 3582void *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}
3642EXPORT_SYMBOL(kmem_cache_alloc_node); 3642EXPORT_SYMBOL(kmem_cache_alloc_node);
3643 3643
3644#ifdef CONFIG_KMEMTRACE 3644#ifdef CONFIG_TRACING
3645void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep, 3645void *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)
3673void *__kmalloc_node(size_t size, gfp_t flags, int node) 3673void *__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}
3691EXPORT_SYMBOL(__kmalloc_node); 3691EXPORT_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)
3725void *__kmalloc(size_t size, gfp_t flags) 3725void *__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));
diff --git a/mm/slub.c b/mm/slub.c
index da0ce55965dc..8d71aaf888d7 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1754,7 +1754,7 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
1754} 1754}
1755EXPORT_SYMBOL(kmem_cache_alloc); 1755EXPORT_SYMBOL(kmem_cache_alloc);
1756 1756
1757#ifdef CONFIG_KMEMTRACE 1757#ifdef CONFIG_TRACING
1758void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags) 1758void *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)
1775EXPORT_SYMBOL(kmem_cache_alloc_node); 1775EXPORT_SYMBOL(kmem_cache_alloc_node);
1776#endif 1776#endif
1777 1777
1778#ifdef CONFIG_KMEMTRACE 1778#ifdef CONFIG_TRACING
1779void *kmem_cache_alloc_node_notrace(struct kmem_cache *s, 1779void *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
238export prefix bindir sharedir sysconfdir 238export prefix bindir sharedir sysconfdir
239 239
240CC = gcc 240CC = $(CROSS_COMPILE)gcc
241AR = ar 241AR = $(CROSS_COMPILE)ar
242RM = rm -f 242RM = rm -f
243TAR = tar 243TAR = tar
244FIND = find 244FIND = find
@@ -356,7 +356,9 @@ LIB_H += util/parse-options.h
356LIB_H += util/parse-events.h 356LIB_H += util/parse-events.h
357LIB_H += util/quote.h 357LIB_H += util/quote.h
358LIB_H += util/util.h 358LIB_H += util/util.h
359LIB_H += util/header.h
359LIB_H += util/help.h 360LIB_H += util/help.h
361LIB_H += util/session.h
360LIB_H += util/strbuf.h 362LIB_H += util/strbuf.h
361LIB_H += util/string.h 363LIB_H += util/string.h
362LIB_H += util/strlist.h 364LIB_H += util/strlist.h
@@ -405,6 +407,7 @@ LIB_OBJS += util/callchain.o
405LIB_OBJS += util/values.o 407LIB_OBJS += util/values.o
406LIB_OBJS += util/debug.o 408LIB_OBJS += util/debug.o
407LIB_OBJS += util/map.o 409LIB_OBJS += util/map.o
410LIB_OBJS += util/session.o
408LIB_OBJS += util/thread.o 411LIB_OBJS += util/thread.o
409LIB_OBJS += util/trace-event-parse.o 412LIB_OBJS += util/trace-event-parse.o
410LIB_OBJS += util/trace-event-read.o 413LIB_OBJS += util/trace-event-read.o
@@ -492,8 +495,10 @@ else
492 LIB_OBJS += util/probe-finder.o 495 LIB_OBJS += util/probe-finder.o
493endif 496endif
494 497
498ifndef NO_LIBPERL
495PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` 499PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
496PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 500PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
501endif
497 502
498ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) 503ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
499 BASIC_CFLAGS += -DNO_LIBPERL 504 BASIC_CFLAGS += -DNO_LIBPERL
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index 605a2a959aa8..81cee78181fa 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * builtin-bench-messaging.c 3 * sched-messaging.c
4 * 4 *
5 * messaging: Benchmark for scheduler and IPC mechanisms 5 * messaging: Benchmark for scheduler and IPC mechanisms
6 * 6 *
@@ -320,10 +320,12 @@ int bench_sched_messaging(int argc, const char **argv,
320 num_groups, num_groups * 2 * num_fds, 320 num_groups, num_groups * 2 * num_fds,
321 thread_mode ? "threads" : "processes"); 321 thread_mode ? "threads" : "processes");
322 printf(" %14s: %lu.%03lu [sec]\n", "Total time", 322 printf(" %14s: %lu.%03lu [sec]\n", "Total time",
323 diff.tv_sec, diff.tv_usec/1000); 323 diff.tv_sec,
324 (unsigned long) (diff.tv_usec/1000));
324 break; 325 break;
325 case BENCH_FORMAT_SIMPLE: 326 case BENCH_FORMAT_SIMPLE:
326 printf("%lu.%03lu\n", diff.tv_sec, diff.tv_usec/1000); 327 printf("%lu.%03lu\n", diff.tv_sec,
328 (unsigned long) (diff.tv_usec/1000));
327 break; 329 break;
328 default: 330 default:
329 /* reaching here is something disaster */ 331 /* reaching here is something disaster */
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 238185f97977..4f77c7c27640 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * builtin-bench-pipe.c 3 * sched-pipe.c
4 * 4 *
5 * pipe: Benchmark for pipe() 5 * pipe: Benchmark for pipe()
6 * 6 *
@@ -87,7 +87,8 @@ int bench_sched_pipe(int argc, const char **argv,
87 if (pid) { 87 if (pid) {
88 retpid = waitpid(pid, &wait_stat, 0); 88 retpid = waitpid(pid, &wait_stat, 0);
89 assert((retpid == pid) && WIFEXITED(wait_stat)); 89 assert((retpid == pid) && WIFEXITED(wait_stat));
90 return 0; 90 } else {
91 exit(0);
91 } 92 }
92 93
93 switch (bench_format) { 94 switch (bench_format) {
@@ -99,7 +100,8 @@ int bench_sched_pipe(int argc, const char **argv,
99 result_usec += diff.tv_usec; 100 result_usec += diff.tv_usec;
100 101
101 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", 102 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
102 diff.tv_sec, diff.tv_usec/1000); 103 diff.tv_sec,
104 (unsigned long) (diff.tv_usec/1000));
103 105
104 printf(" %14lf usecs/op\n", 106 printf(" %14lf usecs/op\n",
105 (double)result_usec / (double)loops); 107 (double)result_usec / (double)loops);
@@ -110,7 +112,8 @@ int bench_sched_pipe(int argc, const char **argv,
110 112
111 case BENCH_FORMAT_SIMPLE: 113 case BENCH_FORMAT_SIMPLE:
112 printf("%lu.%03lu\n", 114 printf("%lu.%03lu\n",
113 diff.tv_sec, diff.tv_usec / 1000); 115 diff.tv_sec,
116 (unsigned long) (diff.tv_usec / 1000));
114 break; 117 break;
115 118
116 default: 119 default:
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 0bf2e8f9af57..21a78d30d53d 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -25,6 +25,7 @@
25#include "util/thread.h" 25#include "util/thread.h"
26#include "util/sort.h" 26#include "util/sort.h"
27#include "util/hist.h" 27#include "util/hist.h"
28#include "util/session.h"
28#include "util/data_map.h" 29#include "util/data_map.h"
29 30
30static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
@@ -462,21 +463,23 @@ static struct perf_file_handler file_handler = {
462 463
463static int __cmd_annotate(void) 464static int __cmd_annotate(void)
464{ 465{
465 struct perf_header *header; 466 struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
466 struct thread *idle; 467 struct thread *idle;
467 int ret; 468 int ret;
468 469
470 if (session == NULL)
471 return -ENOMEM;
472
469 idle = register_idle_thread(); 473 idle = register_idle_thread();
470 register_perf_file_handler(&file_handler); 474 register_perf_file_handler(&file_handler);
471 475
472 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0, 476 ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
473 &event__cwdlen, &event__cwd);
474 if (ret) 477 if (ret)
475 return ret; 478 goto out_delete;
476 479
477 if (dump_trace) { 480 if (dump_trace) {
478 event__print_totals(); 481 event__print_totals();
479 return 0; 482 goto out_delete;
480 } 483 }
481 484
482 if (verbose > 3) 485 if (verbose > 3)
@@ -489,6 +492,8 @@ static int __cmd_annotate(void)
489 output__resort(event__total[0]); 492 output__resort(event__total[0]);
490 493
491 find_annotations(); 494 find_annotations();
495out_delete:
496 perf_session__delete(session);
492 497
493 return ret; 498 return ret;
494} 499}
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index e043eb83092a..46996774e559 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -31,6 +31,9 @@ struct bench_suite {
31 const char *summary; 31 const char *summary;
32 int (*fn)(int, const char **, const char *); 32 int (*fn)(int, const char **, const char *);
33}; 33};
34 \
35/* sentinel: easy for help */
36#define suite_all { "all", "test all suite (pseudo suite)", NULL }
34 37
35static struct bench_suite sched_suites[] = { 38static struct bench_suite sched_suites[] = {
36 { "messaging", 39 { "messaging",
@@ -39,6 +42,7 @@ static struct bench_suite sched_suites[] = {
39 { "pipe", 42 { "pipe",
40 "Flood of communication over pipe() between two processes", 43 "Flood of communication over pipe() between two processes",
41 bench_sched_pipe }, 44 bench_sched_pipe },
45 suite_all,
42 { NULL, 46 { NULL,
43 NULL, 47 NULL,
44 NULL } 48 NULL }
@@ -48,6 +52,7 @@ static struct bench_suite mem_suites[] = {
48 { "memcpy", 52 { "memcpy",
49 "Simple memory copy in various ways", 53 "Simple memory copy in various ways",
50 bench_mem_memcpy }, 54 bench_mem_memcpy },
55 suite_all,
51 { NULL, 56 { NULL,
52 NULL, 57 NULL,
53 NULL } 58 NULL }
@@ -66,6 +71,9 @@ static struct bench_subsys subsystems[] = {
66 { "mem", 71 { "mem",
67 "memory access performance", 72 "memory access performance",
68 mem_suites }, 73 mem_suites },
74 { "all", /* sentinel: easy for help */
75 "test all subsystem (pseudo subsystem)",
76 NULL },
69 { NULL, 77 { NULL,
70 NULL, 78 NULL,
71 NULL } 79 NULL }
@@ -75,11 +83,11 @@ static void dump_suites(int subsys_index)
75{ 83{
76 int i; 84 int i;
77 85
78 printf("List of available suites for %s...\n\n", 86 printf("# List of available suites for %s...\n\n",
79 subsystems[subsys_index].name); 87 subsystems[subsys_index].name);
80 88
81 for (i = 0; subsystems[subsys_index].suites[i].name; i++) 89 for (i = 0; subsystems[subsys_index].suites[i].name; i++)
82 printf("\t%s: %s\n", 90 printf("%14s: %s\n",
83 subsystems[subsys_index].suites[i].name, 91 subsystems[subsys_index].suites[i].name,
84 subsystems[subsys_index].suites[i].summary); 92 subsystems[subsys_index].suites[i].summary);
85 93
@@ -110,10 +118,10 @@ static void print_usage(void)
110 printf("\t%s\n", bench_usage[i]); 118 printf("\t%s\n", bench_usage[i]);
111 printf("\n"); 119 printf("\n");
112 120
113 printf("List of available subsystems...\n\n"); 121 printf("# List of available subsystems...\n\n");
114 122
115 for (i = 0; subsystems[i].name; i++) 123 for (i = 0; subsystems[i].name; i++)
116 printf("\t%s: %s\n", 124 printf("%14s: %s\n",
117 subsystems[i].name, subsystems[i].summary); 125 subsystems[i].name, subsystems[i].summary);
118 printf("\n"); 126 printf("\n");
119} 127}
@@ -131,6 +139,37 @@ static int bench_str2int(char *str)
131 return BENCH_FORMAT_UNKNOWN; 139 return BENCH_FORMAT_UNKNOWN;
132} 140}
133 141
142static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
143{
144 int i;
145 const char *argv[2];
146 struct bench_suite *suites = subsys->suites;
147
148 argv[1] = NULL;
149 /*
150 * TODO:
151 * preparing preset parameters for
152 * embedded, ordinary PC, HPC, etc...
153 * will be helpful
154 */
155 for (i = 0; suites[i].fn; i++) {
156 printf("# Running %s/%s benchmark...\n",
157 subsys->name,
158 suites[i].name);
159
160 argv[1] = suites[i].name;
161 suites[i].fn(1, argv, NULL);
162 printf("\n");
163 }
164}
165
166static void all_subsystem(void)
167{
168 int i;
169 for (i = 0; subsystems[i].suites; i++)
170 all_suite(&subsystems[i]);
171}
172
134int cmd_bench(int argc, const char **argv, const char *prefix __used) 173int cmd_bench(int argc, const char **argv, const char *prefix __used)
135{ 174{
136 int i, j, status = 0; 175 int i, j, status = 0;
@@ -155,6 +194,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
155 goto end; 194 goto end;
156 } 195 }
157 196
197 if (!strcmp(argv[0], "all")) {
198 all_subsystem();
199 goto end;
200 }
201
158 for (i = 0; subsystems[i].name; i++) { 202 for (i = 0; subsystems[i].name; i++) {
159 if (strcmp(subsystems[i].name, argv[0])) 203 if (strcmp(subsystems[i].name, argv[0]))
160 continue; 204 continue;
@@ -165,6 +209,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
165 goto end; 209 goto end;
166 } 210 }
167 211
212 if (!strcmp(argv[1], "all")) {
213 all_suite(&subsystems[i]);
214 goto end;
215 }
216
168 for (j = 0; subsystems[i].suites[j].name; j++) { 217 for (j = 0; subsystems[i].suites[j].name; j++) {
169 if (strcmp(subsystems[i].suites[j].name, argv[1])) 218 if (strcmp(subsystems[i].suites[j].name, argv[1]))
170 continue; 219 continue;
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 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
18static char const *input_name = "perf.data"; 18static char const *input_name = "perf.data";
@@ -55,56 +55,17 @@ static int perf_file_section__process_buildids(struct perf_file_section *self,
55static int __cmd_buildid_list(void) 55static int __cmd_buildid_list(void)
56{ 56{
57 int err = -1; 57 int err = -1;
58 struct perf_header *header; 58 struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
59 struct perf_file_header f_header;
60 struct stat input_stat;
61 int input = open(input_name, O_RDONLY);
62 59
63 if (input < 0) { 60 if (session == NULL)
64 pr_err("failed to open file: %s", input_name); 61 return -1;
65 if (!strcmp(input_name, "perf.data"))
66 pr_err(" (try 'perf record' first)");
67 pr_err("\n");
68 goto out;
69 }
70
71 err = fstat(input, &input_stat);
72 if (err < 0) {
73 perror("failed to stat file");
74 goto out_close;
75 }
76
77 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
78 pr_err("file %s not owned by current user or root\n",
79 input_name);
80 goto out_close;
81 }
82
83 if (!input_stat.st_size) {
84 pr_info("zero-sized file, nothing to do!\n");
85 goto out_close;
86 }
87
88 err = -1;
89 header = perf_header__new();
90 if (header == NULL)
91 goto out_close;
92
93 if (perf_file_header__read(&f_header, header, input) < 0) {
94 pr_warning("incompatible file format");
95 goto out_close;
96 }
97 62
98 err = perf_header__process_sections(header, input, 63 err = perf_header__process_sections(&session->header, session->fd,
99 perf_file_section__process_buildids); 64 perf_file_section__process_buildids);
65 if (err >= 0)
66 dsos__fprintf_buildid(stdout);
100 67
101 if (err < 0) 68 perf_session__delete(session);
102 goto out_close;
103
104 dsos__fprintf_buildid(stdout);
105out_close:
106 close(input);
107out:
108 return err; 69 return err;
109} 70}
110 71
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 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
21static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
22 23
23static struct perf_header *header;
24static u64 sample_type; 24static u64 sample_type;
25 25
26static int alloc_flag; 26static int alloc_flag;
@@ -367,11 +367,18 @@ static struct perf_file_handler file_handler = {
367 367
368static int read_events(void) 368static 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
377static double fragmentation(unsigned long n_req, unsigned long n_alloc) 384static 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
63static int file_new = 1; 64static int file_new = 1;
64 65
65struct perf_header *header = NULL; 66static struct perf_session *session;
66 67
67struct mmap_data { 68struct mmap_data {
68 int counter; 69 int counter;
@@ -216,12 +217,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
216{ 217{
217 struct perf_header_attr *h_attr; 218 struct perf_header_attr *h_attr;
218 219
219 if (nr < header->attrs) { 220 if (nr < session->header.attrs) {
220 h_attr = header->attr[nr]; 221 h_attr = session->header.attr[nr];
221 } else { 222 } else {
222 h_attr = perf_header_attr__new(a); 223 h_attr = perf_header_attr__new(a);
223 if (h_attr != NULL) 224 if (h_attr != NULL)
224 if (perf_header__add_attr(header, h_attr) < 0) { 225 if (perf_header__add_attr(&session->header, h_attr) < 0) {
225 perf_header_attr__delete(h_attr); 226 perf_header_attr__delete(h_attr);
226 h_attr = NULL; 227 h_attr = NULL;
227 } 228 }
@@ -395,9 +396,9 @@ static void open_counters(int cpu, pid_t pid)
395 396
396static void atexit_header(void) 397static void atexit_header(void)
397{ 398{
398 header->data_size += bytes_written; 399 session->header.data_size += bytes_written;
399 400
400 perf_header__write(header, output, true); 401 perf_header__write(&session->header, output, true);
401} 402}
402 403
403static int __cmd_record(int argc, const char **argv) 404static int __cmd_record(int argc, const char **argv)
@@ -440,24 +441,24 @@ static int __cmd_record(int argc, const char **argv)
440 exit(-1); 441 exit(-1);
441 } 442 }
442 443
443 header = perf_header__new(); 444 session = perf_session__new(output_name, O_WRONLY, force);
444 if (header == NULL) { 445 if (session == NULL) {
445 pr_err("Not enough memory for reading perf file header\n"); 446 pr_err("Not enough memory for reading perf file header\n");
446 return -1; 447 return -1;
447 } 448 }
448 449
449 if (!file_new) { 450 if (!file_new) {
450 err = perf_header__read(header, output); 451 err = perf_header__read(&session->header, output);
451 if (err < 0) 452 if (err < 0)
452 return err; 453 return err;
453 } 454 }
454 455
455 if (raw_samples) { 456 if (raw_samples) {
456 perf_header__set_feat(header, HEADER_TRACE_INFO); 457 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
457 } else { 458 } else {
458 for (i = 0; i < nr_counters; i++) { 459 for (i = 0; i < nr_counters; i++) {
459 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 460 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
460 perf_header__set_feat(header, HEADER_TRACE_INFO); 461 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
461 break; 462 break;
462 } 463 }
463 } 464 }
@@ -481,7 +482,7 @@ static int __cmd_record(int argc, const char **argv)
481 } 482 }
482 483
483 if (file_new) { 484 if (file_new) {
484 err = perf_header__write(header, output, false); 485 err = perf_header__write(&session->header, output, false);
485 if (err < 0) 486 if (err < 0)
486 return err; 487 return err;
487 } 488 }
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 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
53static char callchain_default_opt[] = "fractal,0.5"; 54static char callchain_default_opt[] = "fractal,0.5";
54 55
55static struct perf_header *header; 56static struct perf_session *session;
56 57
57static u64 sample_type; 58static u64 sample_type;
58 59
@@ -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 804out_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
22static char const *input_name = "perf.data"; 23static char const *input_name = "perf.data";
23 24
24static struct perf_header *header;
25static u64 sample_type; 25static u64 sample_type;
26 26
27static char default_sort_order[] = "avg, max, switch, runtime"; 27static char default_sort_order[] = "avg, max, switch, runtime";
@@ -1663,11 +1663,18 @@ static struct perf_file_handler file_handler = {
1663 1663
1664static int read_events(void) 1664static 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
1673static void print_bad_events(void) 1680static 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
1060static int __cmd_timechart(void) 1060static 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 1084out_delete:
1083 return EXIT_SUCCESS; 1085 perf_session__delete(session);
1086 return ret;
1084} 1087}
1085 1088
1086static const char * const timechart_usage[] = { 1089static const char * const timechart_usage[] = {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 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
11static char const *script_name; 12static char const *script_name;
12static char const *generate_script_lang; 13static char const *generate_script_lang;
@@ -61,7 +62,7 @@ static int cleanup_scripting(void)
61 62
62static char const *input_name = "perf.data"; 63static char const *input_name = "perf.data";
63 64
64static struct perf_header *header; 65static struct perf_session *session;
65static u64 sample_type; 66static u64 sample_type;
66 67
67static int process_sample_event(event_t *event) 68static int process_sample_event(event_t *event)
@@ -126,11 +127,18 @@ static struct perf_file_handler file_handler = {
126 127
127static int __cmd_trace(void) 128static 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
136struct script_spec { 144struct 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
132int mmap_dispatch_perf_file(struct perf_header **pheader, 132int perf_session__process_events(struct perf_session *self,
133 const char *input_name, 133 int full_paths, int *cwdlen, char **cwd)
134 int force,
135 int full_paths,
136 int *cwdlen,
137 char **cwd)
138{ 134{
139 int err; 135 int err;
140 struct perf_header *header;
141 unsigned long head, shift; 136 unsigned long head, shift;
142 unsigned long offset = 0; 137 unsigned long offset = 0;
143 struct stat input_stat;
144 size_t page_size; 138 size_t page_size;
145 u64 sample_type; 139 u64 sample_type;
146 event_t *event; 140 event_t *event;
147 uint32_t size; 141 uint32_t size;
148 int input;
149 char *buf; 142 char *buf;
150 143
151 if (curr_handler == NULL) { 144 if (curr_handler == NULL) {
@@ -155,56 +148,19 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
155 148
156 page_size = getpagesize(); 149 page_size = getpagesize();
157 150
158 input = open(input_name, O_RDONLY); 151 head = self->header.data_offset;
159 if (input < 0) { 152 sample_type = perf_header__sample_type(&self->header);
160 pr_err("Failed to open file: %s", input_name);
161 if (!strcmp(input_name, "perf.data"))
162 pr_err(" (try 'perf record' first)");
163 pr_err("\n");
164 return -errno;
165 }
166
167 if (fstat(input, &input_stat) < 0) {
168 pr_err("failed to stat file");
169 err = -errno;
170 goto out_close;
171 }
172
173 err = -EACCES;
174 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
175 pr_err("file: %s not owned by current user or root\n",
176 input_name);
177 goto out_close;
178 }
179
180 if (input_stat.st_size == 0) {
181 pr_info("zero-sized file, nothing to do!\n");
182 goto done;
183 }
184
185 err = -ENOMEM;
186 header = perf_header__new();
187 if (header == NULL)
188 goto out_close;
189
190 err = perf_header__read(header, input);
191 if (err < 0)
192 goto out_delete;
193 *pheader = header;
194 head = header->data_offset;
195
196 sample_type = perf_header__sample_type(header);
197 153
198 err = -EINVAL; 154 err = -EINVAL;
199 if (curr_handler->sample_type_check && 155 if (curr_handler->sample_type_check &&
200 curr_handler->sample_type_check(sample_type) < 0) 156 curr_handler->sample_type_check(sample_type) < 0)
201 goto out_delete; 157 goto out_err;
202 158
203 if (!full_paths) { 159 if (!full_paths) {
204 if (getcwd(__cwd, sizeof(__cwd)) == NULL) { 160 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
205 pr_err("failed to get the current directory\n"); 161 pr_err("failed to get the current directory\n");
206 err = -errno; 162 err = -errno;
207 goto out_delete; 163 goto out_err;
208 } 164 }
209 *cwd = __cwd; 165 *cwd = __cwd;
210 *cwdlen = strlen(*cwd); 166 *cwdlen = strlen(*cwd);
@@ -219,11 +175,11 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
219 175
220remap: 176remap:
221 buf = mmap(NULL, page_size * mmap_window, PROT_READ, 177 buf = mmap(NULL, page_size * mmap_window, PROT_READ,
222 MAP_SHARED, input, offset); 178 MAP_SHARED, self->fd, offset);
223 if (buf == MAP_FAILED) { 179 if (buf == MAP_FAILED) {
224 pr_err("failed to mmap file\n"); 180 pr_err("failed to mmap file\n");
225 err = -errno; 181 err = -errno;
226 goto out_delete; 182 goto out_err;
227 } 183 }
228 184
229more: 185more:
@@ -273,19 +229,14 @@ more:
273 229
274 head += size; 230 head += size;
275 231
276 if (offset + head >= header->data_offset + header->data_size) 232 if (offset + head >= self->header.data_offset + self->header.data_size)
277 goto done; 233 goto done;
278 234
279 if (offset + head < (unsigned long)input_stat.st_size) 235 if (offset + head < self->size)
280 goto more; 236 goto more;
281 237
282done: 238done:
283 err = 0; 239 err = 0;
284out_close: 240out_err:
285 close(input);
286
287 return err; 241 return err;
288out_delete:
289 perf_header__delete(header);
290 goto out_close;
291} 242}
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
index 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
7typedef int (*event_type_handler_t)(event_t *); 8typedef int (*event_type_handler_t)(event_t *);
8 9
@@ -21,12 +22,8 @@ struct perf_file_handler {
21}; 22};
22 23
23void register_perf_file_handler(struct perf_file_handler *handler); 24void register_perf_file_handler(struct perf_file_handler *handler);
24int mmap_dispatch_perf_file(struct perf_header **pheader, 25int perf_session__process_events(struct perf_session *self,
25 const char *input_name, 26 int full_paths, int *cwdlen, char **cwd);
26 int force,
27 int full_paths,
28 int *cwdlen,
29 char **cwd);
30int perf_header__read_build_ids(int input, u64 offset, u64 file_size); 27int 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 }
272try_again: 273try_again:
273 al->map = thread__find_map(thread, type, al->addr); 274 al->map = map_groups__find(mg, type, al->addr);
274 if (al->map == NULL) { 275 if (al->map == NULL) {
275 /* 276 /*
276 * If this is outside of all known maps, and is a negative 277 * If this is outside of all known maps, and is a negative
@@ -281,8 +282,8 @@ try_again:
281 * "[vdso]" dso, but for now lets use the old trick of looking 282 * "[vdso]" dso, but for now lets use the old trick of looking
282 * in the whole kernel symbol list. 283 * in the whole kernel symbol list.
283 */ 284 */
284 if ((long long)al->addr < 0 && thread != kthread) { 285 if ((long long)al->addr < 0 && mg != kmaps) {
285 thread = kthread; 286 mg = kmaps;
286 goto try_again; 287 goto try_again;
287 } 288 }
288 al->sym = NULL; 289 al->sym = NULL;
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
104enum map_type { 104enum 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
110struct map { 111struct 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);
150size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
151struct symbol *map__find_symbol(struct map *self, u64 addr, 152struct symbol *map__find_symbol(struct map *self, u64 addr,
152 symbol_filter_t filter); 153 symbol_filter_t filter);
154struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
155 symbol_filter_t filter);
153void map__fixup_start(struct map *self); 156void map__fixup_start(struct map *self);
154void map__fixup_end(struct map *self); 157void 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/* 61int perf_header__init(struct perf_header *self)
62 * Create new perf.data header:
63 */
64struct perf_header *perf_header__new(void)
65{ 62{
66 struct perf_header *self = zalloc(sizeof(*self)); 63 self->size = 1;
67 64 self->attr = malloc(sizeof(void *));
68 if (self != NULL) { 65 return self->attr == NULL ? -ENOMEM : 0;
69 self->size = 1;
70 self->attr = malloc(sizeof(void *));
71
72 if (self->attr == NULL) {
73 free(self);
74 self = NULL;
75 }
76 }
77
78 return self;
79} 66}
80 67
81void perf_header__delete(struct perf_header *self) 68void perf_header__exit(struct perf_header *self)
82{ 69{
83 int i; 70 int i;
84
85 for (i = 0; i < self->attrs; ++i) 71 for (i = 0; i < self->attrs; ++i)
86 perf_header_attr__delete(self->attr[i]); 72 perf_header_attr__delete(self->attr[i]);
87
88 free(self->attr); 73 free(self->attr);
89 free(self);
90} 74}
91 75
92int perf_header__add_attr(struct perf_header *self, 76int perf_header__add_attr(struct perf_header *self,
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d1dbe2b79c42..d118d05d3abe 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -55,8 +55,8 @@ struct perf_header {
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
56}; 56};
57 57
58struct perf_header *perf_header__new(void); 58int perf_header__init(struct perf_header *self);
59void perf_header__delete(struct perf_header *self); 59void perf_header__exit(struct perf_header *self);
60 60
61int perf_header__read(struct perf_header *self, int fd); 61int perf_header__read(struct perf_header *self, int fd);
62int perf_header__write(struct perf_header *self, int fd, bool at_exit); 62int perf_header__write(struct perf_header *self, int fd, bool at_exit);
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 69f94fe9db20..76bdca640a9b 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -104,43 +104,64 @@ void map__fixup_end(struct map *self)
104 104
105#define DSO__DELETED "(deleted)" 105#define DSO__DELETED "(deleted)"
106 106
107struct symbol *map__find_symbol(struct map *self, u64 addr, 107static int map__load(struct map *self, symbol_filter_t filter)
108 symbol_filter_t filter)
109{ 108{
110 if (!dso__loaded(self->dso, self->type)) { 109 const char *name = self->dso->long_name;
111 int nr = dso__load(self->dso, self, filter); 110 int nr = dso__load(self->dso, self, filter);
112 111
113 if (nr < 0) { 112 if (nr < 0) {
114 if (self->dso->has_build_id) { 113 if (self->dso->has_build_id) {
115 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 114 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
116 115
117 build_id__sprintf(self->dso->build_id, 116 build_id__sprintf(self->dso->build_id,
118 sizeof(self->dso->build_id), 117 sizeof(self->dso->build_id),
119 sbuild_id); 118 sbuild_id);
120 pr_warning("%s with build id %s not found", 119 pr_warning("%s with build id %s not found",
121 self->dso->long_name, sbuild_id); 120 name, sbuild_id);
122 } else 121 } else
123 pr_warning("Failed to open %s", 122 pr_warning("Failed to open %s", name);
124 self->dso->long_name); 123
125 pr_warning(", continuing without symbols\n"); 124 pr_warning(", continuing without symbols\n");
126 return NULL; 125 return -1;
127 } else if (nr == 0) { 126 } else if (nr == 0) {
128 const char *name = self->dso->long_name; 127 const size_t len = strlen(name);
129 const size_t len = strlen(name); 128 const size_t real_len = len - sizeof(DSO__DELETED);
130 const size_t real_len = len - sizeof(DSO__DELETED); 129
131 130 if (len > sizeof(DSO__DELETED) &&
132 if (len > sizeof(DSO__DELETED) && 131 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
133 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 132 pr_warning("%.*s was updated, restart the long "
134 pr_warning("%.*s was updated, restart the long running apps that use it!\n", 133 "running apps that use it!\n",
135 (int)real_len, name); 134 (int)real_len, name);
136 } else { 135 } else {
137 pr_warning("no symbols found in %s, maybe install a debug package?\n", name); 136 pr_warning("no symbols found in %s, maybe install "
138 } 137 "a debug package?\n", name);
139 return NULL;
140 } 138 }
139
140 return -1;
141 } 141 }
142 142
143 return self->dso->find_symbol(self->dso, self->type, addr); 143 return 0;
144}
145
146struct symbol *map__find_symbol(struct map *self, u64 addr,
147 symbol_filter_t filter)
148{
149 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
150 return NULL;
151
152 return dso__find_symbol(self->dso, self->type, addr);
153}
154
155struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
156 symbol_filter_t filter)
157{
158 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
159 return NULL;
160
161 if (!dso__sorted_by_name(self->dso, self->type))
162 dso__sort_by_name(self->dso, self->type);
163
164 return dso__find_symbol_by_name(self->dso, self->type, name);
144} 165}
145 166
146struct map *map__clone(struct map *self) 167struct map *map__clone(struct map *self)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
new file mode 100644
index 000000000000..707ce1cb1621
--- /dev/null
+++ b/tools/perf/util/session.c
@@ -0,0 +1,80 @@
1#include <linux/kernel.h>
2
3#include <unistd.h>
4#include <sys/types.h>
5
6#include "session.h"
7#include "util.h"
8
9static int perf_session__open(struct perf_session *self, bool force)
10{
11 struct stat input_stat;
12
13 self->fd = open(self->filename, O_RDONLY);
14 if (self->fd < 0) {
15 pr_err("failed to open file: %s", self->filename);
16 if (!strcmp(self->filename, "perf.data"))
17 pr_err(" (try 'perf record' first)");
18 pr_err("\n");
19 return -errno;
20 }
21
22 if (fstat(self->fd, &input_stat) < 0)
23 goto out_close;
24
25 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
26 pr_err("file %s not owned by current user or root\n",
27 self->filename);
28 goto out_close;
29 }
30
31 if (!input_stat.st_size) {
32 pr_info("zero-sized file (%s), nothing to do!\n",
33 self->filename);
34 goto out_close;
35 }
36
37 if (perf_header__read(&self->header, self->fd) < 0) {
38 pr_err("incompatible file format");
39 goto out_close;
40 }
41
42 self->size = input_stat.st_size;
43 return 0;
44
45out_close:
46 close(self->fd);
47 self->fd = -1;
48 return -1;
49}
50
51struct perf_session *perf_session__new(const char *filename, int mode, bool force)
52{
53 size_t len = strlen(filename) + 1;
54 struct perf_session *self = zalloc(sizeof(*self) + len);
55
56 if (self == NULL)
57 goto out;
58
59 if (perf_header__init(&self->header) < 0)
60 goto out_delete;
61
62 memcpy(self->filename, filename, len);
63
64 if (mode == O_RDONLY && perf_session__open(self, force) < 0) {
65 perf_session__delete(self);
66 self = NULL;
67 }
68out:
69 return self;
70out_delete:
71 free(self);
72 return NULL;
73}
74
75void perf_session__delete(struct perf_session *self)
76{
77 perf_header__exit(&self->header);
78 close(self->fd);
79 free(self);
80}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644
index 000000000000..f3699c8c8ed4
--- /dev/null
+++ b/tools/perf/util/session.h
@@ -0,0 +1,16 @@
1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H
3
4#include "header.h"
5
6struct perf_session {
7 struct perf_header header;
8 unsigned long size;
9 int fd;
10 char filename[0];
11};
12
13struct perf_session *perf_session__new(const char *filename, int mode, bool force);
14void perf_session__delete(struct perf_session *self);
15
16#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 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
31static void dsos__add(struct list_head *head, struct dso *dso); 31static void dsos__add(struct list_head *head, struct dso *dso);
32static struct map *thread__find_map_by_name(struct thread *self, char *name);
33static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 32static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
34struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
35static int dso__load_kernel_sym(struct dso *self, struct map *map, 33static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct thread *thread, symbol_filter_t filter); 34 struct map_groups *mg, symbol_filter_t filter);
37unsigned int symbol__priv_size; 35unsigned int symbol__priv_size;
38static int vmlinux_path__nr_entries; 36static int vmlinux_path__nr_entries;
39static char **vmlinux_path; 37static char **vmlinux_path;
@@ -43,19 +41,41 @@ static struct symbol_conf symbol_conf__defaults = {
43 .try_vmlinux_path = true, 41 .try_vmlinux_path = true,
44}; 42};
45 43
46static struct thread kthread_mem; 44static struct map_groups kmaps_mem;
47struct thread *kthread = &kthread_mem; 45struct map_groups *kmaps = &kmaps_mem;
48 46
49bool dso__loaded(const struct dso *self, enum map_type type) 47bool dso__loaded(const struct dso *self, enum map_type type)
50{ 48{
51 return self->loaded & (1 << type); 49 return self->loaded & (1 << type);
52} 50}
53 51
52bool dso__sorted_by_name(const struct dso *self, enum map_type type)
53{
54 return self->sorted_by_name & (1 << type);
55}
56
54static void dso__set_loaded(struct dso *self, enum map_type type) 57static void dso__set_loaded(struct dso *self, enum map_type type)
55{ 58{
56 self->loaded |= (1 << type); 59 self->loaded |= (1 << type);
57} 60}
58 61
62static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
63{
64 self->sorted_by_name |= (1 << type);
65}
66
67static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
68{
69 switch (map_type) {
70 case MAP__FUNCTION:
71 return symbol_type == 'T' || symbol_type == 'W';
72 case MAP__VARIABLE:
73 return symbol_type == 'D' || symbol_type == 'd';
74 default:
75 return false;
76 }
77}
78
59static void symbols__fixup_end(struct rb_root *self) 79static void symbols__fixup_end(struct rb_root *self)
60{ 80{
61 struct rb_node *nd, *prevnd = rb_first(self); 81 struct rb_node *nd, *prevnd = rb_first(self);
@@ -79,7 +99,7 @@ static void symbols__fixup_end(struct rb_root *self)
79 curr->end = roundup(curr->start, 4096); 99 curr->end = roundup(curr->start, 4096);
80} 100}
81 101
82static void __thread__fixup_maps_end(struct thread *self, enum map_type type) 102static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
83{ 103{
84 struct map *prev, *curr; 104 struct map *prev, *curr;
85 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 105 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
@@ -102,11 +122,11 @@ static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
102 curr->end = ~0UL; 122 curr->end = ~0UL;
103} 123}
104 124
105static void thread__fixup_maps_end(struct thread *self) 125static void map_groups__fixup_end(struct map_groups *self)
106{ 126{
107 int i; 127 int i;
108 for (i = 0; i < MAP__NR_TYPES; ++i) 128 for (i = 0; i < MAP__NR_TYPES; ++i)
109 __thread__fixup_maps_end(self, i); 129 __map_groups__fixup_end(self, i);
110} 130}
111 131
112static struct symbol *symbol__new(u64 start, u64 len, const char *name) 132static struct symbol *symbol__new(u64 start, u64 len, const char *name)
@@ -164,11 +184,11 @@ struct dso *dso__new(const char *name)
164 dso__set_long_name(self, self->name); 184 dso__set_long_name(self, self->name);
165 self->short_name = self->name; 185 self->short_name = self->name;
166 for (i = 0; i < MAP__NR_TYPES; ++i) 186 for (i = 0; i < MAP__NR_TYPES; ++i)
167 self->symbols[i] = RB_ROOT; 187 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
168 self->find_symbol = dso__find_symbol;
169 self->slen_calculated = 0; 188 self->slen_calculated = 0;
170 self->origin = DSO__ORIG_NOT_FOUND; 189 self->origin = DSO__ORIG_NOT_FOUND;
171 self->loaded = 0; 190 self->loaded = 0;
191 self->sorted_by_name = 0;
172 self->has_build_id = 0; 192 self->has_build_id = 0;
173 } 193 }
174 194
@@ -246,11 +266,85 @@ static struct symbol *symbols__find(struct rb_root *self, u64 ip)
246 return NULL; 266 return NULL;
247} 267}
248 268
249struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) 269struct symbol_name_rb_node {
270 struct rb_node rb_node;
271 struct symbol sym;
272};
273
274static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
275{
276 struct rb_node **p = &self->rb_node;
277 struct rb_node *parent = NULL;
278 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
279
280 while (*p != NULL) {
281 parent = *p;
282 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
283 if (strcmp(sym->name, s->sym.name) < 0)
284 p = &(*p)->rb_left;
285 else
286 p = &(*p)->rb_right;
287 }
288 rb_link_node(&symn->rb_node, parent, p);
289 rb_insert_color(&symn->rb_node, self);
290}
291
292static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
293{
294 struct rb_node *nd;
295
296 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
297 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
298 symbols__insert_by_name(self, pos);
299 }
300}
301
302static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
303{
304 struct rb_node *n;
305
306 if (self == NULL)
307 return NULL;
308
309 n = self->rb_node;
310
311 while (n) {
312 struct symbol_name_rb_node *s;
313 int cmp;
314
315 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
316 cmp = strcmp(name, s->sym.name);
317
318 if (cmp < 0)
319 n = n->rb_left;
320 else if (cmp > 0)
321 n = n->rb_right;
322 else
323 return &s->sym;
324 }
325
326 return NULL;
327}
328
329struct symbol *dso__find_symbol(struct dso *self,
330 enum map_type type, u64 addr)
250{ 331{
251 return symbols__find(&self->symbols[type], addr); 332 return symbols__find(&self->symbols[type], addr);
252} 333}
253 334
335struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
336 const char *name)
337{
338 return symbols__find_by_name(&self->symbol_names[type], name);
339}
340
341void dso__sort_by_name(struct dso *self, enum map_type type)
342{
343 dso__set_sorted_by_name(self, type);
344 return symbols__sort_by_name(&self->symbol_names[type],
345 &self->symbols[type]);
346}
347
254int build_id__sprintf(u8 *self, int len, char *bf) 348int build_id__sprintf(u8 *self, int len, char *bf)
255{ 349{
256 char *bid = bf; 350 char *bid = bf;
@@ -327,10 +421,7 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
327 continue; 421 continue;
328 422
329 symbol_type = toupper(line[len]); 423 symbol_type = toupper(line[len]);
330 /* 424 if (!symbol_type__is_a(symbol_type, map->type))
331 * We're interested only in code ('T'ext)
332 */
333 if (symbol_type != 'T' && symbol_type != 'W')
334 continue; 425 continue;
335 426
336 symbol_name = line + len + 2; 427 symbol_name = line + len + 2;
@@ -364,8 +455,8 @@ out_failure:
364 * kernel range is broken in several maps, named [kernel].N, as we don't have 455 * kernel range is broken in several maps, named [kernel].N, as we don't have
365 * the original ELF section names vmlinux have. 456 * the original ELF section names vmlinux have.
366 */ 457 */
367static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread, 458static int dso__split_kallsyms(struct dso *self, struct map *map,
368 symbol_filter_t filter) 459 struct map_groups *mg, symbol_filter_t filter)
369{ 460{
370 struct map *curr_map = map; 461 struct map *curr_map = map;
371 struct symbol *pos; 462 struct symbol *pos;
@@ -382,13 +473,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
382 473
383 module = strchr(pos->name, '\t'); 474 module = strchr(pos->name, '\t');
384 if (module) { 475 if (module) {
385 if (!thread->use_modules) 476 if (!mg->use_modules)
386 goto discard_symbol; 477 goto discard_symbol;
387 478
388 *module++ = '\0'; 479 *module++ = '\0';
389 480
390 if (strcmp(self->name, module)) { 481 if (strcmp(self->name, module)) {
391 curr_map = thread__find_map_by_name(thread, module); 482 curr_map = map_groups__find_by_name(mg, map->type, module);
392 if (curr_map == NULL) { 483 if (curr_map == NULL) {
393 pr_debug("/proc/{kallsyms,modules} " 484 pr_debug("/proc/{kallsyms,modules} "
394 "inconsistency!\n"); 485 "inconsistency!\n");
@@ -419,7 +510,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
419 } 510 }
420 511
421 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 512 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
422 __thread__insert_map(thread, curr_map); 513 map_groups__insert(mg, curr_map);
423 ++kernel_range; 514 ++kernel_range;
424 } 515 }
425 516
@@ -440,7 +531,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
440 531
441 532
442static int dso__load_kallsyms(struct dso *self, struct map *map, 533static int dso__load_kallsyms(struct dso *self, struct map *map,
443 struct thread *thread, symbol_filter_t filter) 534 struct map_groups *mg, symbol_filter_t filter)
444{ 535{
445 if (dso__load_all_kallsyms(self, map) < 0) 536 if (dso__load_all_kallsyms(self, map) < 0)
446 return -1; 537 return -1;
@@ -448,13 +539,13 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
448 symbols__fixup_end(&self->symbols[map->type]); 539 symbols__fixup_end(&self->symbols[map->type]);
449 self->origin = DSO__ORIG_KERNEL; 540 self->origin = DSO__ORIG_KERNEL;
450 541
451 return dso__split_kallsyms(self, map, thread, filter); 542 return dso__split_kallsyms(self, map, mg, filter);
452} 543}
453 544
454size_t kernel_maps__fprintf(FILE *fp) 545size_t kernel_maps__fprintf(FILE *fp)
455{ 546{
456 size_t printed = fprintf(fp, "Kernel maps:\n"); 547 size_t printed = fprintf(fp, "Kernel maps:\n");
457 printed += thread__fprintf_maps(kthread, fp); 548 printed += map_groups__fprintf_maps(kmaps, fp);
458 return printed + fprintf(fp, "END kernel maps\n"); 549 return printed + fprintf(fp, "END kernel maps\n");
459} 550}
460 551
@@ -544,6 +635,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
544 sym->st_shndx != SHN_UNDEF; 635 sym->st_shndx != SHN_UNDEF;
545} 636}
546 637
638static inline bool elf_sym__is_object(const GElf_Sym *sym)
639{
640 return elf_sym__type(sym) == STT_OBJECT &&
641 sym->st_name != 0 &&
642 sym->st_shndx != SHN_UNDEF;
643}
644
547static inline int elf_sym__is_label(const GElf_Sym *sym) 645static inline int elf_sym__is_label(const GElf_Sym *sym)
548{ 646{
549 return elf_sym__type(sym) == STT_NOTYPE && 647 return elf_sym__type(sym) == STT_NOTYPE &&
@@ -564,6 +662,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
564 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 662 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
565} 663}
566 664
665static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
666 const Elf_Data *secstrs)
667{
668 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
669}
670
567static inline const char *elf_sym__name(const GElf_Sym *sym, 671static inline const char *elf_sym__name(const GElf_Sym *sym,
568 const Elf_Data *symstrs) 672 const Elf_Data *symstrs)
569{ 673{
@@ -744,8 +848,32 @@ out:
744 return 0; 848 return 0;
745} 849}
746 850
851static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
852{
853 switch (type) {
854 case MAP__FUNCTION:
855 return elf_sym__is_function(self);
856 case MAP__VARIABLE:
857 return elf_sym__is_object(self);
858 default:
859 return false;
860 }
861}
862
863static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
864{
865 switch (type) {
866 case MAP__FUNCTION:
867 return elf_sec__is_text(self, secstrs);
868 case MAP__VARIABLE:
869 return elf_sec__is_data(self, secstrs);
870 default:
871 return false;
872 }
873}
874
747static int dso__load_sym(struct dso *self, struct map *map, 875static int dso__load_sym(struct dso *self, struct map *map,
748 struct thread *thread, const char *name, int fd, 876 struct map_groups *mg, const char *name, int fd,
749 symbol_filter_t filter, int kernel, int kmodule) 877 symbol_filter_t filter, int kernel, int kmodule)
750{ 878{
751 struct map *curr_map = map; 879 struct map *curr_map = map;
@@ -818,7 +946,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
818 int is_label = elf_sym__is_label(&sym); 946 int is_label = elf_sym__is_label(&sym);
819 const char *section_name; 947 const char *section_name;
820 948
821 if (!is_label && !elf_sym__is_function(&sym)) 949 if (!is_label && !elf_sym__is_a(&sym, map->type))
822 continue; 950 continue;
823 951
824 sec = elf_getscn(elf, sym.st_shndx); 952 sec = elf_getscn(elf, sym.st_shndx);
@@ -827,7 +955,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
827 955
828 gelf_getshdr(sec, &shdr); 956 gelf_getshdr(sec, &shdr);
829 957
830 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 958 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
831 continue; 959 continue;
832 960
833 elf_name = elf_sym__name(&sym, symstrs); 961 elf_name = elf_sym__name(&sym, symstrs);
@@ -849,7 +977,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
849 snprintf(dso_name, sizeof(dso_name), 977 snprintf(dso_name, sizeof(dso_name),
850 "%s%s", self->short_name, section_name); 978 "%s%s", self->short_name, section_name);
851 979
852 curr_map = thread__find_map_by_name(thread, dso_name); 980 curr_map = map_groups__find_by_name(mg, map->type, dso_name);
853 if (curr_map == NULL) { 981 if (curr_map == NULL) {
854 u64 start = sym.st_value; 982 u64 start = sym.st_value;
855 983
@@ -868,7 +996,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
868 curr_map->map_ip = identity__map_ip; 996 curr_map->map_ip = identity__map_ip;
869 curr_map->unmap_ip = identity__map_ip; 997 curr_map->unmap_ip = identity__map_ip;
870 curr_dso->origin = DSO__ORIG_KERNEL; 998 curr_dso->origin = DSO__ORIG_KERNEL;
871 __thread__insert_map(kthread, curr_map); 999 map_groups__insert(kmaps, curr_map);
872 dsos__add(&dsos__kernel, curr_dso); 1000 dsos__add(&dsos__kernel, curr_dso);
873 } else 1001 } else
874 curr_dso = curr_map->dso; 1002 curr_dso = curr_map->dso;
@@ -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
1183static struct map *thread__find_map_by_name(struct thread *self, char *name) 1311struct map *map_groups__find_by_name(struct map_groups *self,
1312 enum map_type type, const char *name)
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
1284static int thread__create_module_maps(struct thread *self) 1413static 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
1356static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread, 1485static int dso__load_vmlinux(struct dso *self, struct map *map,
1486 struct map_groups *mg,
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
1396static int dso__load_kernel_sym(struct dso *self, struct map *map, 1526static 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);
1427do_kallsyms: 1557do_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
1511static int thread__create_kernel_map(struct thread *self, const char *vmlinux) 1641static 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
1542out_delete_kernel_map:
1543 map__delete(kmap);
1544out_delete_kernel_dso: 1665out_delete_kernel_dso:
1545 dso__delete(kernel); 1666 dso__delete(kernel);
1546 return -1; 1667 return NULL;
1668}
1669
1670static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux)
1671{
1672 struct map *functions, *variables;
1673 struct dso *kernel = dsos__create_kernel(vmlinux);
1674
1675 if (kernel == NULL)
1676 return -1;
1677
1678 functions = map__new2(0, kernel, MAP__FUNCTION);
1679 if (functions == NULL)
1680 return -1;
1681
1682 variables = map__new2(0, kernel, MAP__VARIABLE);
1683 if (variables == NULL) {
1684 map__delete(functions);
1685 return -1;
1686 }
1687
1688 functions->map_ip = functions->unmap_ip =
1689 variables->map_ip = variables->unmap_ip = identity__map_ip;
1690 map_groups__insert(self, functions);
1691 map_groups__insert(self, variables);
1692
1693 return 0;
1547} 1694}
1548 1695
1549static void vmlinux_path__exit(void) 1696static 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 {
52struct symbol_conf { 52struct symbol_conf {
53 unsigned short priv_size; 53 unsigned short priv_size;
54 bool try_vmlinux_path, 54 bool try_vmlinux_path,
55 use_modules; 55 use_modules,
56 sort_by_name;
56 const char *vmlinux_name; 57 const char *vmlinux_name;
57}; 58};
58 59
@@ -74,13 +75,13 @@ struct addr_location {
74struct dso { 75struct dso {
75 struct list_head node; 76 struct list_head node;
76 struct rb_root symbols[MAP__NR_TYPES]; 77 struct rb_root symbols[MAP__NR_TYPES];
77 struct symbol *(*find_symbol)(struct dso *self, 78 struct rb_root symbol_names[MAP__NR_TYPES];
78 enum map_type type, u64 addr);
79 u8 adjust_symbols:1; 79 u8 adjust_symbols:1;
80 u8 slen_calculated:1; 80 u8 slen_calculated:1;
81 u8 has_build_id:1; 81 u8 has_build_id:1;
82 u8 kernel:1; 82 u8 kernel:1;
83 unsigned char origin; 83 unsigned char origin;
84 u8 sorted_by_name;
84 u8 loaded; 85 u8 loaded;
85 u8 build_id[BUILD_ID_SIZE]; 86 u8 build_id[BUILD_ID_SIZE];
86 u16 long_name_len; 87 u16 long_name_len;
@@ -93,6 +94,9 @@ struct dso *dso__new(const char *name);
93void dso__delete(struct dso *self); 94void dso__delete(struct dso *self);
94 95
95bool dso__loaded(const struct dso *self, enum map_type type); 96bool dso__loaded(const struct dso *self, enum map_type type);
97bool dso__sorted_by_name(const struct dso *self, enum map_type type);
98
99void dso__sort_by_name(struct dso *self, enum map_type type);
96 100
97struct dso *dsos__findnew(const char *name); 101struct dso *dsos__findnew(const char *name);
98int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 102int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
@@ -103,6 +107,9 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
103size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 107size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
104char dso__symtab_origin(const struct dso *self); 108char dso__symtab_origin(const struct dso *self);
105void dso__set_build_id(struct dso *self, void *build_id); 109void dso__set_build_id(struct dso *self, void *build_id);
110struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
111struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
112 const char *name);
106 113
107int filename__read_build_id(const char *filename, void *bf, size_t size); 114int filename__read_build_id(const char *filename, void *bf, size_t size);
108int sysfs__read_build_id(const char *filename, void *bf, size_t size); 115int sysfs__read_build_id(const char *filename, void *bf, size_t size);
@@ -113,8 +120,8 @@ size_t kernel_maps__fprintf(FILE *fp);
113 120
114int symbol__init(struct symbol_conf *conf); 121int symbol__init(struct symbol_conf *conf);
115 122
116struct thread; 123struct map_groups;
117struct thread *kthread; 124struct map_groups *kmaps;
118extern struct list_head dsos__user, dsos__kernel; 125extern struct list_head dsos__user, dsos__kernel;
119extern struct dso *vdso; 126extern struct dso *vdso;
120#endif /* __PERF_SYMBOL */ 127#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 603f5610861b..b68a00ea4121 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -9,11 +9,9 @@
9static struct rb_root threads; 9static struct rb_root threads;
10static struct thread *last_match; 10static struct thread *last_match;
11 11
12void thread__init(struct thread *self, pid_t pid) 12void map_groups__init(struct map_groups *self)
13{ 13{
14 int i; 14 int i;
15 self->pid = pid;
16 self->comm = NULL;
17 for (i = 0; i < MAP__NR_TYPES; ++i) { 15 for (i = 0; i < MAP__NR_TYPES; ++i) {
18 self->maps[i] = RB_ROOT; 16 self->maps[i] = RB_ROOT;
19 INIT_LIST_HEAD(&self->removed_maps[i]); 17 INIT_LIST_HEAD(&self->removed_maps[i]);
@@ -25,7 +23,8 @@ static struct thread *thread__new(pid_t pid)
25 struct thread *self = zalloc(sizeof(*self)); 23 struct thread *self = zalloc(sizeof(*self));
26 24
27 if (self != NULL) { 25 if (self != NULL) {
28 thread__init(self, pid); 26 map_groups__init(&self->mg);
27 self->pid = pid;
29 self->comm = malloc(32); 28 self->comm = malloc(32);
30 if (self->comm) 29 if (self->comm)
31 snprintf(self->comm, 32, ":%d", self->pid); 30 snprintf(self->comm, 32, ":%d", self->pid);
@@ -55,10 +54,11 @@ int thread__comm_len(struct thread *self)
55 54
56static const char *map_type__name[MAP__NR_TYPES] = { 55static const char *map_type__name[MAP__NR_TYPES] = {
57 [MAP__FUNCTION] = "Functions", 56 [MAP__FUNCTION] = "Functions",
57 [MAP__VARIABLE] = "Variables",
58}; 58};
59 59
60static size_t __thread__fprintf_maps(struct thread *self, 60static size_t __map_groups__fprintf_maps(struct map_groups *self,
61 enum map_type type, FILE *fp) 61 enum map_type type, FILE *fp)
62{ 62{
63 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 63 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
64 struct rb_node *nd; 64 struct rb_node *nd;
@@ -76,16 +76,16 @@ static size_t __thread__fprintf_maps(struct thread *self,
76 return printed; 76 return printed;
77} 77}
78 78
79size_t thread__fprintf_maps(struct thread *self, FILE *fp) 79size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
80{ 80{
81 size_t printed = 0, i; 81 size_t printed = 0, i;
82 for (i = 0; i < MAP__NR_TYPES; ++i) 82 for (i = 0; i < MAP__NR_TYPES; ++i)
83 printed += __thread__fprintf_maps(self, i, fp); 83 printed += __map_groups__fprintf_maps(self, i, fp);
84 return printed; 84 return printed;
85} 85}
86 86
87static size_t __thread__fprintf_removed_maps(struct thread *self, 87static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
88 enum map_type type, FILE *fp) 88 enum map_type type, FILE *fp)
89{ 89{
90 struct map *pos; 90 struct map *pos;
91 size_t printed = 0; 91 size_t printed = 0;
@@ -101,20 +101,25 @@ static size_t __thread__fprintf_removed_maps(struct thread *self,
101 return printed; 101 return printed;
102} 102}
103 103
104static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp) 104static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
105{ 105{
106 size_t printed = 0, i; 106 size_t printed = 0, i;
107 for (i = 0; i < MAP__NR_TYPES; ++i) 107 for (i = 0; i < MAP__NR_TYPES; ++i)
108 printed += __thread__fprintf_removed_maps(self, i, fp); 108 printed += __map_groups__fprintf_removed_maps(self, i, fp);
109 return printed; 109 return printed;
110} 110}
111 111
112static size_t thread__fprintf(struct thread *self, FILE *fp) 112static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
113{ 113{
114 size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 114 size_t printed = map_groups__fprintf_maps(self, fp);
115 printed += thread__fprintf_removed_maps(self, fp);
116 printed += fprintf(fp, "Removed maps:\n"); 115 printed += fprintf(fp, "Removed maps:\n");
117 return printed + thread__fprintf_removed_maps(self, fp); 116 return printed + map_groups__fprintf_removed_maps(self, fp);
117}
118
119static size_t thread__fprintf(struct thread *self, FILE *fp)
120{
121 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
122 map_groups__fprintf(&self->mg, fp);
118} 123}
119 124
120struct thread *threads__findnew(pid_t pid) 125struct thread *threads__findnew(pid_t pid)
@@ -168,7 +173,8 @@ struct thread *register_idle_thread(void)
168 return thread; 173 return thread;
169} 174}
170 175
171static void thread__remove_overlappings(struct thread *self, struct map *map) 176static void map_groups__remove_overlappings(struct map_groups *self,
177 struct map *map)
172{ 178{
173 struct rb_root *root = &self->maps[map->type]; 179 struct rb_root *root = &self->maps[map->type];
174 struct rb_node *next = rb_first(root); 180 struct rb_node *next = rb_first(root);
@@ -238,12 +244,15 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
238 244
239void thread__insert_map(struct thread *self, struct map *map) 245void thread__insert_map(struct thread *self, struct map *map)
240{ 246{
241 thread__remove_overlappings(self, map); 247 map_groups__remove_overlappings(&self->mg, map);
242 maps__insert(&self->maps[map->type], map); 248 map_groups__insert(&self->mg, map);
243} 249}
244 250
245static int thread__clone_maps(struct thread *self, struct thread *parent, 251/*
246 enum map_type type) 252 * XXX This should not really _copy_ te maps, but refcount them.
253 */
254static int map_groups__clone(struct map_groups *self,
255 struct map_groups *parent, enum map_type type)
247{ 256{
248 struct rb_node *nd; 257 struct rb_node *nd;
249 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { 258 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
@@ -251,7 +260,7 @@ static int thread__clone_maps(struct thread *self, struct thread *parent,
251 struct map *new = map__clone(map); 260 struct map *new = map__clone(map);
252 if (new == NULL) 261 if (new == NULL)
253 return -ENOMEM; 262 return -ENOMEM;
254 thread__insert_map(self, new); 263 map_groups__insert(self, new);
255 } 264 }
256 return 0; 265 return 0;
257} 266}
@@ -267,7 +276,7 @@ int thread__fork(struct thread *self, struct thread *parent)
267 return -ENOMEM; 276 return -ENOMEM;
268 277
269 for (i = 0; i < MAP__NR_TYPES; ++i) 278 for (i = 0; i < MAP__NR_TYPES; ++i)
270 if (thread__clone_maps(self, parent, i) < 0) 279 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
271 return -ENOMEM; 280 return -ENOMEM;
272 return 0; 281 return 0;
273} 282}
@@ -286,11 +295,11 @@ size_t threads__fprintf(FILE *fp)
286 return ret; 295 return ret;
287} 296}
288 297
289struct symbol *thread__find_symbol(struct thread *self, 298struct symbol *map_groups__find_symbol(struct map_groups *self,
290 enum map_type type, u64 addr, 299 enum map_type type, u64 addr,
291 symbol_filter_t filter) 300 symbol_filter_t filter)
292{ 301{
293 struct map *map = thread__find_map(self, type, addr); 302 struct map *map = map_groups__find(self, type, addr);
294 303
295 if (map != NULL) 304 if (map != NULL)
296 return map__find_symbol(map, map->map_ip(map, addr), filter); 305 return map__find_symbol(map, map->map_ip(map, addr), filter);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 686d6e914d9e..1751802a09ba 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -5,52 +5,66 @@
5#include <unistd.h> 5#include <unistd.h>
6#include "symbol.h" 6#include "symbol.h"
7 7
8struct thread { 8struct map_groups {
9 struct rb_node rb_node;
10 struct rb_root maps[MAP__NR_TYPES]; 9 struct rb_root maps[MAP__NR_TYPES];
11 struct list_head removed_maps[MAP__NR_TYPES]; 10 struct list_head removed_maps[MAP__NR_TYPES];
12 pid_t pid;
13 bool use_modules; 11 bool use_modules;
12};
13
14struct thread {
15 struct rb_node rb_node;
16 struct map_groups mg;
17 pid_t pid;
14 char shortname[3]; 18 char shortname[3];
15 char *comm; 19 char *comm;
16 int comm_len; 20 int comm_len;
17}; 21};
18 22
19void thread__init(struct thread *self, pid_t pid); 23void map_groups__init(struct map_groups *self);
20int thread__set_comm(struct thread *self, const char *comm); 24int thread__set_comm(struct thread *self, const char *comm);
21int thread__comm_len(struct thread *self); 25int thread__comm_len(struct thread *self);
22struct thread *threads__findnew(pid_t pid); 26struct thread *threads__findnew(pid_t pid);
23struct thread *register_idle_thread(void); 27struct thread *register_idle_thread(void);
24void thread__insert_map(struct thread *self, struct map *map); 28void thread__insert_map(struct thread *self, struct map *map);
25int thread__fork(struct thread *self, struct thread *parent); 29int thread__fork(struct thread *self, struct thread *parent);
26size_t thread__fprintf_maps(struct thread *self, FILE *fp); 30size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
27size_t threads__fprintf(FILE *fp); 31size_t threads__fprintf(FILE *fp);
28 32
29void maps__insert(struct rb_root *maps, struct map *map); 33void maps__insert(struct rb_root *maps, struct map *map);
30struct map *maps__find(struct rb_root *maps, u64 addr); 34struct map *maps__find(struct rb_root *maps, u64 addr);
31 35
32static inline struct map *thread__find_map(struct thread *self, 36static inline void map_groups__insert(struct map_groups *self, struct map *map)
37{
38 maps__insert(&self->maps[map->type], map);
39}
40
41static inline struct map *map_groups__find(struct map_groups *self,
33 enum map_type type, u64 addr) 42 enum map_type type, u64 addr)
34{ 43{
35 return self ? maps__find(&self->maps[type], addr) : NULL; 44 return maps__find(&self->maps[type], addr);
36} 45}
37 46
38static inline void __thread__insert_map(struct thread *self, struct map *map) 47static inline struct map *thread__find_map(struct thread *self,
48 enum map_type type, u64 addr)
39{ 49{
40 maps__insert(&self->maps[map->type], map); 50 return self ? map_groups__find(&self->mg, type, addr) : NULL;
41} 51}
42 52
43void thread__find_addr_location(struct thread *self, u8 cpumode, 53void thread__find_addr_location(struct thread *self, u8 cpumode,
44 enum map_type type, u64 addr, 54 enum map_type type, u64 addr,
45 struct addr_location *al, 55 struct addr_location *al,
46 symbol_filter_t filter); 56 symbol_filter_t filter);
47struct symbol *thread__find_symbol(struct thread *self, 57struct symbol *map_groups__find_symbol(struct map_groups *self,
48 enum map_type type, u64 addr, 58 enum map_type type, u64 addr,
49 symbol_filter_t filter); 59 symbol_filter_t filter);
50 60
51static inline struct symbol * 61static inline struct symbol *
52thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) 62map_groups__find_function(struct map_groups *self, u64 addr,
63 symbol_filter_t filter)
53{ 64{
54 return thread__find_symbol(self, MAP__FUNCTION, addr, filter); 65 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
55} 66}
67
68struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name);
56#endif /* __PERF_THREAD_H */ 70#endif /* __PERF_THREAD_H */