diff options
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 | ||
2238 | static int validate_group(struct perf_event *event) | 2238 | static 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 | } |
3920 | EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); | 3920 | EXPORT_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 | |||
12 | perf*.xml | 12 | perf*.xml |
13 | perf*.html | 13 | perf*.html |
14 | common-cmds.h | 14 | common-cmds.h |
15 | perf.data | ||
15 | tags | 16 | tags |
16 | TAGS | 17 | TAGS |
17 | cscope* | 18 | cscope* |
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 @@ | |||
1 | perf-kmem(1) | ||
2 | ============== | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | perf-kmem - Tool to trace/measure kernel memory(slab) properties | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | 'perf kmem' {record} [<options>] | ||
12 | |||
13 | DESCRIPTION | ||
14 | ----------- | ||
15 | There'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 | |||
22 | OPTIONS | ||
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 | |||
42 | SEE ALSO | ||
43 | -------- | ||
44 | linkperf: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 | |||
369 | LIB_H += util/hist.h | 369 | LIB_H += util/hist.h |
370 | LIB_H += util/thread.h | 370 | LIB_H += util/thread.h |
371 | LIB_H += util/data_map.h | 371 | LIB_H += util/data_map.h |
372 | LIB_H += util/process_events.h | ||
372 | 373 | ||
373 | LIB_OBJS += util/abspath.o | 374 | LIB_OBJS += util/abspath.o |
374 | LIB_OBJS += util/alias.o | 375 | LIB_OBJS += util/alias.o |
@@ -411,6 +412,7 @@ LIB_OBJS += util/svghelper.o | |||
411 | LIB_OBJS += util/sort.o | 412 | LIB_OBJS += util/sort.o |
412 | LIB_OBJS += util/hist.o | 413 | LIB_OBJS += util/hist.o |
413 | LIB_OBJS += util/data_map.o | 414 | LIB_OBJS += util/data_map.o |
415 | LIB_OBJS += util/process_events.o | ||
414 | 416 | ||
415 | BUILTIN_OBJS += builtin-annotate.o | 417 | BUILTIN_OBJS += builtin-annotate.o |
416 | 418 | ||
@@ -419,6 +421,7 @@ BUILTIN_OBJS += builtin-bench.o | |||
419 | # Benchmark modules | 421 | # Benchmark modules |
420 | BUILTIN_OBJS += bench/sched-messaging.o | 422 | BUILTIN_OBJS += bench/sched-messaging.o |
421 | BUILTIN_OBJS += bench/sched-pipe.o | 423 | BUILTIN_OBJS += bench/sched-pipe.o |
424 | BUILTIN_OBJS += bench/mem-memcpy.o | ||
422 | 425 | ||
423 | BUILTIN_OBJS += builtin-help.o | 426 | BUILTIN_OBJS += builtin-help.o |
424 | BUILTIN_OBJS += builtin-sched.o | 427 | BUILTIN_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 | ||
4 | extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); | 4 | extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); |
5 | extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); | 5 | extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); |
6 | extern 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 | |||
25 | static const char *length_str = "1MB"; | ||
26 | static const char *routine = "default"; | ||
27 | static int use_clock = 0; | ||
28 | static int clock_fd; | ||
29 | |||
30 | static 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 | |||
41 | struct routine { | ||
42 | const char *name; | ||
43 | const char *desc; | ||
44 | void * (*fn)(void *dst, const void *src, size_t len); | ||
45 | }; | ||
46 | |||
47 | struct routine routines[] = { | ||
48 | { "default", | ||
49 | "Default memcpy() provided by glibc", | ||
50 | memcpy }, | ||
51 | { NULL, | ||
52 | NULL, | ||
53 | NULL } | ||
54 | }; | ||
55 | |||
56 | static const char * const bench_mem_memcpy_usage[] = { | ||
57 | "perf bench mem memcpy <options>", | ||
58 | NULL | ||
59 | }; | ||
60 | |||
61 | static struct perf_event_attr clock_attr = { | ||
62 | .type = PERF_TYPE_HARDWARE, | ||
63 | .config = PERF_COUNT_HW_CPU_CYCLES | ||
64 | }; | ||
65 | |||
66 | static 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 | |||
76 | static 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 | |||
87 | static double timeval2double(struct timeval *ts) | ||
88 | { | ||
89 | return (double)ts->tv_sec + | ||
90 | (double)ts->tv_usec / (double)1000000; | ||
91 | } | ||
92 | |||
93 | int 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 | ||
28 | static char const *input_name = "perf.data"; | 29 | static char const *input_name = "perf.data"; |
29 | 30 | ||
@@ -33,11 +34,9 @@ static int input; | |||
33 | static int full_paths; | 34 | static int full_paths; |
34 | 35 | ||
35 | static int print_line; | 36 | static int print_line; |
36 | static bool use_modules; | ||
37 | 37 | ||
38 | static unsigned long page_size; | 38 | static unsigned long page_size; |
39 | static unsigned long mmap_window = 32; | 39 | static unsigned long mmap_window = 32; |
40 | const char *vmlinux_name; | ||
41 | 40 | ||
42 | struct sym_hist { | 41 | struct 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 | ||
57 | static struct symbol_conf symbol_conf = { | ||
58 | .priv_size = sizeof(struct sym_priv), | ||
59 | .try_vmlinux_path = true, | ||
60 | }; | ||
61 | |||
58 | static const char *sym_hist_filter; | 62 | static const char *sym_hist_filter; |
59 | 63 | ||
60 | static int symbol_filter(struct map *map __used, struct symbol *sym) | 64 | static 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) { |
168 | got_map: | 172 | got_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 | ||
204 | static int | 208 | static int |
205 | process_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 | |||
230 | static int | ||
231 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) | 209 | process_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 | ||
250 | static int | 228 | static int |
251 | process_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 | |||
277 | static int | ||
278 | process_event(event_t *event, unsigned long offset, unsigned long head) | 229 | process_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 | |||
646 | remap: | 592 | remap: |
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 | ||
771 | int cmd_annotate(int argc, const char **argv, const char *prefix __used) | 718 | int 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 | ||
47 | static 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 | |||
46 | struct bench_subsys { | 56 | struct 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 | ||
61 | static void dump_suites(int subsys_index) | 74 | static 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; | |||
26 | static int alloc_flag; | 26 | static int alloc_flag; |
27 | static int caller_flag; | 27 | static int caller_flag; |
28 | 28 | ||
29 | sort_fn_t alloc_sort_fn; | ||
30 | sort_fn_t caller_sort_fn; | ||
31 | |||
32 | static int alloc_lines = -1; | 29 | static int alloc_lines = -1; |
33 | static int caller_lines = -1; | 30 | static int caller_lines = -1; |
34 | 31 | ||
32 | static bool raw_ip; | ||
33 | |||
34 | static char default_sort_order[] = "frag,hit,bytes"; | ||
35 | |||
35 | static char *cwd; | 36 | static char *cwd; |
36 | static int cwdlen; | 37 | static int cwdlen; |
37 | 38 | ||
39 | static int *cpunode_map; | ||
40 | static int max_cpu_num; | ||
41 | |||
38 | struct alloc_stat { | 42 | struct 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; | |||
56 | static struct rb_root root_caller_sorted; | 58 | static struct rb_root root_caller_sorted; |
57 | 59 | ||
58 | static unsigned long total_requested, total_allocated; | 60 | static unsigned long total_requested, total_allocated; |
61 | static unsigned long nr_allocs, nr_cross_allocs; | ||
59 | 62 | ||
60 | struct raw_event_sample { | 63 | struct 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 | |||
70 | static 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 | |||
93 | static 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 | |||
65 | static int | 129 | static int |
66 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) | 130 | process_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 | ||
84 | static void insert_alloc_stat(unsigned long ptr, | 148 | static 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 | ||
122 | static void insert_caller_stat(unsigned long call_site, | 188 | static 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 | ||
160 | static void process_alloc_event(struct raw_event_sample *raw, | 226 | static 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 | |||
259 | static int ptr_cmp(struct alloc_stat *, struct alloc_stat *); | ||
260 | static int callsite_cmp(struct alloc_stat *, struct alloc_stat *); | ||
261 | |||
262 | static 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 | ||
184 | static void process_free_event(struct raw_event_sample *raw __used, | 287 | static 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 | ||
192 | static void | 313 | static 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 | ||
353 | static void print_summary(void) | 477 | static 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 | ||
364 | static void print_result(void) | 489 | static void print_result(void) |
@@ -370,20 +495,34 @@ static void print_result(void) | |||
370 | print_summary(); | 495 | print_summary(); |
371 | } | 496 | } |
372 | 497 | ||
498 | struct sort_dimension { | ||
499 | const char name[20]; | ||
500 | sort_fn_t cmp; | ||
501 | struct list_head list; | ||
502 | }; | ||
503 | |||
504 | static LIST_HEAD(caller_sort); | ||
505 | static LIST_HEAD(alloc_sort); | ||
506 | |||
373 | static void sort_insert(struct rb_root *root, struct alloc_stat *data, | 507 | static 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 | ||
398 | static void __sort_result(struct rb_root *root, struct rb_root *root_sorted, | 537 | static 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 | ||
415 | static void sort_result(void) | 554 | static 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 | ||
421 | static int __cmd_kmem(void) | 560 | static int __cmd_kmem(void) |
@@ -433,7 +572,6 @@ static const char * const kmem_usage[] = { | |||
433 | NULL | 572 | NULL |
434 | }; | 573 | }; |
435 | 574 | ||
436 | |||
437 | static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) | 575 | static 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 | ||
584 | static struct sort_dimension ptr_sort_dimension = { | ||
585 | .name = "ptr", | ||
586 | .cmp = ptr_cmp, | ||
587 | }; | ||
588 | |||
446 | static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r) | 589 | static 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 | ||
598 | static struct sort_dimension callsite_sort_dimension = { | ||
599 | .name = "callsite", | ||
600 | .cmp = callsite_cmp, | ||
601 | }; | ||
602 | |||
455 | static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r) | 603 | static 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 | ||
612 | static struct sort_dimension hit_sort_dimension = { | ||
613 | .name = "hit", | ||
614 | .cmp = hit_cmp, | ||
615 | }; | ||
616 | |||
464 | static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r) | 617 | static 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 | ||
626 | static struct sort_dimension bytes_sort_dimension = { | ||
627 | .name = "bytes", | ||
628 | .cmp = bytes_cmp, | ||
629 | }; | ||
630 | |||
473 | static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r) | 631 | static 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 | ||
645 | static struct sort_dimension frag_sort_dimension = { | ||
646 | .name = "frag", | ||
647 | .cmp = frag_cmp, | ||
648 | }; | ||
649 | |||
650 | static 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 | |||
659 | static struct sort_dimension pingpong_sort_dimension = { | ||
660 | .name = "pingpong", | ||
661 | .cmp = pingpong_cmp, | ||
662 | }; | ||
663 | |||
664 | static 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 | |||
676 | static 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 | |||
695 | static 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 | |||
487 | static int parse_sort_opt(const struct option *opt __used, | 717 | static 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 | ||
34 | static char const *input_name = "perf.data"; | 35 | static char const *input_name = "perf.data"; |
35 | 36 | ||
@@ -38,7 +39,6 @@ static char *dso_list_str, *comm_list_str, *sym_list_str, | |||
38 | static struct strlist *dso_list, *comm_list, *sym_list; | 39 | static struct strlist *dso_list, *comm_list, *sym_list; |
39 | 40 | ||
40 | static int force; | 41 | static int force; |
41 | static bool use_modules; | ||
42 | 42 | ||
43 | static int full_paths; | 43 | static int full_paths; |
44 | static int show_nr_samples; | 44 | static int show_nr_samples; |
@@ -52,15 +52,13 @@ static char *pretty_printing_style = default_pretty_printing_style; | |||
52 | static int exclude_other = 1; | 52 | static int exclude_other = 1; |
53 | 53 | ||
54 | static char callchain_default_opt[] = "fractal,0.5"; | 54 | static char callchain_default_opt[] = "fractal,0.5"; |
55 | const char *vmlinux_name; | ||
56 | |||
57 | static char *cwd; | ||
58 | static int cwdlen; | ||
59 | 55 | ||
60 | static struct perf_header *header; | 56 | static struct perf_header *header; |
61 | 57 | ||
62 | static u64 sample_type; | 58 | static u64 sample_type; |
63 | 59 | ||
60 | struct symbol_conf symbol_conf; | ||
61 | |||
64 | 62 | ||
65 | static size_t | 63 | static size_t |
66 | callchain__fprintf_left_margin(FILE *fp, int left_margin) | 64 | callchain__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 | ||
463 | static int call__match(struct symbol *sym) | 461 | static 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 | ||
753 | static int | 751 | static int |
754 | process_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 | |||
780 | static int | ||
781 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) | 752 | process_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 | ||
800 | static int | 771 | static int |
801 | process_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 | |||
832 | static int | ||
833 | process_lost_event(event_t *event, unsigned long offset, unsigned long head) | 772 | process_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 | ||
1097 | int cmd_report(int argc, const char **argv, const char *prefix __used) | 1036 | int 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) | |||
225 | static struct sched_atom * | 225 | static struct sched_atom * |
226 | get_new_event(struct task_desc *task, u64 timestamp) | 226 | get_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 | ||
963 | static void thread_atoms_insert(struct thread *thread) | 963 | static 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; | |||
79 | static bool hide_kernel_symbols = false; | 79 | static bool hide_kernel_symbols = false; |
80 | static bool hide_user_symbols = false; | 80 | static bool hide_user_symbols = false; |
81 | static struct winsize winsize; | 81 | static struct winsize winsize; |
82 | const char *vmlinux_name; | 82 | struct symbol_conf symbol_conf; |
83 | 83 | ||
84 | /* | 84 | /* |
85 | * Source | 85 | * Source |
@@ -128,7 +128,7 @@ struct sym_entry { | |||
128 | 128 | ||
129 | static inline struct symbol *sym_entry__symbol(struct sym_entry *self) | 129 | static 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 | ||
134 | static void get_term_dimensions(struct winsize *ws) | 134 | static 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 | ||
1312 | int cmd_top(int argc, const char **argv, const char *prefix __used) | 1297 | int 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 | |||
14 | perf-top mainporcelain common | 14 | perf-top mainporcelain common |
15 | perf-trace mainporcelain common | 15 | perf-trace mainporcelain common |
16 | perf-probe mainporcelain common | 16 | perf-probe mainporcelain common |
17 | perf-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 | ||
102 | int mmap_dispatch_perf_file(struct perf_header **pheader, | 102 | int 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 { | |||
23 | void register_perf_file_handler(struct perf_file_handler *handler); | 23 | void register_perf_file_handler(struct perf_file_handler *handler); |
24 | int mmap_dispatch_perf_file(struct perf_header **pheader, | 24 | int 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); | |||
119 | struct map *map__clone(struct map *self); | 119 | struct map *map__clone(struct map *self); |
120 | int map__overlap(struct map *l, struct map *r); | 120 | int map__overlap(struct map *l, struct map *r); |
121 | size_t map__fprintf(struct map *self, FILE *fp); | 121 | size_t map__fprintf(struct map *self, FILE *fp); |
122 | struct symbol *map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter); | 122 | struct symbol *map__find_function(struct map *self, u64 ip, |
123 | void map__fixup_start(struct map *self); | 123 | symbol_filter_t filter); |
124 | void map__fixup_end(struct map *self); | 124 | void map__fixup_start(struct map *self, struct rb_root *symbols); |
125 | void map__fixup_end(struct map *self, struct rb_root *symbols); | ||
125 | 126 | ||
126 | int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); | 127 | int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); |
127 | void event__synthesize_threads(int (*process)(event_t *event)); | 128 | void 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 | */ |
64 | struct perf_header *perf_header__new(void) | 64 | struct 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 | |||
10 | static inline void set_bit(int nr, unsigned long *addr) | 12 | static 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 | ||
83 | void map__fixup_start(struct map *self) | 83 | void 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 | ||
92 | void map__fixup_end(struct map *self) | 92 | void 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 | ||
103 | struct symbol * | 103 | struct symbol *map__find_function(struct map *self, u64 ip, |
104 | map__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 | ||
142 | struct map *map__clone(struct map *self) | 142 | struct 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 | |||
3 | char *cwd; | ||
4 | int cwdlen; | ||
5 | |||
6 | int | ||
7 | process_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 | |||
34 | int | ||
35 | process_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 | |||
24 | extern char *cwd; | ||
25 | extern int cwdlen; | ||
26 | extern int process_mmap_event(event_t *, unsigned long, unsigned long); | ||
27 | extern 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 | |||
3 | char *cwd; | ||
4 | int cwdlen; | ||
5 | |||
6 | int | ||
7 | process_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 | int | ||
34 | process_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 | |||
29 | extern char *cwd; | ||
30 | extern int cwdlen; | ||
31 | |||
32 | extern int process_mmap_event(event_t *, unsigned long , unsigned long); | ||
33 | extern 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; | |||
37 | static int vmlinux_path__nr_entries; | 38 | static int vmlinux_path__nr_entries; |
38 | static char **vmlinux_path; | 39 | static char **vmlinux_path; |
39 | 40 | ||
41 | static struct symbol_conf symbol_conf__defaults = { | ||
42 | .use_modules = true, | ||
43 | .try_vmlinux_path = true, | ||
44 | }; | ||
45 | |||
40 | static struct rb_root kernel_maps; | 46 | static struct rb_root kernel_maps; |
41 | 47 | ||
42 | static void dso__fixup_sym_end(struct dso *self) | 48 | static 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) | |||
88 | static struct symbol *symbol__new(u64 start, u64 len, const char *name) | 94 | static 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 | ||
153 | static void dso__delete_symbols(struct dso *self) | 158 | static 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 | ||
166 | void dso__delete(struct dso *self) | 171 | void 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 | ||
180 | static void dso__insert_symbol(struct dso *self, struct symbol *sym) | 185 | static 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 | ||
199 | struct symbol *dso__find_symbol(struct dso *self, u64 ip) | 204 | static 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 | ||
227 | struct symbol *dso__find_function(struct dso *self, u64 ip) | ||
228 | { | ||
229 | return symbols__find(&self->functions, ip); | ||
230 | } | ||
231 | |||
222 | int build_id__sprintf(u8 *self, int len, char *bf) | 232 | int 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; |
888 | out_elf_end: | 899 | out_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 | ||
1158 | struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp, | 1169 | struct 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) { |
1427 | out_fixup: | 1440 | out_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 | ||
1488 | static int kernel_maps__create_kernel_map(const char *vmlinux_name) | 1501 | static 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 | ||
1580 | int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, | 1593 | static 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 | ||
1601 | void symbol__init(unsigned int priv_size) | 1617 | int 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 | ||
52 | struct symbol_conf { | ||
53 | unsigned short priv_size; | ||
54 | bool try_vmlinux_path, | ||
55 | use_modules; | ||
56 | const char *vmlinux_name; | ||
57 | }; | ||
58 | |||
52 | extern unsigned int symbol__priv_size; | 59 | extern unsigned int symbol__priv_size; |
53 | 60 | ||
54 | static inline void *symbol__priv(struct symbol *self) | 61 | static inline void *symbol__priv(struct symbol *self) |
@@ -58,8 +65,8 @@ static inline void *symbol__priv(struct symbol *self) | |||
58 | 65 | ||
59 | struct dso { | 66 | struct 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 { | |||
76 | struct dso *dso__new(const char *name); | 83 | struct dso *dso__new(const char *name); |
77 | void dso__delete(struct dso *self); | 84 | void dso__delete(struct dso *self); |
78 | 85 | ||
79 | struct symbol *dso__find_symbol(struct dso *self, u64 ip); | 86 | struct symbol *dso__find_function(struct dso *self, u64 ip); |
80 | 87 | ||
81 | struct dso *dsos__findnew(const char *name); | 88 | struct dso *dsos__findnew(const char *name); |
82 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); | 89 | int 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); | |||
93 | bool dsos__read_build_ids(void); | 100 | bool dsos__read_build_ids(void); |
94 | int build_id__sprintf(u8 *self, int len, char *bf); | 101 | int build_id__sprintf(u8 *self, int len, char *bf); |
95 | 102 | ||
96 | int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, | ||
97 | bool use_modules); | ||
98 | size_t kernel_maps__fprintf(FILE *fp); | 103 | size_t kernel_maps__fprintf(FILE *fp); |
99 | 104 | ||
100 | void symbol__init(unsigned int priv_size); | 105 | int symbol__init(struct symbol_conf *conf); |
101 | 106 | ||
102 | extern struct list_head dsos; | 107 | extern struct list_head dsos; |
103 | extern struct map *kernel_map; | 108 | extern 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 | ||
12 | static struct thread *thread__new(pid_t pid) | 12 | static 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); | |||
26 | void maps__insert(struct rb_root *maps, struct map *map); | 26 | void maps__insert(struct rb_root *maps, struct map *map); |
27 | struct map *maps__find(struct rb_root *maps, u64 ip); | 27 | struct map *maps__find(struct rb_root *maps, u64 ip); |
28 | 28 | ||
29 | struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp, | 29 | struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp, |
30 | symbol_filter_t filter); | 30 | symbol_filter_t filter); |
31 | struct map *kernel_maps__find_by_dso_name(const char *name); | 31 | struct map *kernel_maps__find_by_dso_name(const char *name); |
32 | 32 | ||
33 | static inline struct map *thread__find_map(struct thread *self, u64 ip) | 33 | static 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 | */ |
292 | extern char *xstrdup(const char *str); | 292 | extern char *xstrdup(const char *str); |
293 | extern void *xmalloc(size_t size); | 293 | extern void *xmalloc(size_t size) __attribute__((weak)); |
294 | extern void *xmemdupz(const void *data, size_t len); | 294 | extern void *xmemdupz(const void *data, size_t len); |
295 | extern char *xstrndup(const char *str, size_t len); | 295 | extern char *xstrndup(const char *str, size_t len); |
296 | extern void *xrealloc(void *ptr, size_t size); | 296 | extern void *xrealloc(void *ptr, size_t size) __attribute__((weak)); |
297 | extern void *xcalloc(size_t nmemb, size_t size); | 297 | |
298 | extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); | 298 | static inline void *zalloc(size_t size) |
299 | extern ssize_t xread(int fd, void *buf, size_t len); | 299 | { |
300 | extern ssize_t xwrite(int fd, const void *buf, size_t len); | 300 | return calloc(1, size); |
301 | extern int xdup(int fd); | 301 | } |
302 | extern FILE *xfdopen(int fd, const char *mode); | ||
303 | extern int xmkstemp(char *template); | ||
304 | 302 | ||
305 | static inline size_t xsize_t(off_t len) | 303 | static 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 | ||
82 | void *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 | |||
98 | void *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 | */ |
118 | ssize_t xread(int fd, void *buf, size_t len) | 87 | static 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 | */ |
134 | ssize_t xwrite(int fd, const void *buf, size_t len) | 103 | static 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 | |||
183 | int 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 | |||
191 | FILE *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 | |||
199 | int 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 | } | ||