aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/cpu/perf_event.c4
-rw-r--r--kernel/perf_event.c4
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/Documentation/perf-kmem.txt44
-rw-r--r--tools/perf/Makefile3
-rw-r--r--tools/perf/bench/bench.h1
-rw-r--r--tools/perf/bench/mem-memcpy.c193
-rw-r--r--tools/perf/builtin-annotate.c80
-rw-r--r--tools/perf/builtin-bench.c15
-rw-r--r--tools/perf/builtin-help.c4
-rw-r--r--tools/perf/builtin-kmem.c354
-rw-r--r--tools/perf/builtin-probe.c4
-rw-r--r--tools/perf/builtin-report.c86
-rw-r--r--tools/perf/builtin-sched.c16
-rw-r--r--tools/perf/builtin-top.c68
-rw-r--r--tools/perf/builtin-trace.c2
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/util/data_map.c8
-rw-r--r--tools/perf/util/data_map.h2
-rw-r--r--tools/perf/util/event.h7
-rw-r--r--tools/perf/util/header.c8
-rw-r--r--tools/perf/util/include/asm/bug.h22
-rw-r--r--tools/perf/util/include/linux/bitops.h2
-rw-r--r--tools/perf/util/map.c14
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/process_event.c53
-rw-r--r--tools/perf/util/process_event.h29
-rw-r--r--tools/perf/util/process_events.c64
-rw-r--r--tools/perf/util/process_events.h35
-rw-r--r--tools/perf/util/symbol.c110
-rw-r--r--tools/perf/util/symbol.h17
-rw-r--r--tools/perf/util/thread.c2
-rw-r--r--tools/perf/util/thread.h4
-rw-r--r--tools/perf/util/util.h16
-rw-r--r--tools/perf/util/wrapper.c61
35 files changed, 916 insertions, 420 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index bd8743024204..c1bbed1021d9 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -2229,10 +2229,10 @@ validate_event(struct cpu_hw_events *cpuc, struct perf_event *event)
2229{ 2229{
2230 struct hw_perf_event fake_event = event->hw; 2230 struct hw_perf_event fake_event = event->hw;
2231 2231
2232 if (event->pmu != &pmu) 2232 if (event->pmu && event->pmu != &pmu)
2233 return 0; 2233 return 0;
2234 2234
2235 return x86_schedule_event(cpuc, &fake_event); 2235 return x86_schedule_event(cpuc, &fake_event) >= 0;
2236} 2236}
2237 2237
2238static int validate_group(struct perf_event *event) 2238static int validate_group(struct perf_event *event)
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 9425c9600c89..35df94e344f2 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -1831,7 +1831,7 @@ static int perf_event_read_group(struct perf_event *event,
1831 1831
1832 size = n * sizeof(u64); 1832 size = n * sizeof(u64);
1833 1833
1834 if (copy_to_user(buf + size, values, size)) { 1834 if (copy_to_user(buf + ret, values, size)) {
1835 ret = -EFAULT; 1835 ret = -EFAULT;
1836 goto unlock; 1836 goto unlock;
1837 } 1837 }
@@ -3914,7 +3914,7 @@ void perf_swevent_put_recursion_context(int rctx)
3914{ 3914{
3915 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); 3915 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
3916 barrier(); 3916 barrier();
3917 cpuctx->recursion[rctx]++; 3917 cpuctx->recursion[rctx]--;
3918 put_cpu_var(perf_cpu_context); 3918 put_cpu_var(perf_cpu_context);
3919} 3919}
3920EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); 3920EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context);
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 0854f110bf7f..fe08660ce0bd 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -12,6 +12,7 @@ perf*.1
12perf*.xml 12perf*.xml
13perf*.html 13perf*.html
14common-cmds.h 14common-cmds.h
15perf.data
15tags 16tags
16TAGS 17TAGS
17cscope* 18cscope*
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
new file mode 100644
index 000000000000..44b0ce35c28a
--- /dev/null
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -0,0 +1,44 @@
1perf-kmem(1)
2==============
3
4NAME
5----
6perf-kmem - Tool to trace/measure kernel memory(slab) properties
7
8SYNOPSIS
9--------
10[verse]
11'perf kmem' {record} [<options>]
12
13DESCRIPTION
14-----------
15There's two variants of perf kmem:
16
17 'perf kmem record <command>' to record the kmem events
18 of an arbitrary workload.
19
20 'perf kmem' to report kernel memory statistics.
21
22OPTIONS
23-------
24-i <file>::
25--input=<file>::
26 Select the input file (default: perf.data)
27
28--stat=<caller|alloc>::
29 Select per callsite or per allocation statistics
30
31-s <key[,key2...]>::
32--sort=<key[,key2...]>::
33 Sort the output (default: frag,hit,bytes)
34
35-l <num>::
36--line=<num>::
37 Print n lines only
38
39--raw-ip::
40 Print raw ip instead of symbol
41
42SEE ALSO
43--------
44linkperf:perf-record[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 3ef6621bf6cd..de37d492e10f 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -369,6 +369,7 @@ LIB_H += util/sort.h
369LIB_H += util/hist.h 369LIB_H += util/hist.h
370LIB_H += util/thread.h 370LIB_H += util/thread.h
371LIB_H += util/data_map.h 371LIB_H += util/data_map.h
372LIB_H += util/process_events.h
372 373
373LIB_OBJS += util/abspath.o 374LIB_OBJS += util/abspath.o
374LIB_OBJS += util/alias.o 375LIB_OBJS += util/alias.o
@@ -411,6 +412,7 @@ LIB_OBJS += util/svghelper.o
411LIB_OBJS += util/sort.o 412LIB_OBJS += util/sort.o
412LIB_OBJS += util/hist.o 413LIB_OBJS += util/hist.o
413LIB_OBJS += util/data_map.o 414LIB_OBJS += util/data_map.o
415LIB_OBJS += util/process_events.o
414 416
415BUILTIN_OBJS += builtin-annotate.o 417BUILTIN_OBJS += builtin-annotate.o
416 418
@@ -419,6 +421,7 @@ BUILTIN_OBJS += builtin-bench.o
419# Benchmark modules 421# Benchmark modules
420BUILTIN_OBJS += bench/sched-messaging.o 422BUILTIN_OBJS += bench/sched-messaging.o
421BUILTIN_OBJS += bench/sched-pipe.o 423BUILTIN_OBJS += bench/sched-pipe.o
424BUILTIN_OBJS += bench/mem-memcpy.o
422 425
423BUILTIN_OBJS += builtin-help.o 426BUILTIN_OBJS += builtin-help.o
424BUILTIN_OBJS += builtin-sched.o 427BUILTIN_OBJS += builtin-sched.o
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index 9fbd8d745fa1..f7781c6267c0 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -3,6 +3,7 @@
3 3
4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); 4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); 5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
6extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
6 7
7#define BENCH_FORMAT_DEFAULT_STR "default" 8#define BENCH_FORMAT_DEFAULT_STR "default"
8#define BENCH_FORMAT_DEFAULT 0 9#define BENCH_FORMAT_DEFAULT 0
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
new file mode 100644
index 000000000000..89773178e894
--- /dev/null
+++ b/tools/perf/bench/mem-memcpy.c
@@ -0,0 +1,193 @@
1/*
2 * mem-memcpy.c
3 *
4 * memcpy: Simple memory copy in various ways
5 *
6 * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
7 */
8#include <ctype.h>
9
10#include "../perf.h"
11#include "../util/util.h"
12#include "../util/parse-options.h"
13#include "../util/string.h"
14#include "../util/header.h"
15#include "bench.h"
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/time.h>
21#include <errno.h>
22
23#define K 1024
24
25static const char *length_str = "1MB";
26static const char *routine = "default";
27static int use_clock = 0;
28static int clock_fd;
29
30static const struct option options[] = {
31 OPT_STRING('l', "length", &length_str, "1MB",
32 "Specify length of memory to copy. "
33 "available unit: B, MB, GB (upper and lower)"),
34 OPT_STRING('r', "routine", &routine, "default",
35 "Specify routine to copy"),
36 OPT_BOOLEAN('c', "clock", &use_clock,
37 "Use CPU clock for measuring"),
38 OPT_END()
39};
40
41struct routine {
42 const char *name;
43 const char *desc;
44 void * (*fn)(void *dst, const void *src, size_t len);
45};
46
47struct routine routines[] = {
48 { "default",
49 "Default memcpy() provided by glibc",
50 memcpy },
51 { NULL,
52 NULL,
53 NULL }
54};
55
56static const char * const bench_mem_memcpy_usage[] = {
57 "perf bench mem memcpy <options>",
58 NULL
59};
60
61static struct perf_event_attr clock_attr = {
62 .type = PERF_TYPE_HARDWARE,
63 .config = PERF_COUNT_HW_CPU_CYCLES
64};
65
66static void init_clock(void)
67{
68 clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
69
70 if (clock_fd < 0 && errno == ENOSYS)
71 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
72 else
73 BUG_ON(clock_fd < 0);
74}
75
76static u64 get_clock(void)
77{
78 int ret;
79 u64 clk;
80
81 ret = read(clock_fd, &clk, sizeof(u64));
82 BUG_ON(ret != sizeof(u64));
83
84 return clk;
85}
86
87static double timeval2double(struct timeval *ts)
88{
89 return (double)ts->tv_sec +
90 (double)ts->tv_usec / (double)1000000;
91}
92
93int bench_mem_memcpy(int argc, const char **argv,
94 const char *prefix __used)
95{
96 int i;
97 void *dst, *src;
98 size_t length;
99 double bps = 0.0;
100 struct timeval tv_start, tv_end, tv_diff;
101 u64 clock_start, clock_end, clock_diff;
102
103 clock_start = clock_end = clock_diff = 0ULL;
104 argc = parse_options(argc, argv, options,
105 bench_mem_memcpy_usage, 0);
106
107 tv_diff.tv_sec = 0;
108 tv_diff.tv_usec = 0;
109 length = (size_t)perf_atoll((char *)length_str);
110
111 if ((s64)length <= 0) {
112 fprintf(stderr, "Invalid length:%s\n", length_str);
113 return 1;
114 }
115
116 for (i = 0; routines[i].name; i++) {
117 if (!strcmp(routines[i].name, routine))
118 break;
119 }
120 if (!routines[i].name) {
121 printf("Unknown routine:%s\n", routine);
122 printf("Available routines...\n");
123 for (i = 0; routines[i].name; i++) {
124 printf("\t%s ... %s\n",
125 routines[i].name, routines[i].desc);
126 }
127 return 1;
128 }
129
130 dst = zalloc(length);
131 if (!dst)
132 die("memory allocation failed - maybe length is too large?\n");
133
134 src = zalloc(length);
135 if (!src)
136 die("memory allocation failed - maybe length is too large?\n");
137
138 if (bench_format == BENCH_FORMAT_DEFAULT) {
139 printf("# Copying %s Bytes from %p to %p ...\n\n",
140 length_str, src, dst);
141 }
142
143 if (use_clock) {
144 init_clock();
145 clock_start = get_clock();
146 } else {
147 BUG_ON(gettimeofday(&tv_start, NULL));
148 }
149
150 routines[i].fn(dst, src, length);
151
152 if (use_clock) {
153 clock_end = get_clock();
154 clock_diff = clock_end - clock_start;
155 } else {
156 BUG_ON(gettimeofday(&tv_end, NULL));
157 timersub(&tv_end, &tv_start, &tv_diff);
158 bps = (double)((double)length / timeval2double(&tv_diff));
159 }
160
161 switch (bench_format) {
162 case BENCH_FORMAT_DEFAULT:
163 if (use_clock) {
164 printf(" %14lf Clock/Byte\n",
165 (double)clock_diff / (double)length);
166 } else {
167 if (bps < K)
168 printf(" %14lf B/Sec\n", bps);
169 else if (bps < K * K)
170 printf(" %14lfd KB/Sec\n", bps / 1024);
171 else if (bps < K * K * K)
172 printf(" %14lf MB/Sec\n", bps / 1024 / 1024);
173 else {
174 printf(" %14lf GB/Sec\n",
175 bps / 1024 / 1024 / 1024);
176 }
177 }
178 break;
179 case BENCH_FORMAT_SIMPLE:
180 if (use_clock) {
181 printf("%14lf\n",
182 (double)clock_diff / (double)length);
183 } else
184 printf("%lf\n", bps);
185 break;
186 default:
187 /* reaching this means there's some disaster: */
188 die("unknown format: %d\n", bench_format);
189 break;
190 }
191
192 return 0;
193}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 6b13a1ecf1e7..18ac5eaefc36 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -24,6 +24,7 @@
24#include "util/thread.h" 24#include "util/thread.h"
25#include "util/sort.h" 25#include "util/sort.h"
26#include "util/hist.h" 26#include "util/hist.h"
27#include "util/process_events.h"
27 28
28static char const *input_name = "perf.data"; 29static char const *input_name = "perf.data";
29 30
@@ -33,11 +34,9 @@ static int input;
33static int full_paths; 34static int full_paths;
34 35
35static int print_line; 36static int print_line;
36static bool use_modules;
37 37
38static unsigned long page_size; 38static unsigned long page_size;
39static unsigned long mmap_window = 32; 39static unsigned long mmap_window = 32;
40const char *vmlinux_name;
41 40
42struct sym_hist { 41struct sym_hist {
43 u64 sum; 42 u64 sum;
@@ -55,6 +54,11 @@ struct sym_priv {
55 struct sym_ext *ext; 54 struct sym_ext *ext;
56}; 55};
57 56
57static struct symbol_conf symbol_conf = {
58 .priv_size = sizeof(struct sym_priv),
59 .try_vmlinux_path = true,
60};
61
58static const char *sym_hist_filter; 62static const char *sym_hist_filter;
59 63
60static int symbol_filter(struct map *map __used, struct symbol *sym) 64static int symbol_filter(struct map *map __used, struct symbol *sym)
@@ -158,7 +162,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
158 162
159 if (event->header.misc & PERF_RECORD_MISC_KERNEL) { 163 if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
160 level = 'k'; 164 level = 'k';
161 sym = kernel_maps__find_symbol(ip, &map, symbol_filter); 165 sym = kernel_maps__find_function(ip, &map, symbol_filter);
162 dump_printf(" ...... dso: %s\n", 166 dump_printf(" ...... dso: %s\n",
163 map ? map->dso->long_name : "<not found>"); 167 map ? map->dso->long_name : "<not found>");
164 } else if (event->header.misc & PERF_RECORD_MISC_USER) { 168 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
@@ -167,7 +171,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
167 if (map != NULL) { 171 if (map != NULL) {
168got_map: 172got_map:
169 ip = map->map_ip(map, ip); 173 ip = map->map_ip(map, ip);
170 sym = map__find_symbol(map, ip, symbol_filter); 174 sym = map__find_function(map, ip, symbol_filter);
171 } else { 175 } else {
172 /* 176 /*
173 * If this is outside of all known maps, 177 * If this is outside of all known maps,
@@ -202,32 +206,6 @@ got_map:
202} 206}
203 207
204static int 208static int
205process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
206{
207 struct map *map = map__new(&event->mmap, NULL, 0);
208 struct thread *thread = threads__findnew(event->mmap.pid);
209
210 dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
211 (void *)(offset + head),
212 (void *)(long)(event->header.size),
213 event->mmap.pid,
214 (void *)(long)event->mmap.start,
215 (void *)(long)event->mmap.len,
216 (void *)(long)event->mmap.pgoff,
217 event->mmap.filename);
218
219 if (thread == NULL || map == NULL) {
220 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
221 return 0;
222 }
223
224 thread__insert_map(thread, map);
225 total_mmap++;
226
227 return 0;
228}
229
230static int
231process_comm_event(event_t *event, unsigned long offset, unsigned long head) 209process_comm_event(event_t *event, unsigned long offset, unsigned long head)
232{ 210{
233 struct thread *thread = threads__findnew(event->comm.pid); 211 struct thread *thread = threads__findnew(event->comm.pid);
@@ -248,33 +226,6 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
248} 226}
249 227
250static int 228static int
251process_fork_event(event_t *event, unsigned long offset, unsigned long head)
252{
253 struct thread *thread = threads__findnew(event->fork.pid);
254 struct thread *parent = threads__findnew(event->fork.ppid);
255
256 dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n",
257 (void *)(offset + head),
258 (void *)(long)(event->header.size),
259 event->fork.pid, event->fork.ppid);
260
261 /*
262 * A thread clone will have the same PID for both
263 * parent and child.
264 */
265 if (thread == parent)
266 return 0;
267
268 if (!thread || !parent || thread__fork(thread, parent)) {
269 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
270 return -1;
271 }
272 total_fork++;
273
274 return 0;
275}
276
277static int
278process_event(event_t *event, unsigned long offset, unsigned long head) 229process_event(event_t *event, unsigned long offset, unsigned long head)
279{ 230{
280 switch (event->header.type) { 231 switch (event->header.type) {
@@ -288,7 +239,7 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
288 return process_comm_event(event, offset, head); 239 return process_comm_event(event, offset, head);
289 240
290 case PERF_RECORD_FORK: 241 case PERF_RECORD_FORK:
291 return process_fork_event(event, offset, head); 242 return process_task_event(event, offset, head);
292 /* 243 /*
293 * We dont process them right now but they are fine: 244 * We dont process them right now but they are fine:
294 */ 245 */
@@ -638,11 +589,6 @@ static int __cmd_annotate(void)
638 exit(0); 589 exit(0);
639 } 590 }
640 591
641 if (kernel_maps__init(vmlinux_name, true, use_modules) < 0) {
642 pr_err("failed to create kernel maps for symbol resolution\b");
643 return -1;
644 }
645
646remap: 592remap:
647 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 593 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
648 MAP_SHARED, input, offset); 594 MAP_SHARED, input, offset);
@@ -743,8 +689,9 @@ static const struct option options[] = {
743 "be more verbose (show symbol address, etc)"), 689 "be more verbose (show symbol address, etc)"),
744 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 690 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
745 "dump raw trace in ASCII"), 691 "dump raw trace in ASCII"),
746 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 692 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
747 OPT_BOOLEAN('m', "modules", &use_modules, 693 "file", "vmlinux pathname"),
694 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
748 "load module symbols - WARNING: use only with -k and LIVE kernel"), 695 "load module symbols - WARNING: use only with -k and LIVE kernel"),
749 OPT_BOOLEAN('l', "print-line", &print_line, 696 OPT_BOOLEAN('l', "print-line", &print_line,
750 "print matching source lines (may be slow)"), 697 "print matching source lines (may be slow)"),
@@ -770,7 +717,8 @@ static void setup_sorting(void)
770 717
771int cmd_annotate(int argc, const char **argv, const char *prefix __used) 718int cmd_annotate(int argc, const char **argv, const char *prefix __used)
772{ 719{
773 symbol__init(sizeof(struct sym_priv)); 720 if (symbol__init(&symbol_conf) < 0)
721 return -1;
774 722
775 page_size = getpagesize(); 723 page_size = getpagesize();
776 724
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index 90c39baae0de..e043eb83092a 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -12,6 +12,7 @@
12 * 12 *
13 * Available subsystem list: 13 * Available subsystem list:
14 * sched ... scheduler and IPC mechanism 14 * sched ... scheduler and IPC mechanism
15 * mem ... memory access performance
15 * 16 *
16 */ 17 */
17 18
@@ -43,6 +44,15 @@ static struct bench_suite sched_suites[] = {
43 NULL } 44 NULL }
44}; 45};
45 46
47static struct bench_suite mem_suites[] = {
48 { "memcpy",
49 "Simple memory copy in various ways",
50 bench_mem_memcpy },
51 { NULL,
52 NULL,
53 NULL }
54};
55
46struct bench_subsys { 56struct bench_subsys {
47 const char *name; 57 const char *name;
48 const char *summary; 58 const char *summary;
@@ -53,9 +63,12 @@ static struct bench_subsys subsystems[] = {
53 { "sched", 63 { "sched",
54 "scheduler and IPC mechanism", 64 "scheduler and IPC mechanism",
55 sched_suites }, 65 sched_suites },
66 { "mem",
67 "memory access performance",
68 mem_suites },
56 { NULL, 69 { NULL,
57 NULL, 70 NULL,
58 NULL } 71 NULL }
59}; 72};
60 73
61static void dump_suites(int subsys_index) 74static void dump_suites(int subsys_index)
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 768f9c826312..9f810b17c25c 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -179,7 +179,7 @@ static void add_man_viewer(const char *name)
179 179
180 while (*p) 180 while (*p)
181 p = &((*p)->next); 181 p = &((*p)->next);
182 *p = calloc(1, (sizeof(**p) + len + 1)); 182 *p = zalloc(sizeof(**p) + len + 1);
183 strncpy((*p)->name, name, len); 183 strncpy((*p)->name, name, len);
184} 184}
185 185
@@ -194,7 +194,7 @@ static void do_add_man_viewer_info(const char *name,
194 size_t len, 194 size_t len,
195 const char *value) 195 const char *value)
196{ 196{
197 struct man_viewer_info_list *new = calloc(1, sizeof(*new) + len + 1); 197 struct man_viewer_info_list *new = zalloc(sizeof(*new) + len + 1);
198 198
199 strncpy(new->name, name, len); 199 strncpy(new->name, name, len);
200 new->info = strdup(value); 200 new->info = strdup(value);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 256d18fa0471..35722fafc4d1 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -26,26 +26,28 @@ static u64 sample_type;
26static int alloc_flag; 26static int alloc_flag;
27static int caller_flag; 27static int caller_flag;
28 28
29sort_fn_t alloc_sort_fn;
30sort_fn_t caller_sort_fn;
31
32static int alloc_lines = -1; 29static int alloc_lines = -1;
33static int caller_lines = -1; 30static int caller_lines = -1;
34 31
32static bool raw_ip;
33
34static char default_sort_order[] = "frag,hit,bytes";
35
35static char *cwd; 36static char *cwd;
36static int cwdlen; 37static int cwdlen;
37 38
39static int *cpunode_map;
40static int max_cpu_num;
41
38struct alloc_stat { 42struct alloc_stat {
39 union { 43 u64 call_site;
40 struct { 44 u64 ptr;
41 char *name;
42 u64 call_site;
43 };
44 u64 ptr;
45 };
46 u64 bytes_req; 45 u64 bytes_req;
47 u64 bytes_alloc; 46 u64 bytes_alloc;
48 u32 hit; 47 u32 hit;
48 u32 pingpong;
49
50 short alloc_cpu;
49 51
50 struct rb_node node; 52 struct rb_node node;
51}; 53};
@@ -56,12 +58,74 @@ static struct rb_root root_caller_stat;
56static struct rb_root root_caller_sorted; 58static struct rb_root root_caller_sorted;
57 59
58static unsigned long total_requested, total_allocated; 60static unsigned long total_requested, total_allocated;
61static unsigned long nr_allocs, nr_cross_allocs;
59 62
60struct raw_event_sample { 63struct raw_event_sample {
61 u32 size; 64 u32 size;
62 char data[0]; 65 char data[0];
63}; 66};
64 67
68#define PATH_SYS_NODE "/sys/devices/system/node"
69
70static void init_cpunode_map(void)
71{
72 FILE *fp;
73 int i;
74
75 fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
76 if (!fp) {
77 max_cpu_num = 4096;
78 return;
79 }
80
81 if (fscanf(fp, "%d", &max_cpu_num) < 1)
82 die("Failed to read 'kernel_max' from sysfs");
83 max_cpu_num++;
84
85 cpunode_map = calloc(max_cpu_num, sizeof(int));
86 if (!cpunode_map)
87 die("calloc");
88 for (i = 0; i < max_cpu_num; i++)
89 cpunode_map[i] = -1;
90 fclose(fp);
91}
92
93static void setup_cpunode_map(void)
94{
95 struct dirent *dent1, *dent2;
96 DIR *dir1, *dir2;
97 unsigned int cpu, mem;
98 char buf[PATH_MAX];
99
100 init_cpunode_map();
101
102 dir1 = opendir(PATH_SYS_NODE);
103 if (!dir1)
104 return;
105
106 while (true) {
107 dent1 = readdir(dir1);
108 if (!dent1)
109 break;
110
111 if (sscanf(dent1->d_name, "node%u", &mem) < 1)
112 continue;
113
114 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
115 dir2 = opendir(buf);
116 if (!dir2)
117 continue;
118 while (true) {
119 dent2 = readdir(dir2);
120 if (!dent2)
121 break;
122 if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
123 continue;
124 cpunode_map[cpu] = mem;
125 }
126 }
127}
128
65static int 129static int
66process_comm_event(event_t *event, unsigned long offset, unsigned long head) 130process_comm_event(event_t *event, unsigned long offset, unsigned long head)
67{ 131{
@@ -81,16 +145,13 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
81 return 0; 145 return 0;
82} 146}
83 147
84static void insert_alloc_stat(unsigned long ptr, 148static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
85 int bytes_req, int bytes_alloc) 149 int bytes_req, int bytes_alloc, int cpu)
86{ 150{
87 struct rb_node **node = &root_alloc_stat.rb_node; 151 struct rb_node **node = &root_alloc_stat.rb_node;
88 struct rb_node *parent = NULL; 152 struct rb_node *parent = NULL;
89 struct alloc_stat *data = NULL; 153 struct alloc_stat *data = NULL;
90 154
91 if (!alloc_flag)
92 return;
93
94 while (*node) { 155 while (*node) {
95 parent = *node; 156 parent = *node;
96 data = rb_entry(*node, struct alloc_stat, node); 157 data = rb_entry(*node, struct alloc_stat, node);
@@ -109,7 +170,10 @@ static void insert_alloc_stat(unsigned long ptr,
109 data->bytes_alloc += bytes_req; 170 data->bytes_alloc += bytes_req;
110 } else { 171 } else {
111 data = malloc(sizeof(*data)); 172 data = malloc(sizeof(*data));
173 if (!data)
174 die("malloc");
112 data->ptr = ptr; 175 data->ptr = ptr;
176 data->pingpong = 0;
113 data->hit = 1; 177 data->hit = 1;
114 data->bytes_req = bytes_req; 178 data->bytes_req = bytes_req;
115 data->bytes_alloc = bytes_alloc; 179 data->bytes_alloc = bytes_alloc;
@@ -117,6 +181,8 @@ static void insert_alloc_stat(unsigned long ptr,
117 rb_link_node(&data->node, parent, node); 181 rb_link_node(&data->node, parent, node);
118 rb_insert_color(&data->node, &root_alloc_stat); 182 rb_insert_color(&data->node, &root_alloc_stat);
119 } 183 }
184 data->call_site = call_site;
185 data->alloc_cpu = cpu;
120} 186}
121 187
122static void insert_caller_stat(unsigned long call_site, 188static void insert_caller_stat(unsigned long call_site,
@@ -126,9 +192,6 @@ static void insert_caller_stat(unsigned long call_site,
126 struct rb_node *parent = NULL; 192 struct rb_node *parent = NULL;
127 struct alloc_stat *data = NULL; 193 struct alloc_stat *data = NULL;
128 194
129 if (!caller_flag)
130 return;
131
132 while (*node) { 195 while (*node) {
133 parent = *node; 196 parent = *node;
134 data = rb_entry(*node, struct alloc_stat, node); 197 data = rb_entry(*node, struct alloc_stat, node);
@@ -147,7 +210,10 @@ static void insert_caller_stat(unsigned long call_site,
147 data->bytes_alloc += bytes_req; 210 data->bytes_alloc += bytes_req;
148 } else { 211 } else {
149 data = malloc(sizeof(*data)); 212 data = malloc(sizeof(*data));
213 if (!data)
214 die("malloc");
150 data->call_site = call_site; 215 data->call_site = call_site;
216 data->pingpong = 0;
151 data->hit = 1; 217 data->hit = 1;
152 data->bytes_req = bytes_req; 218 data->bytes_req = bytes_req;
153 data->bytes_alloc = bytes_alloc; 219 data->bytes_alloc = bytes_alloc;
@@ -159,34 +225,89 @@ static void insert_caller_stat(unsigned long call_site,
159 225
160static void process_alloc_event(struct raw_event_sample *raw, 226static void process_alloc_event(struct raw_event_sample *raw,
161 struct event *event, 227 struct event *event,
162 int cpu __used, 228 int cpu,
163 u64 timestamp __used, 229 u64 timestamp __used,
164 struct thread *thread __used, 230 struct thread *thread __used,
165 int node __used) 231 int node)
166{ 232{
167 unsigned long call_site; 233 unsigned long call_site;
168 unsigned long ptr; 234 unsigned long ptr;
169 int bytes_req; 235 int bytes_req;
170 int bytes_alloc; 236 int bytes_alloc;
237 int node1, node2;
171 238
172 ptr = raw_field_value(event, "ptr", raw->data); 239 ptr = raw_field_value(event, "ptr", raw->data);
173 call_site = raw_field_value(event, "call_site", raw->data); 240 call_site = raw_field_value(event, "call_site", raw->data);
174 bytes_req = raw_field_value(event, "bytes_req", raw->data); 241 bytes_req = raw_field_value(event, "bytes_req", raw->data);
175 bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data); 242 bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data);
176 243
177 insert_alloc_stat(ptr, bytes_req, bytes_alloc); 244 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
178 insert_caller_stat(call_site, bytes_req, bytes_alloc); 245 insert_caller_stat(call_site, bytes_req, bytes_alloc);
179 246
180 total_requested += bytes_req; 247 total_requested += bytes_req;
181 total_allocated += bytes_alloc; 248 total_allocated += bytes_alloc;
249
250 if (node) {
251 node1 = cpunode_map[cpu];
252 node2 = raw_field_value(event, "node", raw->data);
253 if (node1 != node2)
254 nr_cross_allocs++;
255 }
256 nr_allocs++;
257}
258
259static int ptr_cmp(struct alloc_stat *, struct alloc_stat *);
260static int callsite_cmp(struct alloc_stat *, struct alloc_stat *);
261
262static struct alloc_stat *search_alloc_stat(unsigned long ptr,
263 unsigned long call_site,
264 struct rb_root *root,
265 sort_fn_t sort_fn)
266{
267 struct rb_node *node = root->rb_node;
268 struct alloc_stat key = { .ptr = ptr, .call_site = call_site };
269
270 while (node) {
271 struct alloc_stat *data;
272 int cmp;
273
274 data = rb_entry(node, struct alloc_stat, node);
275
276 cmp = sort_fn(&key, data);
277 if (cmp < 0)
278 node = node->rb_left;
279 else if (cmp > 0)
280 node = node->rb_right;
281 else
282 return data;
283 }
284 return NULL;
182} 285}
183 286
184static void process_free_event(struct raw_event_sample *raw __used, 287static void process_free_event(struct raw_event_sample *raw,
185 struct event *event __used, 288 struct event *event,
186 int cpu __used, 289 int cpu,
187 u64 timestamp __used, 290 u64 timestamp __used,
188 struct thread *thread __used) 291 struct thread *thread __used)
189{ 292{
293 unsigned long ptr;
294 struct alloc_stat *s_alloc, *s_caller;
295
296 ptr = raw_field_value(event, "ptr", raw->data);
297
298 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
299 if (!s_alloc)
300 return;
301
302 if (cpu != s_alloc->alloc_cpu) {
303 s_alloc->pingpong++;
304
305 s_caller = search_alloc_stat(0, s_alloc->call_site,
306 &root_caller_stat, callsite_cmp);
307 assert(s_caller);
308 s_caller->pingpong++;
309 }
310 s_alloc->alloc_cpu = -1;
190} 311}
191 312
192static void 313static void
@@ -291,7 +412,7 @@ static int read_events(void)
291 register_idle_thread(); 412 register_idle_thread();
292 register_perf_file_handler(&file_handler); 413 register_perf_file_handler(&file_handler);
293 414
294 return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, 415 return mmap_dispatch_perf_file(&header, input_name, 0, 0,
295 &cwdlen, &cwd); 416 &cwdlen, &cwd);
296} 417}
297 418
@@ -307,10 +428,10 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
307{ 428{
308 struct rb_node *next; 429 struct rb_node *next;
309 430
310 printf("%.78s\n", graph_dotted_line); 431 printf("%.102s\n", graph_dotted_line);
311 printf("%-28s|", is_caller ? "Callsite": "Alloc Ptr"); 432 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
312 printf("Total_alloc/Per | Total_req/Per | Hit | Frag\n"); 433 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
313 printf("%.78s\n", graph_dotted_line); 434 printf("%.102s\n", graph_dotted_line);
314 435
315 next = rb_first(root); 436 next = rb_first(root);
316 437
@@ -318,36 +439,39 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
318 struct alloc_stat *data = rb_entry(next, struct alloc_stat, 439 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
319 node); 440 node);
320 struct symbol *sym = NULL; 441 struct symbol *sym = NULL;
321 char bf[BUFSIZ]; 442 char buf[BUFSIZ];
322 u64 addr; 443 u64 addr;
323 444
324 if (is_caller) { 445 if (is_caller) {
325 addr = data->call_site; 446 addr = data->call_site;
326 sym = kernel_maps__find_symbol(addr, NULL, NULL); 447 if (!raw_ip)
448 sym = kernel_maps__find_function(addr, NULL, NULL);
327 } else 449 } else
328 addr = data->ptr; 450 addr = data->ptr;
329 451
330 if (sym != NULL) 452 if (sym != NULL)
331 snprintf(bf, sizeof(bf), "%s/%Lx", sym->name, 453 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
332 addr - sym->start); 454 addr - sym->start);
333 else 455 else
334 snprintf(bf, sizeof(bf), "%#Lx", addr); 456 snprintf(buf, sizeof(buf), "%#Lx", addr);
457 printf(" %-34s |", buf);
335 458
336 printf("%-28s|%8llu/%-6lu |%8llu/%-6lu|%6lu|%8.3f%%\n", 459 printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n",
337 bf, (unsigned long long)data->bytes_alloc, 460 (unsigned long long)data->bytes_alloc,
338 (unsigned long)data->bytes_alloc / data->hit, 461 (unsigned long)data->bytes_alloc / data->hit,
339 (unsigned long long)data->bytes_req, 462 (unsigned long long)data->bytes_req,
340 (unsigned long)data->bytes_req / data->hit, 463 (unsigned long)data->bytes_req / data->hit,
341 (unsigned long)data->hit, 464 (unsigned long)data->hit,
465 (unsigned long)data->pingpong,
342 fragmentation(data->bytes_req, data->bytes_alloc)); 466 fragmentation(data->bytes_req, data->bytes_alloc));
343 467
344 next = rb_next(next); 468 next = rb_next(next);
345 } 469 }
346 470
347 if (n_lines == -1) 471 if (n_lines == -1)
348 printf(" ... | ... | ... | ... | ... \n"); 472 printf(" ... | ... | ... | ... | ... | ... \n");
349 473
350 printf(" ------------------------------------------------------------------------------\n"); 474 printf("%.102s\n", graph_dotted_line);
351} 475}
352 476
353static void print_summary(void) 477static void print_summary(void)
@@ -359,6 +483,7 @@ static void print_summary(void)
359 total_allocated - total_requested); 483 total_allocated - total_requested);
360 printf("Internal fragmentation: %f%%\n", 484 printf("Internal fragmentation: %f%%\n",
361 fragmentation(total_requested, total_allocated)); 485 fragmentation(total_requested, total_allocated));
486 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
362} 487}
363 488
364static void print_result(void) 489static void print_result(void)
@@ -370,20 +495,34 @@ static void print_result(void)
370 print_summary(); 495 print_summary();
371} 496}
372 497
498struct sort_dimension {
499 const char name[20];
500 sort_fn_t cmp;
501 struct list_head list;
502};
503
504static LIST_HEAD(caller_sort);
505static LIST_HEAD(alloc_sort);
506
373static void sort_insert(struct rb_root *root, struct alloc_stat *data, 507static void sort_insert(struct rb_root *root, struct alloc_stat *data,
374 sort_fn_t sort_fn) 508 struct list_head *sort_list)
375{ 509{
376 struct rb_node **new = &(root->rb_node); 510 struct rb_node **new = &(root->rb_node);
377 struct rb_node *parent = NULL; 511 struct rb_node *parent = NULL;
512 struct sort_dimension *sort;
378 513
379 while (*new) { 514 while (*new) {
380 struct alloc_stat *this; 515 struct alloc_stat *this;
381 int cmp; 516 int cmp = 0;
382 517
383 this = rb_entry(*new, struct alloc_stat, node); 518 this = rb_entry(*new, struct alloc_stat, node);
384 parent = *new; 519 parent = *new;
385 520
386 cmp = sort_fn(data, this); 521 list_for_each_entry(sort, sort_list, list) {
522 cmp = sort->cmp(data, this);
523 if (cmp)
524 break;
525 }
387 526
388 if (cmp > 0) 527 if (cmp > 0)
389 new = &((*new)->rb_left); 528 new = &((*new)->rb_left);
@@ -396,7 +535,7 @@ static void sort_insert(struct rb_root *root, struct alloc_stat *data,
396} 535}
397 536
398static void __sort_result(struct rb_root *root, struct rb_root *root_sorted, 537static void __sort_result(struct rb_root *root, struct rb_root *root_sorted,
399 sort_fn_t sort_fn) 538 struct list_head *sort_list)
400{ 539{
401 struct rb_node *node; 540 struct rb_node *node;
402 struct alloc_stat *data; 541 struct alloc_stat *data;
@@ -408,14 +547,14 @@ static void __sort_result(struct rb_root *root, struct rb_root *root_sorted,
408 547
409 rb_erase(node, root); 548 rb_erase(node, root);
410 data = rb_entry(node, struct alloc_stat, node); 549 data = rb_entry(node, struct alloc_stat, node);
411 sort_insert(root_sorted, data, sort_fn); 550 sort_insert(root_sorted, data, sort_list);
412 } 551 }
413} 552}
414 553
415static void sort_result(void) 554static void sort_result(void)
416{ 555{
417 __sort_result(&root_alloc_stat, &root_alloc_sorted, alloc_sort_fn); 556 __sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort);
418 __sort_result(&root_caller_stat, &root_caller_sorted, caller_sort_fn); 557 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
419} 558}
420 559
421static int __cmd_kmem(void) 560static int __cmd_kmem(void)
@@ -433,7 +572,6 @@ static const char * const kmem_usage[] = {
433 NULL 572 NULL
434}; 573};
435 574
436
437static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) 575static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
438{ 576{
439 if (l->ptr < r->ptr) 577 if (l->ptr < r->ptr)
@@ -443,6 +581,11 @@ static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
443 return 0; 581 return 0;
444} 582}
445 583
584static struct sort_dimension ptr_sort_dimension = {
585 .name = "ptr",
586 .cmp = ptr_cmp,
587};
588
446static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r) 589static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
447{ 590{
448 if (l->call_site < r->call_site) 591 if (l->call_site < r->call_site)
@@ -452,6 +595,11 @@ static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
452 return 0; 595 return 0;
453} 596}
454 597
598static struct sort_dimension callsite_sort_dimension = {
599 .name = "callsite",
600 .cmp = callsite_cmp,
601};
602
455static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r) 603static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r)
456{ 604{
457 if (l->hit < r->hit) 605 if (l->hit < r->hit)
@@ -461,6 +609,11 @@ static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r)
461 return 0; 609 return 0;
462} 610}
463 611
612static struct sort_dimension hit_sort_dimension = {
613 .name = "hit",
614 .cmp = hit_cmp,
615};
616
464static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r) 617static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r)
465{ 618{
466 if (l->bytes_alloc < r->bytes_alloc) 619 if (l->bytes_alloc < r->bytes_alloc)
@@ -470,6 +623,11 @@ static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r)
470 return 0; 623 return 0;
471} 624}
472 625
626static struct sort_dimension bytes_sort_dimension = {
627 .name = "bytes",
628 .cmp = bytes_cmp,
629};
630
473static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r) 631static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r)
474{ 632{
475 double x, y; 633 double x, y;
@@ -484,31 +642,88 @@ static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r)
484 return 0; 642 return 0;
485} 643}
486 644
645static struct sort_dimension frag_sort_dimension = {
646 .name = "frag",
647 .cmp = frag_cmp,
648};
649
650static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r)
651{
652 if (l->pingpong < r->pingpong)
653 return -1;
654 else if (l->pingpong > r->pingpong)
655 return 1;
656 return 0;
657}
658
659static struct sort_dimension pingpong_sort_dimension = {
660 .name = "pingpong",
661 .cmp = pingpong_cmp,
662};
663
664static struct sort_dimension *avail_sorts[] = {
665 &ptr_sort_dimension,
666 &callsite_sort_dimension,
667 &hit_sort_dimension,
668 &bytes_sort_dimension,
669 &frag_sort_dimension,
670 &pingpong_sort_dimension,
671};
672
673#define NUM_AVAIL_SORTS \
674 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
675
676static int sort_dimension__add(const char *tok, struct list_head *list)
677{
678 struct sort_dimension *sort;
679 int i;
680
681 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
682 if (!strcmp(avail_sorts[i]->name, tok)) {
683 sort = malloc(sizeof(*sort));
684 if (!sort)
685 die("malloc");
686 memcpy(sort, avail_sorts[i], sizeof(*sort));
687 list_add_tail(&sort->list, list);
688 return 0;
689 }
690 }
691
692 return -1;
693}
694
695static int setup_sorting(struct list_head *sort_list, const char *arg)
696{
697 char *tok;
698 char *str = strdup(arg);
699
700 if (!str)
701 die("strdup");
702
703 while (true) {
704 tok = strsep(&str, ",");
705 if (!tok)
706 break;
707 if (sort_dimension__add(tok, sort_list) < 0) {
708 error("Unknown --sort key: '%s'", tok);
709 return -1;
710 }
711 }
712
713 free(str);
714 return 0;
715}
716
487static int parse_sort_opt(const struct option *opt __used, 717static int parse_sort_opt(const struct option *opt __used,
488 const char *arg, int unset __used) 718 const char *arg, int unset __used)
489{ 719{
490 sort_fn_t sort_fn;
491
492 if (!arg) 720 if (!arg)
493 return -1; 721 return -1;
494 722
495 if (strcmp(arg, "ptr") == 0)
496 sort_fn = ptr_cmp;
497 else if (strcmp(arg, "call_site") == 0)
498 sort_fn = callsite_cmp;
499 else if (strcmp(arg, "hit") == 0)
500 sort_fn = hit_cmp;
501 else if (strcmp(arg, "bytes") == 0)
502 sort_fn = bytes_cmp;
503 else if (strcmp(arg, "frag") == 0)
504 sort_fn = frag_cmp;
505 else
506 return -1;
507
508 if (caller_flag > alloc_flag) 723 if (caller_flag > alloc_flag)
509 caller_sort_fn = sort_fn; 724 return setup_sorting(&caller_sort, arg);
510 else 725 else
511 alloc_sort_fn = sort_fn; 726 return setup_sorting(&alloc_sort, arg);
512 727
513 return 0; 728 return 0;
514} 729}
@@ -552,12 +767,13 @@ static const struct option kmem_options[] = {
552 OPT_CALLBACK(0, "stat", NULL, "<alloc>|<caller>", 767 OPT_CALLBACK(0, "stat", NULL, "<alloc>|<caller>",
553 "stat selector, Pass 'alloc' or 'caller'.", 768 "stat selector, Pass 'alloc' or 'caller'.",
554 parse_stat_opt), 769 parse_stat_opt),
555 OPT_CALLBACK('s', "sort", NULL, "key", 770 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
556 "sort by key: ptr, call_site, hit, bytes, frag", 771 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
557 parse_sort_opt), 772 parse_sort_opt),
558 OPT_CALLBACK('l', "line", NULL, "num", 773 OPT_CALLBACK('l', "line", NULL, "num",
559 "show n lins", 774 "show n lins",
560 parse_line_opt), 775 parse_line_opt),
776 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
561 OPT_END() 777 OPT_END()
562}; 778};
563 779
@@ -604,10 +820,12 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __used)
604 else if (argc) 820 else if (argc)
605 usage_with_options(kmem_usage, kmem_options); 821 usage_with_options(kmem_usage, kmem_options);
606 822
607 if (!alloc_sort_fn) 823 if (list_empty(&caller_sort))
608 alloc_sort_fn = bytes_cmp; 824 setup_sorting(&caller_sort, default_sort_order);
609 if (!caller_sort_fn) 825 if (list_empty(&alloc_sort))
610 caller_sort_fn = bytes_cmp; 826 setup_sorting(&alloc_sort, default_sort_order);
827
828 setup_cpunode_map();
611 829
612 return __cmd_kmem(); 830 return __cmd_kmem();
613} 831}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index d78a3d945492..a2f6daf01ecb 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -309,9 +309,9 @@ static int synthesize_probe_event(struct probe_point *pp)
309{ 309{
310 char *buf; 310 char *buf;
311 int i, len, ret; 311 int i, len, ret;
312 pp->probes[0] = buf = (char *)calloc(MAX_CMDLEN, sizeof(char)); 312 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
313 if (!buf) 313 if (!buf)
314 die("Failed to allocate memory by calloc."); 314 die("Failed to allocate memory by zalloc.");
315 ret = snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); 315 ret = snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
316 if (ret <= 0 || ret >= MAX_CMDLEN) 316 if (ret <= 0 || ret >= MAX_CMDLEN)
317 goto error; 317 goto error;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index fe474b7f8ad0..e4b1004e76ea 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -30,6 +30,7 @@
30#include "util/thread.h" 30#include "util/thread.h"
31#include "util/sort.h" 31#include "util/sort.h"
32#include "util/hist.h" 32#include "util/hist.h"
33#include "util/process_events.h"
33 34
34static char const *input_name = "perf.data"; 35static char const *input_name = "perf.data";
35 36
@@ -38,7 +39,6 @@ static char *dso_list_str, *comm_list_str, *sym_list_str,
38static struct strlist *dso_list, *comm_list, *sym_list; 39static struct strlist *dso_list, *comm_list, *sym_list;
39 40
40static int force; 41static int force;
41static bool use_modules;
42 42
43static int full_paths; 43static int full_paths;
44static int show_nr_samples; 44static int show_nr_samples;
@@ -52,15 +52,13 @@ static char *pretty_printing_style = default_pretty_printing_style;
52static int exclude_other = 1; 52static int exclude_other = 1;
53 53
54static char callchain_default_opt[] = "fractal,0.5"; 54static char callchain_default_opt[] = "fractal,0.5";
55const char *vmlinux_name;
56
57static char *cwd;
58static int cwdlen;
59 55
60static struct perf_header *header; 56static struct perf_header *header;
61 57
62static u64 sample_type; 58static u64 sample_type;
63 59
60struct symbol_conf symbol_conf;
61
64 62
65static size_t 63static size_t
66callchain__fprintf_left_margin(FILE *fp, int left_margin) 64callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -450,14 +448,14 @@ got_map:
450 * trick of looking in the whole kernel symbol list. 448 * trick of looking in the whole kernel symbol list.
451 */ 449 */
452 if ((long long)ip < 0) 450 if ((long long)ip < 0)
453 return kernel_maps__find_symbol(ip, mapp, NULL); 451 return kernel_maps__find_function(ip, mapp, NULL);
454 } 452 }
455 dump_printf(" ...... dso: %s\n", 453 dump_printf(" ...... dso: %s\n",
456 map ? map->dso->long_name : "<not found>"); 454 map ? map->dso->long_name : "<not found>");
457 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); 455 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
458 *ipp = ip; 456 *ipp = ip;
459 457
460 return map ? map__find_symbol(map, ip, NULL) : NULL; 458 return map ? map__find_function(map, ip, NULL) : NULL;
461} 459}
462 460
463static int call__match(struct symbol *sym) 461static int call__match(struct symbol *sym)
@@ -497,7 +495,7 @@ static struct symbol **resolve_callchain(struct thread *thread,
497 case PERF_CONTEXT_HV: 495 case PERF_CONTEXT_HV:
498 break; 496 break;
499 case PERF_CONTEXT_KERNEL: 497 case PERF_CONTEXT_KERNEL:
500 sym = kernel_maps__find_symbol(ip, NULL, NULL); 498 sym = kernel_maps__find_function(ip, NULL, NULL);
501 break; 499 break;
502 default: 500 default:
503 sym = resolve_symbol(thread, NULL, &ip); 501 sym = resolve_symbol(thread, NULL, &ip);
@@ -717,7 +715,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
717 715
718 if (cpumode == PERF_RECORD_MISC_KERNEL) { 716 if (cpumode == PERF_RECORD_MISC_KERNEL) {
719 level = 'k'; 717 level = 'k';
720 sym = kernel_maps__find_symbol(ip, &map, NULL); 718 sym = kernel_maps__find_function(ip, &map, NULL);
721 dump_printf(" ...... dso: %s\n", 719 dump_printf(" ...... dso: %s\n",
722 map ? map->dso->long_name : "<not found>"); 720 map ? map->dso->long_name : "<not found>");
723 } else if (cpumode == PERF_RECORD_MISC_USER) { 721 } else if (cpumode == PERF_RECORD_MISC_USER) {
@@ -751,33 +749,6 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
751} 749}
752 750
753static int 751static int
754process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
755{
756 struct map *map = map__new(&event->mmap, cwd, cwdlen);
757 struct thread *thread = threads__findnew(event->mmap.pid);
758
759 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
760 (void *)(offset + head),
761 (void *)(long)(event->header.size),
762 event->mmap.pid,
763 event->mmap.tid,
764 (void *)(long)event->mmap.start,
765 (void *)(long)event->mmap.len,
766 (void *)(long)event->mmap.pgoff,
767 event->mmap.filename);
768
769 if (thread == NULL || map == NULL) {
770 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
771 return 0;
772 }
773
774 thread__insert_map(thread, map);
775 total_mmap++;
776
777 return 0;
778}
779
780static int
781process_comm_event(event_t *event, unsigned long offset, unsigned long head) 752process_comm_event(event_t *event, unsigned long offset, unsigned long head)
782{ 753{
783 struct thread *thread = threads__findnew(event->comm.pid); 754 struct thread *thread = threads__findnew(event->comm.pid);
@@ -798,38 +769,6 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
798} 769}
799 770
800static int 771static int
801process_task_event(event_t *event, unsigned long offset, unsigned long head)
802{
803 struct thread *thread = threads__findnew(event->fork.pid);
804 struct thread *parent = threads__findnew(event->fork.ppid);
805
806 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
807 (void *)(offset + head),
808 (void *)(long)(event->header.size),
809 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
810 event->fork.pid, event->fork.tid,
811 event->fork.ppid, event->fork.ptid);
812
813 /*
814 * A thread clone will have the same PID for both
815 * parent and child.
816 */
817 if (thread == parent)
818 return 0;
819
820 if (event->header.type == PERF_RECORD_EXIT)
821 return 0;
822
823 if (!thread || !parent || thread__fork(thread, parent)) {
824 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
825 return -1;
826 }
827 total_fork++;
828
829 return 0;
830}
831
832static int
833process_lost_event(event_t *event, unsigned long offset, unsigned long head) 772process_lost_event(event_t *event, unsigned long offset, unsigned long head)
834{ 773{
835 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n", 774 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
@@ -926,8 +865,7 @@ static int __cmd_report(void)
926 865
927 register_perf_file_handler(&file_handler); 866 register_perf_file_handler(&file_handler);
928 867
929 ret = mmap_dispatch_perf_file(&header, input_name, vmlinux_name, 868 ret = mmap_dispatch_perf_file(&header, input_name, force,
930 !vmlinux_name, force,
931 full_paths, &cwdlen, &cwd); 869 full_paths, &cwdlen, &cwd);
932 if (ret) 870 if (ret)
933 return ret; 871 return ret;
@@ -1024,9 +962,10 @@ static const struct option options[] = {
1024 "be more verbose (show symbol address, etc)"), 962 "be more verbose (show symbol address, etc)"),
1025 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 963 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1026 "dump raw trace in ASCII"), 964 "dump raw trace in ASCII"),
1027 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 965 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
966 "file", "vmlinux pathname"),
1028 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 967 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1029 OPT_BOOLEAN('m', "modules", &use_modules, 968 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1030 "load module symbols - WARNING: use only with -k and LIVE kernel"), 969 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1031 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 970 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1032 "Show a column with the number of samples"), 971 "Show a column with the number of samples"),
@@ -1096,7 +1035,8 @@ static void setup_list(struct strlist **list, const char *list_str,
1096 1035
1097int cmd_report(int argc, const char **argv, const char *prefix __used) 1036int cmd_report(int argc, const char **argv, const char *prefix __used)
1098{ 1037{
1099 symbol__init(0); 1038 if (symbol__init(&symbol_conf) < 0)
1039 return -1;
1100 1040
1101 argc = parse_options(argc, argv, options, report_usage, 0); 1041 argc = parse_options(argc, argv, options, report_usage, 0);
1102 1042
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 260f57a72ee0..19eb708a706b 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -225,7 +225,7 @@ static void calibrate_sleep_measurement_overhead(void)
225static struct sched_atom * 225static struct sched_atom *
226get_new_event(struct task_desc *task, u64 timestamp) 226get_new_event(struct task_desc *task, u64 timestamp)
227{ 227{
228 struct sched_atom *event = calloc(1, sizeof(*event)); 228 struct sched_atom *event = zalloc(sizeof(*event));
229 unsigned long idx = task->nr_events; 229 unsigned long idx = task->nr_events;
230 size_t size; 230 size_t size;
231 231
@@ -293,7 +293,7 @@ add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
293 return; 293 return;
294 } 294 }
295 295
296 wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem)); 296 wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
297 sem_init(wakee_event->wait_sem, 0, 0); 297 sem_init(wakee_event->wait_sem, 0, 0);
298 wakee_event->specific_wait = 1; 298 wakee_event->specific_wait = 1;
299 event->wait_sem = wakee_event->wait_sem; 299 event->wait_sem = wakee_event->wait_sem;
@@ -323,7 +323,7 @@ static struct task_desc *register_pid(unsigned long pid, const char *comm)
323 if (task) 323 if (task)
324 return task; 324 return task;
325 325
326 task = calloc(1, sizeof(*task)); 326 task = zalloc(sizeof(*task));
327 task->pid = pid; 327 task->pid = pid;
328 task->nr = nr_tasks; 328 task->nr = nr_tasks;
329 strcpy(task->comm, comm); 329 strcpy(task->comm, comm);
@@ -962,9 +962,7 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data,
962 962
963static void thread_atoms_insert(struct thread *thread) 963static void thread_atoms_insert(struct thread *thread)
964{ 964{
965 struct work_atoms *atoms; 965 struct work_atoms *atoms = zalloc(sizeof(*atoms));
966
967 atoms = calloc(sizeof(*atoms), 1);
968 if (!atoms) 966 if (!atoms)
969 die("No memory"); 967 die("No memory");
970 968
@@ -996,9 +994,7 @@ add_sched_out_event(struct work_atoms *atoms,
996 char run_state, 994 char run_state,
997 u64 timestamp) 995 u64 timestamp)
998{ 996{
999 struct work_atom *atom; 997 struct work_atom *atom = zalloc(sizeof(*atom));
1000
1001 atom = calloc(sizeof(*atom), 1);
1002 if (!atom) 998 if (!atom)
1003 die("Non memory"); 999 die("Non memory");
1004 1000
@@ -1718,7 +1714,7 @@ static int read_events(void)
1718 register_idle_thread(); 1714 register_idle_thread();
1719 register_perf_file_handler(&file_handler); 1715 register_perf_file_handler(&file_handler);
1720 1716
1721 return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, 1717 return mmap_dispatch_perf_file(&header, input_name, 0, 0,
1722 &cwdlen, &cwd); 1718 &cwdlen, &cwd);
1723} 1719}
1724 1720
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 6a5de90e9b83..ded6cf65ad9c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -79,7 +79,7 @@ static int dump_symtab = 0;
79static bool hide_kernel_symbols = false; 79static bool hide_kernel_symbols = false;
80static bool hide_user_symbols = false; 80static bool hide_user_symbols = false;
81static struct winsize winsize; 81static struct winsize winsize;
82const char *vmlinux_name; 82struct symbol_conf symbol_conf;
83 83
84/* 84/*
85 * Source 85 * Source
@@ -128,7 +128,7 @@ struct sym_entry {
128 128
129static inline struct symbol *sym_entry__symbol(struct sym_entry *self) 129static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
130{ 130{
131 return ((void *)self) + symbol__priv_size; 131 return ((void *)self) + symbol_conf.priv_size;
132} 132}
133 133
134static void get_term_dimensions(struct winsize *ws) 134static void get_term_dimensions(struct winsize *ws)
@@ -181,7 +181,7 @@ static void parse_source(struct sym_entry *syme)
181 return; 181 return;
182 182
183 if (syme->src == NULL) { 183 if (syme->src == NULL) {
184 syme->src = calloc(1, sizeof(*source)); 184 syme->src = zalloc(sizeof(*source));
185 if (syme->src == NULL) 185 if (syme->src == NULL)
186 return; 186 return;
187 pthread_mutex_init(&syme->src->lock, NULL); 187 pthread_mutex_init(&syme->src->lock, NULL);
@@ -451,9 +451,8 @@ static void print_sym_table(void)
451 struct sym_entry *syme, *n; 451 struct sym_entry *syme, *n;
452 struct rb_root tmp = RB_ROOT; 452 struct rb_root tmp = RB_ROOT;
453 struct rb_node *nd; 453 struct rb_node *nd;
454 int sym_width = 0, dso_width = 0; 454 int sym_width = 0, dso_width = 0, max_dso_width;
455 const int win_width = winsize.ws_col - 1; 455 const int win_width = winsize.ws_col - 1;
456 struct dso *unique_dso = NULL, *first_dso = NULL;
457 456
458 samples = userspace_samples = 0; 457 samples = userspace_samples = 0;
459 458
@@ -539,11 +538,6 @@ static void print_sym_table(void)
539 (int)syme->snap_count < count_filter) 538 (int)syme->snap_count < count_filter)
540 continue; 539 continue;
541 540
542 if (first_dso == NULL)
543 unique_dso = first_dso = syme->map->dso;
544 else if (syme->map->dso != first_dso)
545 unique_dso = NULL;
546
547 if (syme->map->dso->long_name_len > dso_width) 541 if (syme->map->dso->long_name_len > dso_width)
548 dso_width = syme->map->dso->long_name_len; 542 dso_width = syme->map->dso->long_name_len;
549 543
@@ -553,14 +547,10 @@ static void print_sym_table(void)
553 547
554 printed = 0; 548 printed = 0;
555 549
556 if (unique_dso) 550 max_dso_width = winsize.ws_col - sym_width - 29;
557 printf("DSO: %s\n", unique_dso->long_name); 551 if (dso_width > max_dso_width)
558 else { 552 dso_width = max_dso_width;
559 int max_dso_width = winsize.ws_col - sym_width - 29; 553 putchar('\n');
560 if (dso_width > max_dso_width)
561 dso_width = max_dso_width;
562 putchar('\n');
563 }
564 if (nr_counters == 1) 554 if (nr_counters == 1)
565 printf(" samples pcnt"); 555 printf(" samples pcnt");
566 else 556 else
@@ -568,17 +558,13 @@ static void print_sym_table(void)
568 558
569 if (verbose) 559 if (verbose)
570 printf(" RIP "); 560 printf(" RIP ");
571 printf(" %-*.*s", sym_width, sym_width, "function"); 561 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
572 if (!unique_dso)
573 printf(" DSO");
574 putchar('\n');
575 printf(" %s _______ _____", 562 printf(" %s _______ _____",
576 nr_counters == 1 ? " " : "______"); 563 nr_counters == 1 ? " " : "______");
577 if (verbose) 564 if (verbose)
578 printf(" ________________"); 565 printf(" ________________");
579 printf(" %-*.*s", sym_width, sym_width, graph_line); 566 printf(" %-*.*s", sym_width, sym_width, graph_line);
580 if (!unique_dso) 567 printf(" %-*.*s", dso_width, dso_width, graph_line);
581 printf(" %-*.*s", dso_width, dso_width, graph_line);
582 puts("\n"); 568 puts("\n");
583 569
584 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 570 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
@@ -603,12 +589,10 @@ static void print_sym_table(void)
603 if (verbose) 589 if (verbose)
604 printf(" %016llx", sym->start); 590 printf(" %016llx", sym->start);
605 printf(" %-*.*s", sym_width, sym_width, sym->name); 591 printf(" %-*.*s", sym_width, sym_width, sym->name);
606 if (!unique_dso) 592 printf(" %-*.*s\n", dso_width, dso_width,
607 printf(" %-*.*s", dso_width, dso_width, 593 dso_width >= syme->map->dso->long_name_len ?
608 dso_width >= syme->map->dso->long_name_len ? 594 syme->map->dso->long_name :
609 syme->map->dso->long_name : 595 syme->map->dso->short_name);
610 syme->map->dso->short_name);
611 printf("\n");
612 } 596 }
613} 597}
614 598
@@ -711,7 +695,7 @@ static void print_mapped_keys(void)
711 695
712 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 696 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
713 697
714 if (vmlinux_name) { 698 if (symbol_conf.vmlinux_name) {
715 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 699 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
716 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 700 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
717 fprintf(stdout, "\t[S] stop annotation.\n"); 701 fprintf(stdout, "\t[S] stop annotation.\n");
@@ -748,7 +732,7 @@ static int key_mapped(int c)
748 case 'F': 732 case 'F':
749 case 's': 733 case 's':
750 case 'S': 734 case 'S':
751 return vmlinux_name ? 1 : 0; 735 return symbol_conf.vmlinux_name ? 1 : 0;
752 default: 736 default:
753 break; 737 break;
754 } 738 }
@@ -964,7 +948,7 @@ static void event__process_sample(const event_t *self, int counter)
964 map = thread__find_map(thread, ip); 948 map = thread__find_map(thread, ip);
965 if (map != NULL) { 949 if (map != NULL) {
966 ip = map->map_ip(map, ip); 950 ip = map->map_ip(map, ip);
967 sym = map__find_symbol(map, ip, symbol_filter); 951 sym = map__find_function(map, ip, symbol_filter);
968 if (sym == NULL) 952 if (sym == NULL)
969 return; 953 return;
970 userspace_samples++; 954 userspace_samples++;
@@ -984,7 +968,7 @@ static void event__process_sample(const event_t *self, int counter)
984 if (hide_kernel_symbols) 968 if (hide_kernel_symbols)
985 return; 969 return;
986 970
987 sym = kernel_maps__find_symbol(ip, &map, symbol_filter); 971 sym = kernel_maps__find_function(ip, &map, symbol_filter);
988 if (sym == NULL) 972 if (sym == NULL)
989 return; 973 return;
990 break; 974 break;
@@ -1277,7 +1261,8 @@ static const struct option options[] = {
1277 "system-wide collection from all CPUs"), 1261 "system-wide collection from all CPUs"),
1278 OPT_INTEGER('C', "CPU", &profile_cpu, 1262 OPT_INTEGER('C', "CPU", &profile_cpu,
1279 "CPU to profile on"), 1263 "CPU to profile on"),
1280 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 1264 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1265 "file", "vmlinux pathname"),
1281 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 1266 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
1282 "hide kernel symbols"), 1267 "hide kernel symbols"),
1283 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1268 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
@@ -1311,7 +1296,7 @@ static const struct option options[] = {
1311 1296
1312int cmd_top(int argc, const char **argv, const char *prefix __used) 1297int cmd_top(int argc, const char **argv, const char *prefix __used)
1313{ 1298{
1314 int counter, err; 1299 int counter;
1315 1300
1316 page_size = sysconf(_SC_PAGE_SIZE); 1301 page_size = sysconf(_SC_PAGE_SIZE);
1317 1302
@@ -1329,15 +1314,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1329 if (!nr_counters) 1314 if (!nr_counters)
1330 nr_counters = 1; 1315 nr_counters = 1;
1331 1316
1332 symbol__init(sizeof(struct sym_entry) + 1317 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1333 (nr_counters + 1) * sizeof(unsigned long)); 1318 (nr_counters + 1) * sizeof(unsigned long));
1319 if (symbol_conf.vmlinux_name == NULL)
1320 symbol_conf.try_vmlinux_path = true;
1321 if (symbol__init(&symbol_conf) < 0)
1322 return -1;
1334 1323
1335 if (delay_secs < 1) 1324 if (delay_secs < 1)
1336 delay_secs = 1; 1325 delay_secs = 1;
1337 1326
1338 err = kernel_maps__init(vmlinux_name, !vmlinux_name, true);
1339 if (err < 0)
1340 return err;
1341 parse_source(sym_filter_entry); 1327 parse_source(sym_filter_entry);
1342 1328
1343 /* 1329 /*
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index b71198e5dc14..75972fd073df 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -131,7 +131,7 @@ static int __cmd_trace(void)
131 register_idle_thread(); 131 register_idle_thread();
132 register_perf_file_handler(&file_handler); 132 register_perf_file_handler(&file_handler);
133 133
134 return mmap_dispatch_perf_file(&header, input_name, NULL, false, 134 return mmap_dispatch_perf_file(&header, input_name,
135 0, 0, &cwdlen, &cwd); 135 0, 0, &cwdlen, &cwd);
136} 136}
137 137
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index d3a6e18e4a5e..02b09ea17a3e 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -14,3 +14,4 @@ perf-timechart mainporcelain common
14perf-top mainporcelain common 14perf-top mainporcelain common
15perf-trace mainporcelain common 15perf-trace mainporcelain common
16perf-probe mainporcelain common 16perf-probe mainporcelain common
17perf-kmem mainporcelain common
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index f318d19b2562..b238462b8983 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -101,8 +101,6 @@ out:
101 101
102int mmap_dispatch_perf_file(struct perf_header **pheader, 102int mmap_dispatch_perf_file(struct perf_header **pheader,
103 const char *input_name, 103 const char *input_name,
104 const char *vmlinux_name,
105 bool try_vmlinux_path,
106 int force, 104 int force,
107 int full_paths, 105 int full_paths,
108 int *cwdlen, 106 int *cwdlen,
@@ -172,12 +170,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
172 curr_handler->sample_type_check(sample_type) < 0) 170 curr_handler->sample_type_check(sample_type) < 0)
173 goto out_delete; 171 goto out_delete;
174 172
175 err = -ENOMEM;
176 if (kernel_maps__init(vmlinux_name, try_vmlinux_path, true) < 0) {
177 pr_err("failed to setup the kernel maps to resolve symbols\n");
178 goto out_delete;
179 }
180
181 if (!full_paths) { 173 if (!full_paths) {
182 if (getcwd(__cwd, sizeof(__cwd)) == NULL) { 174 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
183 pr_err("failed to get the current directory\n"); 175 pr_err("failed to get the current directory\n");
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
index 3f0d21b3819e..ae036ecd7625 100644
--- a/tools/perf/util/data_map.h
+++ b/tools/perf/util/data_map.h
@@ -23,8 +23,6 @@ struct perf_file_handler {
23void register_perf_file_handler(struct perf_file_handler *handler); 23void register_perf_file_handler(struct perf_file_handler *handler);
24int mmap_dispatch_perf_file(struct perf_header **pheader, 24int mmap_dispatch_perf_file(struct perf_header **pheader,
25 const char *input_name, 25 const char *input_name,
26 const char *vmlinux_name,
27 bool try_vmlinux_path,
28 int force, 26 int force,
29 int full_paths, 27 int full_paths,
30 int *cwdlen, 28 int *cwdlen,
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index f1e392612652..882a9531db97 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -119,9 +119,10 @@ void map__delete(struct map *self);
119struct map *map__clone(struct map *self); 119struct map *map__clone(struct map *self);
120int map__overlap(struct map *l, struct map *r); 120int map__overlap(struct map *l, struct map *r);
121size_t map__fprintf(struct map *self, FILE *fp); 121size_t map__fprintf(struct map *self, FILE *fp);
122struct symbol *map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter); 122struct symbol *map__find_function(struct map *self, u64 ip,
123void map__fixup_start(struct map *self); 123 symbol_filter_t filter);
124void map__fixup_end(struct map *self); 124void map__fixup_start(struct map *self, struct rb_root *symbols);
125void map__fixup_end(struct map *self, struct rb_root *symbols);
125 126
126int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); 127int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
127void event__synthesize_threads(int (*process)(event_t *event)); 128void event__synthesize_threads(int (*process)(event_t *event));
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1332f8ec04aa..4b586569bb02 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -63,7 +63,7 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
63 */ 63 */
64struct perf_header *perf_header__new(void) 64struct perf_header *perf_header__new(void)
65{ 65{
66 struct perf_header *self = calloc(sizeof(*self), 1); 66 struct perf_header *self = zalloc(sizeof(*self));
67 67
68 if (self != NULL) { 68 if (self != NULL) {
69 self->size = 1; 69 self->size = 1;
@@ -253,12 +253,6 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
253 253
254 buildid_sec = &feat_sec[idx++]; 254 buildid_sec = &feat_sec[idx++];
255 255
256 /*
257 * Read the kernel buildid nad the list of loaded modules with
258 * its build_ids:
259 */
260 kernel_maps__init(NULL, false, true);
261
262 /* Write build-ids */ 256 /* Write build-ids */
263 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 257 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
264 err = dsos__write_buildid_table(fd); 258 err = dsos__write_buildid_table(fd);
diff --git a/tools/perf/util/include/asm/bug.h b/tools/perf/util/include/asm/bug.h
new file mode 100644
index 000000000000..7fcc6810adc2
--- /dev/null
+++ b/tools/perf/util/include/asm/bug.h
@@ -0,0 +1,22 @@
1#ifndef _PERF_ASM_GENERIC_BUG_H
2#define _PERF_ASM_GENERIC_BUG_H
3
4#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0)
5
6#define WARN(condition, format...) ({ \
7 int __ret_warn_on = !!(condition); \
8 if (unlikely(__ret_warn_on)) \
9 __WARN_printf(format); \
10 unlikely(__ret_warn_on); \
11})
12
13#define WARN_ONCE(condition, format...) ({ \
14 static int __warned; \
15 int __ret_warn_once = !!(condition); \
16 \
17 if (unlikely(__ret_warn_once)) \
18 if (WARN(!__warned, format)) \
19 __warned = 1; \
20 unlikely(__ret_warn_once); \
21})
22#endif
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index ace57c36d1d0..8d63116e9435 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -7,6 +7,8 @@
7#define CONFIG_GENERIC_FIND_FIRST_BIT 7#define CONFIG_GENERIC_FIND_FIRST_BIT
8#include "../../../../include/linux/bitops.h" 8#include "../../../../include/linux/bitops.h"
9 9
10#undef __KERNEL__
11
10static inline void set_bit(int nr, unsigned long *addr) 12static inline void set_bit(int nr, unsigned long *addr)
11{ 13{
12 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); 14 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 09412321a80d..41c5c4a20010 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -80,18 +80,18 @@ void map__delete(struct map *self)
80 free(self); 80 free(self);
81} 81}
82 82
83void map__fixup_start(struct map *self) 83void map__fixup_start(struct map *self, struct rb_root *symbols)
84{ 84{
85 struct rb_node *nd = rb_first(&self->dso->syms); 85 struct rb_node *nd = rb_first(symbols);
86 if (nd != NULL) { 86 if (nd != NULL) {
87 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 87 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
88 self->start = sym->start; 88 self->start = sym->start;
89 } 89 }
90} 90}
91 91
92void map__fixup_end(struct map *self) 92void map__fixup_end(struct map *self, struct rb_root *symbols)
93{ 93{
94 struct rb_node *nd = rb_last(&self->dso->syms); 94 struct rb_node *nd = rb_last(symbols);
95 if (nd != NULL) { 95 if (nd != NULL) {
96 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 96 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
97 self->end = sym->end; 97 self->end = sym->end;
@@ -100,8 +100,8 @@ void map__fixup_end(struct map *self)
100 100
101#define DSO__DELETED "(deleted)" 101#define DSO__DELETED "(deleted)"
102 102
103struct symbol * 103struct symbol *map__find_function(struct map *self, u64 ip,
104map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter) 104 symbol_filter_t filter)
105{ 105{
106 if (!self->dso->loaded) { 106 if (!self->dso->loaded) {
107 int nr = dso__load(self->dso, self, filter); 107 int nr = dso__load(self->dso, self, filter);
@@ -136,7 +136,7 @@ map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter)
136 } 136 }
137 } 137 }
138 138
139 return self->dso->find_symbol(self->dso, ip); 139 return self->dso->find_function(self->dso, ip);
140} 140}
141 141
142struct map *map__clone(struct map *self) 142struct map *map__clone(struct map *self)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 070027469270..9e5dbd66d34d 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -197,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
197 if (id == config) { 197 if (id == config) {
198 closedir(evt_dir); 198 closedir(evt_dir);
199 closedir(sys_dir); 199 closedir(sys_dir);
200 path = calloc(1, sizeof(path)); 200 path = zalloc(sizeof(path));
201 path->system = malloc(MAX_EVENT_LENGTH); 201 path->system = malloc(MAX_EVENT_LENGTH);
202 if (!path->system) { 202 if (!path->system) {
203 free(path); 203 free(path);
diff --git a/tools/perf/util/process_event.c b/tools/perf/util/process_event.c
new file mode 100644
index 000000000000..a970789581a2
--- /dev/null
+++ b/tools/perf/util/process_event.c
@@ -0,0 +1,53 @@
1#include "process_event.h"
2
3char *cwd;
4int cwdlen;
5
6int
7process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
8{
9 struct map *map = map__new(&event->mmap, cwd, cwdlen);
10 struct thread *thread = threads__findnew(event->mmap.pid);
11
12 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
13 (void *)(offset + head),
14 (void *)(long)(event->header.size),
15 event->mmap.pid,
16 event->mmap.tid,
17 (void *)(long)event->mmap.start,
18 (void *)(long)event->mmap.len,
19 (void *)(long)event->mmap.pgoff,
20 event->mmap.filename);
21
22 if (thread == NULL || map == NULL) {
23 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
24 return 0;
25 }
26
27 thread__insert_map(thread, map);
28 total_mmap++;
29
30 return 0;
31
32}
33
34int
35process_comm_event(event_t *event, unsigned long offset, unsigned long head)
36{
37 struct thread *thread = threads__findnew(event->comm.pid);
38
39 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
40 (void *)(offset + head),
41 (void *)(long)(event->header.size),
42 event->comm.comm, event->comm.pid);
43
44 if (thread == NULL ||
45 thread__set_comm_adjust(thread, event->comm.comm)) {
46 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
47 return -1;
48 }
49 total_comm++;
50
51 return 0;
52}
53
diff --git a/tools/perf/util/process_event.h b/tools/perf/util/process_event.h
new file mode 100644
index 000000000000..6f68c69736cd
--- /dev/null
+++ b/tools/perf/util/process_event.h
@@ -0,0 +1,29 @@
1#ifndef __PROCESS_EVENT_H
2#define __PROCESS_EVENT_H
3
4#include "../builtin.h"
5#include "util.h"
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13
14#include "../perf.h"
15#include "debug.h"
16
17#include "parse-options.h"
18#include "parse-events.h"
19
20#include "thread.h"
21#include "sort.h"
22#include "hist.h"
23
24extern char *cwd;
25extern int cwdlen;
26extern int process_mmap_event(event_t *, unsigned long, unsigned long);
27extern int process_comm_event(event_t *, unsigned long , unsigned long);
28
29#endif /* __PROCESS_H */
diff --git a/tools/perf/util/process_events.c b/tools/perf/util/process_events.c
new file mode 100644
index 000000000000..a9204363efd8
--- /dev/null
+++ b/tools/perf/util/process_events.c
@@ -0,0 +1,64 @@
1#include "process_events.h"
2
3char *cwd;
4int cwdlen;
5
6int
7process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
8{
9 struct map *map = map__new(&event->mmap, cwd, cwdlen);
10 struct thread *thread = threads__findnew(event->mmap.pid);
11
12 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
13 (void *)(offset + head),
14 (void *)(long)(event->header.size),
15 event->mmap.pid,
16 event->mmap.tid,
17 (void *)(long)event->mmap.start,
18 (void *)(long)event->mmap.len,
19 (void *)(long)event->mmap.pgoff,
20 event->mmap.filename);
21
22 if (thread == NULL || map == NULL) {
23 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
24 return 0;
25 }
26
27 thread__insert_map(thread, map);
28 total_mmap++;
29
30 return 0;
31}
32
33int
34process_task_event(event_t *event, unsigned long offset, unsigned long head)
35{
36 struct thread *thread = threads__findnew(event->fork.pid);
37 struct thread *parent = threads__findnew(event->fork.ppid);
38
39 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
40 (void *)(offset + head),
41 (void *)(long)(event->header.size),
42 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
43 event->fork.pid, event->fork.tid,
44 event->fork.ppid, event->fork.ptid);
45
46 /*
47 * A thread clone will have the same PID for both
48 * parent and child.
49 */
50 if (thread == parent)
51 return 0;
52
53 if (event->header.type == PERF_RECORD_EXIT)
54 return 0;
55
56 if (!thread || !parent || thread__fork(thread, parent)) {
57 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
58 return -1;
59 }
60 total_fork++;
61
62 return 0;
63}
64
diff --git a/tools/perf/util/process_events.h b/tools/perf/util/process_events.h
new file mode 100644
index 000000000000..73d092f83283
--- /dev/null
+++ b/tools/perf/util/process_events.h
@@ -0,0 +1,35 @@
1#ifndef __PROCESS_EVENTS_H
2#define __PROCESS_EVENTS_H
3
4#include "../builtin.h"
5
6#include "util.h"
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23
24#include "data_map.h"
25#include "thread.h"
26#include "sort.h"
27#include "hist.h"
28
29extern char *cwd;
30extern int cwdlen;
31
32extern int process_mmap_event(event_t *, unsigned long , unsigned long);
33extern int process_task_event(event_t *, unsigned long, unsigned long);
34
35#endif /* __PROCESS_EVENTS_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 44d81d5ae8cf..4ed379b915fe 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -6,6 +6,7 @@
6 6
7#include "debug.h" 7#include "debug.h"
8 8
9#include <asm/bug.h>
9#include <libelf.h> 10#include <libelf.h>
10#include <gelf.h> 11#include <gelf.h>
11#include <elf.h> 12#include <elf.h>
@@ -37,11 +38,16 @@ unsigned int symbol__priv_size;
37static int vmlinux_path__nr_entries; 38static int vmlinux_path__nr_entries;
38static char **vmlinux_path; 39static char **vmlinux_path;
39 40
41static struct symbol_conf symbol_conf__defaults = {
42 .use_modules = true,
43 .try_vmlinux_path = true,
44};
45
40static struct rb_root kernel_maps; 46static struct rb_root kernel_maps;
41 47
42static void dso__fixup_sym_end(struct dso *self) 48static void symbols__fixup_end(struct rb_root *self)
43{ 49{
44 struct rb_node *nd, *prevnd = rb_first(&self->syms); 50 struct rb_node *nd, *prevnd = rb_first(self);
45 struct symbol *curr, *prev; 51 struct symbol *curr, *prev;
46 52
47 if (prevnd == NULL) 53 if (prevnd == NULL)
@@ -88,15 +94,14 @@ static void kernel_maps__fixup_end(void)
88static struct symbol *symbol__new(u64 start, u64 len, const char *name) 94static struct symbol *symbol__new(u64 start, u64 len, const char *name)
89{ 95{
90 size_t namelen = strlen(name) + 1; 96 size_t namelen = strlen(name) + 1;
91 struct symbol *self = calloc(1, (symbol__priv_size + 97 struct symbol *self = zalloc(symbol__priv_size +
92 sizeof(*self) + namelen)); 98 sizeof(*self) + namelen);
93 if (!self) 99 if (self == NULL)
94 return NULL; 100 return NULL;
95 101
96 if (symbol__priv_size) { 102 if (symbol__priv_size)
97 memset(self, 0, symbol__priv_size);
98 self = ((void *)self) + symbol__priv_size; 103 self = ((void *)self) + symbol__priv_size;
99 } 104
100 self->start = start; 105 self->start = start;
101 self->end = len ? start + len - 1 : start; 106 self->end = len ? start + len - 1 : start;
102 107
@@ -139,8 +144,8 @@ struct dso *dso__new(const char *name)
139 strcpy(self->name, name); 144 strcpy(self->name, name);
140 dso__set_long_name(self, self->name); 145 dso__set_long_name(self, self->name);
141 self->short_name = self->name; 146 self->short_name = self->name;
142 self->syms = RB_ROOT; 147 self->functions = RB_ROOT;
143 self->find_symbol = dso__find_symbol; 148 self->find_function = dso__find_function;
144 self->slen_calculated = 0; 149 self->slen_calculated = 0;
145 self->origin = DSO__ORIG_NOT_FOUND; 150 self->origin = DSO__ORIG_NOT_FOUND;
146 self->loaded = 0; 151 self->loaded = 0;
@@ -150,22 +155,22 @@ struct dso *dso__new(const char *name)
150 return self; 155 return self;
151} 156}
152 157
153static void dso__delete_symbols(struct dso *self) 158static void symbols__delete(struct rb_root *self)
154{ 159{
155 struct symbol *pos; 160 struct symbol *pos;
156 struct rb_node *next = rb_first(&self->syms); 161 struct rb_node *next = rb_first(self);
157 162
158 while (next) { 163 while (next) {
159 pos = rb_entry(next, struct symbol, rb_node); 164 pos = rb_entry(next, struct symbol, rb_node);
160 next = rb_next(&pos->rb_node); 165 next = rb_next(&pos->rb_node);
161 rb_erase(&pos->rb_node, &self->syms); 166 rb_erase(&pos->rb_node, self);
162 symbol__delete(pos); 167 symbol__delete(pos);
163 } 168 }
164} 169}
165 170
166void dso__delete(struct dso *self) 171void dso__delete(struct dso *self)
167{ 172{
168 dso__delete_symbols(self); 173 symbols__delete(&self->functions);
169 if (self->long_name != self->name) 174 if (self->long_name != self->name)
170 free(self->long_name); 175 free(self->long_name);
171 free(self); 176 free(self);
@@ -177,9 +182,9 @@ void dso__set_build_id(struct dso *self, void *build_id)
177 self->has_build_id = 1; 182 self->has_build_id = 1;
178} 183}
179 184
180static void dso__insert_symbol(struct dso *self, struct symbol *sym) 185static void symbols__insert(struct rb_root *self, struct symbol *sym)
181{ 186{
182 struct rb_node **p = &self->syms.rb_node; 187 struct rb_node **p = &self->rb_node;
183 struct rb_node *parent = NULL; 188 struct rb_node *parent = NULL;
184 const u64 ip = sym->start; 189 const u64 ip = sym->start;
185 struct symbol *s; 190 struct symbol *s;
@@ -193,17 +198,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
193 p = &(*p)->rb_right; 198 p = &(*p)->rb_right;
194 } 199 }
195 rb_link_node(&sym->rb_node, parent, p); 200 rb_link_node(&sym->rb_node, parent, p);
196 rb_insert_color(&sym->rb_node, &self->syms); 201 rb_insert_color(&sym->rb_node, self);
197} 202}
198 203
199struct symbol *dso__find_symbol(struct dso *self, u64 ip) 204static struct symbol *symbols__find(struct rb_root *self, u64 ip)
200{ 205{
201 struct rb_node *n; 206 struct rb_node *n;
202 207
203 if (self == NULL) 208 if (self == NULL)
204 return NULL; 209 return NULL;
205 210
206 n = self->syms.rb_node; 211 n = self->rb_node;
207 212
208 while (n) { 213 while (n) {
209 struct symbol *s = rb_entry(n, struct symbol, rb_node); 214 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -219,6 +224,11 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
219 return NULL; 224 return NULL;
220} 225}
221 226
227struct symbol *dso__find_function(struct dso *self, u64 ip)
228{
229 return symbols__find(&self->functions, ip);
230}
231
222int build_id__sprintf(u8 *self, int len, char *bf) 232int build_id__sprintf(u8 *self, int len, char *bf)
223{ 233{
224 char *bid = bf; 234 char *bid = bf;
@@ -248,9 +258,9 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
248 size_t ret = fprintf(fp, "dso: %s (", self->short_name); 258 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
249 259
250 ret += dso__fprintf_buildid(self, fp); 260 ret += dso__fprintf_buildid(self, fp);
251 ret += fprintf(fp, ")\n"); 261 ret += fprintf(fp, ")\nFunctions:\n");
252 262
253 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 263 for (nd = rb_first(&self->functions); nd; nd = rb_next(nd)) {
254 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 264 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
255 ret += symbol__fprintf(pos, fp); 265 ret += symbol__fprintf(pos, fp);
256 } 266 }
@@ -315,7 +325,7 @@ static int kernel_maps__load_all_kallsyms(void)
315 * kernel_maps__split_kallsyms, when we have split the 325 * kernel_maps__split_kallsyms, when we have split the
316 * maps per module 326 * maps per module
317 */ 327 */
318 dso__insert_symbol(kernel_map->dso, sym); 328 symbols__insert(&kernel_map->dso->functions, sym);
319 } 329 }
320 330
321 free(line); 331 free(line);
@@ -339,7 +349,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
339 struct map *map = kernel_map; 349 struct map *map = kernel_map;
340 struct symbol *pos; 350 struct symbol *pos;
341 int count = 0; 351 int count = 0;
342 struct rb_node *next = rb_first(&kernel_map->dso->syms); 352 struct rb_node *next = rb_first(&kernel_map->dso->functions);
343 int kernel_range = 0; 353 int kernel_range = 0;
344 354
345 while (next) { 355 while (next) {
@@ -389,12 +399,13 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter)
389 } 399 }
390 400
391 if (filter && filter(map, pos)) { 401 if (filter && filter(map, pos)) {
392 rb_erase(&pos->rb_node, &kernel_map->dso->syms); 402 rb_erase(&pos->rb_node, &kernel_map->dso->functions);
393 symbol__delete(pos); 403 symbol__delete(pos);
394 } else { 404 } else {
395 if (map != kernel_map) { 405 if (map != kernel_map) {
396 rb_erase(&pos->rb_node, &kernel_map->dso->syms); 406 rb_erase(&pos->rb_node,
397 dso__insert_symbol(map->dso, pos); 407 &kernel_map->dso->functions);
408 symbols__insert(&map->dso->functions, pos);
398 } 409 }
399 count++; 410 count++;
400 } 411 }
@@ -409,7 +420,7 @@ static int kernel_maps__load_kallsyms(symbol_filter_t filter)
409 if (kernel_maps__load_all_kallsyms()) 420 if (kernel_maps__load_all_kallsyms())
410 return -1; 421 return -1;
411 422
412 dso__fixup_sym_end(kernel_map->dso); 423 symbols__fixup_end(&kernel_map->dso->functions);
413 kernel_map->dso->origin = DSO__ORIG_KERNEL; 424 kernel_map->dso->origin = DSO__ORIG_KERNEL;
414 425
415 return kernel_maps__split_kallsyms(filter); 426 return kernel_maps__split_kallsyms(filter);
@@ -480,7 +491,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
480 if (filter && filter(map, sym)) 491 if (filter && filter(map, sym))
481 symbol__delete(sym); 492 symbol__delete(sym);
482 else { 493 else {
483 dso__insert_symbol(self, sym); 494 symbols__insert(&self->functions, sym);
484 nr_syms++; 495 nr_syms++;
485 } 496 }
486 } 497 }
@@ -678,7 +689,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
678 if (filter && filter(map, f)) 689 if (filter && filter(map, f))
679 symbol__delete(f); 690 symbol__delete(f);
680 else { 691 else {
681 dso__insert_symbol(self, f); 692 symbols__insert(&self->functions, f);
682 ++nr; 693 ++nr;
683 } 694 }
684 } 695 }
@@ -700,7 +711,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
700 if (filter && filter(map, f)) 711 if (filter && filter(map, f))
701 symbol__delete(f); 712 symbol__delete(f);
702 else { 713 else {
703 dso__insert_symbol(self, f); 714 symbols__insert(&self->functions, f);
704 ++nr; 715 ++nr;
705 } 716 }
706 } 717 }
@@ -874,7 +885,7 @@ new_symbol:
874 if (filter && filter(curr_map, f)) 885 if (filter && filter(curr_map, f))
875 symbol__delete(f); 886 symbol__delete(f);
876 else { 887 else {
877 dso__insert_symbol(curr_dso, f); 888 symbols__insert(&curr_dso->functions, f);
878 nr++; 889 nr++;
879 } 890 }
880 } 891 }
@@ -883,7 +894,7 @@ new_symbol:
883 * For misannotated, zeroed, ASM function sizes. 894 * For misannotated, zeroed, ASM function sizes.
884 */ 895 */
885 if (nr > 0) 896 if (nr > 0)
886 dso__fixup_sym_end(self); 897 symbols__fixup_end(&self->functions);
887 err = nr; 898 err = nr;
888out_elf_end: 899out_elf_end:
889 elf_end(elf); 900 elf_end(elf);
@@ -1155,8 +1166,8 @@ static void kernel_maps__insert(struct map *map)
1155 maps__insert(&kernel_maps, map); 1166 maps__insert(&kernel_maps, map);
1156} 1167}
1157 1168
1158struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp, 1169struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp,
1159 symbol_filter_t filter) 1170 symbol_filter_t filter)
1160{ 1171{
1161 struct map *map = maps__find(&kernel_maps, ip); 1172 struct map *map = maps__find(&kernel_maps, ip);
1162 1173
@@ -1165,8 +1176,10 @@ struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp,
1165 1176
1166 if (map) { 1177 if (map) {
1167 ip = map->map_ip(map, ip); 1178 ip = map->map_ip(map, ip);
1168 return map__find_symbol(map, ip, filter); 1179 return map__find_function(map, ip, filter);
1169 } 1180 } else
1181 WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps),
1182 "Empty kernel_maps, was symbol__init() called?\n");
1170 1183
1171 return NULL; 1184 return NULL;
1172} 1185}
@@ -1425,8 +1438,8 @@ do_kallsyms:
1425 1438
1426 if (err > 0) { 1439 if (err > 0) {
1427out_fixup: 1440out_fixup:
1428 map__fixup_start(map); 1441 map__fixup_start(map, &map->dso->functions);
1429 map__fixup_end(map); 1442 map__fixup_end(map, &map->dso->functions);
1430 } 1443 }
1431 1444
1432 return err; 1445 return err;
@@ -1485,9 +1498,9 @@ size_t dsos__fprintf_buildid(FILE *fp)
1485 return ret; 1498 return ret;
1486} 1499}
1487 1500
1488static int kernel_maps__create_kernel_map(const char *vmlinux_name) 1501static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
1489{ 1502{
1490 struct dso *kernel = dso__new(vmlinux_name ?: "[kernel.kallsyms]"); 1503 struct dso *kernel = dso__new(conf->vmlinux_name ?: "[kernel.kallsyms]");
1491 1504
1492 if (kernel == NULL) 1505 if (kernel == NULL)
1493 return -1; 1506 return -1;
@@ -1577,18 +1590,21 @@ out_fail:
1577 return -1; 1590 return -1;
1578} 1591}
1579 1592
1580int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, 1593static int kernel_maps__init(const struct symbol_conf *conf)
1581 bool use_modules)
1582{ 1594{
1583 if (try_vmlinux_path && vmlinux_path__init() < 0) 1595 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
1596
1597 symbol__priv_size = pconf->priv_size;
1598
1599 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
1584 return -1; 1600 return -1;
1585 1601
1586 if (kernel_maps__create_kernel_map(vmlinux_name) < 0) { 1602 if (kernel_maps__create_kernel_map(pconf) < 0) {
1587 vmlinux_path__exit(); 1603 vmlinux_path__exit();
1588 return -1; 1604 return -1;
1589 } 1605 }
1590 1606
1591 if (use_modules && kernel_maps__create_module_maps() < 0) 1607 if (pconf->use_modules && kernel_maps__create_module_maps() < 0)
1592 pr_debug("Failed to load list of modules in use, " 1608 pr_debug("Failed to load list of modules in use, "
1593 "continuing...\n"); 1609 "continuing...\n");
1594 /* 1610 /*
@@ -1598,8 +1614,8 @@ int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path,
1598 return 0; 1614 return 0;
1599} 1615}
1600 1616
1601void symbol__init(unsigned int priv_size) 1617int symbol__init(struct symbol_conf *conf)
1602{ 1618{
1603 elf_version(EV_CURRENT); 1619 elf_version(EV_CURRENT);
1604 symbol__priv_size = priv_size; 1620 return kernel_maps__init(conf);
1605} 1621}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8c4d026e067a..65846d0c5df7 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -49,6 +49,13 @@ struct symbol {
49 char name[0]; 49 char name[0];
50}; 50};
51 51
52struct symbol_conf {
53 unsigned short priv_size;
54 bool try_vmlinux_path,
55 use_modules;
56 const char *vmlinux_name;
57};
58
52extern unsigned int symbol__priv_size; 59extern unsigned int symbol__priv_size;
53 60
54static inline void *symbol__priv(struct symbol *self) 61static inline void *symbol__priv(struct symbol *self)
@@ -58,8 +65,8 @@ static inline void *symbol__priv(struct symbol *self)
58 65
59struct dso { 66struct dso {
60 struct list_head node; 67 struct list_head node;
61 struct rb_root syms; 68 struct rb_root functions;
62 struct symbol *(*find_symbol)(struct dso *, u64 ip); 69 struct symbol *(*find_function)(struct dso *, u64 ip);
63 u8 adjust_symbols:1; 70 u8 adjust_symbols:1;
64 u8 slen_calculated:1; 71 u8 slen_calculated:1;
65 u8 loaded:1; 72 u8 loaded:1;
@@ -76,7 +83,7 @@ struct dso {
76struct dso *dso__new(const char *name); 83struct dso *dso__new(const char *name);
77void dso__delete(struct dso *self); 84void dso__delete(struct dso *self);
78 85
79struct symbol *dso__find_symbol(struct dso *self, u64 ip); 86struct symbol *dso__find_function(struct dso *self, u64 ip);
80 87
81struct dso *dsos__findnew(const char *name); 88struct dso *dsos__findnew(const char *name);
82int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 89int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
@@ -93,11 +100,9 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size);
93bool dsos__read_build_ids(void); 100bool dsos__read_build_ids(void);
94int build_id__sprintf(u8 *self, int len, char *bf); 101int build_id__sprintf(u8 *self, int len, char *bf);
95 102
96int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path,
97 bool use_modules);
98size_t kernel_maps__fprintf(FILE *fp); 103size_t kernel_maps__fprintf(FILE *fp);
99 104
100void symbol__init(unsigned int priv_size); 105int symbol__init(struct symbol_conf *conf);
101 106
102extern struct list_head dsos; 107extern struct list_head dsos;
103extern struct map *kernel_map; 108extern struct map *kernel_map;
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 0f6d78c9863a..1796625f7784 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -11,7 +11,7 @@ static struct thread *last_match;
11 11
12static struct thread *thread__new(pid_t pid) 12static struct thread *thread__new(pid_t pid)
13{ 13{
14 struct thread *self = calloc(1, sizeof(*self)); 14 struct thread *self = zalloc(sizeof(*self));
15 15
16 if (self != NULL) { 16 if (self != NULL) {
17 self->pid = pid; 17 self->pid = pid;
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index e4b8d437725a..74cba6487edb 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -26,8 +26,8 @@ size_t threads__fprintf(FILE *fp);
26void maps__insert(struct rb_root *maps, struct map *map); 26void maps__insert(struct rb_root *maps, struct map *map);
27struct map *maps__find(struct rb_root *maps, u64 ip); 27struct map *maps__find(struct rb_root *maps, u64 ip);
28 28
29struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp, 29struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp,
30 symbol_filter_t filter); 30 symbol_filter_t filter);
31struct map *kernel_maps__find_by_dso_name(const char *name); 31struct map *kernel_maps__find_by_dso_name(const char *name);
32 32
33static inline struct map *thread__find_map(struct thread *self, u64 ip) 33static inline struct map *thread__find_map(struct thread *self, u64 ip)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index e1c623e0c99e..c673d8825883 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -290,17 +290,15 @@ static inline char *gitstrchrnul(const char *s, int c)
290 * Wrappers: 290 * Wrappers:
291 */ 291 */
292extern char *xstrdup(const char *str); 292extern char *xstrdup(const char *str);
293extern void *xmalloc(size_t size); 293extern void *xmalloc(size_t size) __attribute__((weak));
294extern void *xmemdupz(const void *data, size_t len); 294extern void *xmemdupz(const void *data, size_t len);
295extern char *xstrndup(const char *str, size_t len); 295extern char *xstrndup(const char *str, size_t len);
296extern void *xrealloc(void *ptr, size_t size); 296extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
297extern void *xcalloc(size_t nmemb, size_t size); 297
298extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); 298static inline void *zalloc(size_t size)
299extern ssize_t xread(int fd, void *buf, size_t len); 299{
300extern ssize_t xwrite(int fd, const void *buf, size_t len); 300 return calloc(1, size);
301extern int xdup(int fd); 301}
302extern FILE *xfdopen(int fd, const char *mode);
303extern int xmkstemp(char *template);
304 302
305static inline size_t xsize_t(off_t len) 303static inline size_t xsize_t(off_t len)
306{ 304{
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 4574ac28396f..bf44ca85d23b 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -79,43 +79,12 @@ void *xrealloc(void *ptr, size_t size)
79 return ret; 79 return ret;
80} 80}
81 81
82void *xcalloc(size_t nmemb, size_t size)
83{
84 void *ret = calloc(nmemb, size);
85 if (!ret && (!nmemb || !size))
86 ret = calloc(1, 1);
87 if (!ret) {
88 release_pack_memory(nmemb * size, -1);
89 ret = calloc(nmemb, size);
90 if (!ret && (!nmemb || !size))
91 ret = calloc(1, 1);
92 if (!ret)
93 die("Out of memory, calloc failed");
94 }
95 return ret;
96}
97
98void *xmmap(void *start, size_t length,
99 int prot, int flags, int fd, off_t offset)
100{
101 void *ret = mmap(start, length, prot, flags, fd, offset);
102 if (ret == MAP_FAILED) {
103 if (!length)
104 return NULL;
105 release_pack_memory(length, fd);
106 ret = mmap(start, length, prot, flags, fd, offset);
107 if (ret == MAP_FAILED)
108 die("Out of memory? mmap failed: %s", strerror(errno));
109 }
110 return ret;
111}
112
113/* 82/*
114 * xread() is the same a read(), but it automatically restarts read() 83 * xread() is the same a read(), but it automatically restarts read()
115 * operations with a recoverable error (EAGAIN and EINTR). xread() 84 * operations with a recoverable error (EAGAIN and EINTR). xread()
116 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available. 85 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
117 */ 86 */
118ssize_t xread(int fd, void *buf, size_t len) 87static ssize_t xread(int fd, void *buf, size_t len)
119{ 88{
120 ssize_t nr; 89 ssize_t nr;
121 while (1) { 90 while (1) {
@@ -131,7 +100,7 @@ ssize_t xread(int fd, void *buf, size_t len)
131 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT 100 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
132 * GUARANTEE that "len" bytes is written even if the operation is successful. 101 * GUARANTEE that "len" bytes is written even if the operation is successful.
133 */ 102 */
134ssize_t xwrite(int fd, const void *buf, size_t len) 103static ssize_t xwrite(int fd, const void *buf, size_t len)
135{ 104{
136 ssize_t nr; 105 ssize_t nr;
137 while (1) { 106 while (1) {
@@ -179,29 +148,3 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
179 148
180 return total; 149 return total;
181} 150}
182
183int xdup(int fd)
184{
185 int ret = dup(fd);
186 if (ret < 0)
187 die("dup failed: %s", strerror(errno));
188 return ret;
189}
190
191FILE *xfdopen(int fd, const char *mode)
192{
193 FILE *stream = fdopen(fd, mode);
194 if (stream == NULL)
195 die("Out of memory? fdopen failed: %s", strerror(errno));
196 return stream;
197}
198
199int xmkstemp(char *template)
200{
201 int fd;
202
203 fd = mkstemp(template);
204 if (fd < 0)
205 die("Unable to create temporary file: %s", strerror(errno));
206 return fd;
207}