aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/Documentation/perf-probe.txt4
-rw-r--r--tools/perf/Makefile4
-rw-r--r--tools/perf/builtin-probe.c29
-rw-r--r--tools/perf/builtin-record.c328
-rw-r--r--tools/perf/builtin-report.c29
-rw-r--r--tools/perf/builtin-stat.c39
-rw-r--r--tools/perf/builtin-test.c184
-rw-r--r--tools/perf/builtin-top.c283
-rw-r--r--tools/perf/perf.h26
-rw-r--r--tools/perf/util/callchain.c224
-rw-r--r--tools/perf/util/callchain.h74
-rw-r--r--tools/perf/util/cpumap.c5
-rw-r--r--tools/perf/util/cpumap.h2
-rw-r--r--tools/perf/util/event.c125
-rw-r--r--tools/perf/util/event.h5
-rw-r--r--tools/perf/util/evlist.c170
-rw-r--r--tools/perf/util/evlist.h41
-rw-r--r--tools/perf/util/evsel.c318
-rw-r--r--tools/perf/util/evsel.h33
-rw-r--r--tools/perf/util/header.c17
-rw-r--r--tools/perf/util/header.h7
-rw-r--r--tools/perf/util/hist.c15
-rw-r--r--tools/perf/util/hist.h2
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/parse-events.c71
-rw-r--r--tools/perf/util/parse-events.h7
-rw-r--r--tools/perf/util/probe-event.c68
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-finder.c361
-rw-r--r--tools/perf/util/session.c26
-rw-r--r--tools/perf/util/session.h20
-rw-r--r--tools/perf/util/thread.c55
-rw-r--r--tools/perf/util/thread.h14
-rw-r--r--tools/perf/util/thread_map.c64
-rw-r--r--tools/perf/util/thread_map.h15
-rw-r--r--tools/perf/util/ui/browsers/hists.c2
36 files changed, 1647 insertions, 1022 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 86b797a35aa6..fcc51fe0195c 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -73,6 +73,10 @@ OPTIONS
73 (Only for --vars) Show external defined variables in addition to local 73 (Only for --vars) Show external defined variables in addition to local
74 variables. 74 variables.
75 75
76-F::
77--funcs::
78 Show available functions in given module or kernel.
79
76-f:: 80-f::
77--force:: 81--force::
78 Forcibly add events with existing name. 82 Forcibly add events with existing name.
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7141c42e1469..638e8e146bb9 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -402,6 +402,7 @@ LIB_H += util/debug.h
402LIB_H += util/debugfs.h 402LIB_H += util/debugfs.h
403LIB_H += util/event.h 403LIB_H += util/event.h
404LIB_H += util/evsel.h 404LIB_H += util/evsel.h
405LIB_H += util/evlist.h
405LIB_H += util/exec_cmd.h 406LIB_H += util/exec_cmd.h
406LIB_H += util/types.h 407LIB_H += util/types.h
407LIB_H += util/levenshtein.h 408LIB_H += util/levenshtein.h
@@ -425,6 +426,7 @@ LIB_H += util/values.h
425LIB_H += util/sort.h 426LIB_H += util/sort.h
426LIB_H += util/hist.h 427LIB_H += util/hist.h
427LIB_H += util/thread.h 428LIB_H += util/thread.h
429LIB_H += util/thread_map.h
428LIB_H += util/trace-event.h 430LIB_H += util/trace-event.h
429LIB_H += util/probe-finder.h 431LIB_H += util/probe-finder.h
430LIB_H += util/probe-event.h 432LIB_H += util/probe-event.h
@@ -440,6 +442,7 @@ LIB_OBJS += $(OUTPUT)util/ctype.o
440LIB_OBJS += $(OUTPUT)util/debugfs.o 442LIB_OBJS += $(OUTPUT)util/debugfs.o
441LIB_OBJS += $(OUTPUT)util/environment.o 443LIB_OBJS += $(OUTPUT)util/environment.o
442LIB_OBJS += $(OUTPUT)util/event.o 444LIB_OBJS += $(OUTPUT)util/event.o
445LIB_OBJS += $(OUTPUT)util/evlist.o
443LIB_OBJS += $(OUTPUT)util/evsel.o 446LIB_OBJS += $(OUTPUT)util/evsel.o
444LIB_OBJS += $(OUTPUT)util/exec_cmd.o 447LIB_OBJS += $(OUTPUT)util/exec_cmd.o
445LIB_OBJS += $(OUTPUT)util/help.o 448LIB_OBJS += $(OUTPUT)util/help.o
@@ -469,6 +472,7 @@ LIB_OBJS += $(OUTPUT)util/map.o
469LIB_OBJS += $(OUTPUT)util/pstack.o 472LIB_OBJS += $(OUTPUT)util/pstack.o
470LIB_OBJS += $(OUTPUT)util/session.o 473LIB_OBJS += $(OUTPUT)util/session.o
471LIB_OBJS += $(OUTPUT)util/thread.o 474LIB_OBJS += $(OUTPUT)util/thread.o
475LIB_OBJS += $(OUTPUT)util/thread_map.o
472LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 476LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
473LIB_OBJS += $(OUTPUT)util/trace-event-read.o 477LIB_OBJS += $(OUTPUT)util/trace-event-read.o
474LIB_OBJS += $(OUTPUT)util/trace-event-info.o 478LIB_OBJS += $(OUTPUT)util/trace-event-info.o
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index add163c9f0e7..6cf708aba7c9 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -52,6 +52,7 @@ static struct {
52 bool show_lines; 52 bool show_lines;
53 bool show_vars; 53 bool show_vars;
54 bool show_ext_vars; 54 bool show_ext_vars;
55 bool show_funcs;
55 bool mod_events; 56 bool mod_events;
56 int nevents; 57 int nevents;
57 struct perf_probe_event events[MAX_PROBES]; 58 struct perf_probe_event events[MAX_PROBES];
@@ -221,6 +222,8 @@ static const struct option options[] = {
221 OPT__DRY_RUN(&probe_event_dry_run), 222 OPT__DRY_RUN(&probe_event_dry_run),
222 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 223 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
223 "Set how many probe points can be found for a probe."), 224 "Set how many probe points can be found for a probe."),
225 OPT_BOOLEAN('F', "funcs", &params.show_funcs,
226 "Show potential probe-able functions."),
224 OPT_END() 227 OPT_END()
225}; 228};
226 229
@@ -246,7 +249,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
246 params.max_probe_points = MAX_PROBES; 249 params.max_probe_points = MAX_PROBES;
247 250
248 if ((!params.nevents && !params.dellist && !params.list_events && 251 if ((!params.nevents && !params.dellist && !params.list_events &&
249 !params.show_lines)) 252 !params.show_lines && !params.show_funcs))
250 usage_with_options(probe_usage, options); 253 usage_with_options(probe_usage, options);
251 254
252 /* 255 /*
@@ -267,12 +270,36 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
267 pr_err(" Error: Don't use --list with --vars.\n"); 270 pr_err(" Error: Don't use --list with --vars.\n");
268 usage_with_options(probe_usage, options); 271 usage_with_options(probe_usage, options);
269 } 272 }
273 if (params.show_funcs) {
274 pr_err(" Error: Don't use --list with --funcs.\n");
275 usage_with_options(probe_usage, options);
276 }
270 ret = show_perf_probe_events(); 277 ret = show_perf_probe_events();
271 if (ret < 0) 278 if (ret < 0)
272 pr_err(" Error: Failed to show event list. (%d)\n", 279 pr_err(" Error: Failed to show event list. (%d)\n",
273 ret); 280 ret);
274 return ret; 281 return ret;
275 } 282 }
283 if (params.show_funcs) {
284 if (params.nevents != 0 || params.dellist) {
285 pr_err(" Error: Don't use --funcs with"
286 " --add/--del.\n");
287 usage_with_options(probe_usage, options);
288 }
289 if (params.show_lines) {
290 pr_err(" Error: Don't use --funcs with --line.\n");
291 usage_with_options(probe_usage, options);
292 }
293 if (params.show_vars) {
294 pr_err(" Error: Don't use --funcs with --vars.\n");
295 usage_with_options(probe_usage, options);
296 }
297 ret = show_available_funcs(params.target_module);
298 if (ret < 0)
299 pr_err(" Error: Failed to show functions."
300 " (%d)\n", ret);
301 return ret;
302 }
276 303
277#ifdef DWARF_SUPPORT 304#ifdef DWARF_SUPPORT
278 if (params.show_lines) { 305 if (params.show_lines) {
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index b2f729fdb317..d7886307f6f4 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -18,17 +18,20 @@
18 18
19#include "util/header.h" 19#include "util/header.h"
20#include "util/event.h" 20#include "util/event.h"
21#include "util/evlist.h"
21#include "util/evsel.h" 22#include "util/evsel.h"
22#include "util/debug.h" 23#include "util/debug.h"
23#include "util/session.h" 24#include "util/session.h"
24#include "util/symbol.h" 25#include "util/symbol.h"
25#include "util/cpumap.h" 26#include "util/cpumap.h"
27#include "util/thread_map.h"
26 28
27#include <unistd.h> 29#include <unistd.h>
28#include <sched.h> 30#include <sched.h>
29#include <sys/mman.h> 31#include <sys/mman.h>
30 32
31#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 33#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
34#define SID(e, x, y) xyarray__entry(e->id, x, y)
32 35
33enum write_mode_t { 36enum write_mode_t {
34 WRITE_FORCE, 37 WRITE_FORCE,
@@ -46,7 +49,7 @@ static unsigned int user_freq = UINT_MAX;
46static int freq = 1000; 49static int freq = 1000;
47static int output; 50static int output;
48static int pipe_output = 0; 51static int pipe_output = 0;
49static const char *output_name = "perf.data"; 52static const char *output_name = NULL;
50static int group = 0; 53static int group = 0;
51static int realtime_prio = 0; 54static int realtime_prio = 0;
52static bool nodelay = false; 55static bool nodelay = false;
@@ -66,51 +69,17 @@ static bool sample_address = false;
66static bool sample_time = false; 69static bool sample_time = false;
67static bool no_buildid = false; 70static bool no_buildid = false;
68static bool no_buildid_cache = false; 71static bool no_buildid_cache = false;
72static struct perf_evlist *evsel_list;
69 73
70static long samples = 0; 74static long samples = 0;
71static u64 bytes_written = 0; 75static u64 bytes_written = 0;
72 76
73static struct pollfd *event_array;
74
75static int nr_poll = 0;
76static int nr_cpu = 0;
77
78static int file_new = 1; 77static int file_new = 1;
79static off_t post_processing_offset; 78static off_t post_processing_offset;
80 79
81static struct perf_session *session; 80static struct perf_session *session;
82static const char *cpu_list; 81static const char *cpu_list;
83 82
84struct mmap_data {
85 void *base;
86 unsigned int mask;
87 unsigned int prev;
88};
89
90static struct mmap_data mmap_array[MAX_NR_CPUS];
91
92static unsigned long mmap_read_head(struct mmap_data *md)
93{
94 struct perf_event_mmap_page *pc = md->base;
95 long head;
96
97 head = pc->data_head;
98 rmb();
99
100 return head;
101}
102
103static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
104{
105 struct perf_event_mmap_page *pc = md->base;
106
107 /*
108 * ensure all reads are done before we write the tail out.
109 */
110 /* mb(); */
111 pc->data_tail = tail;
112}
113
114static void advance_output(size_t size) 83static void advance_output(size_t size)
115{ 84{
116 bytes_written += size; 85 bytes_written += size;
@@ -139,9 +108,9 @@ static int process_synthesized_event(event_t *event,
139 return 0; 108 return 0;
140} 109}
141 110
142static void mmap_read(struct mmap_data *md) 111static void mmap_read(struct perf_mmap *md)
143{ 112{
144 unsigned int head = mmap_read_head(md); 113 unsigned int head = perf_mmap__read_head(md);
145 unsigned int old = md->prev; 114 unsigned int old = md->prev;
146 unsigned char *data = md->base + page_size; 115 unsigned char *data = md->base + page_size;
147 unsigned long size; 116 unsigned long size;
@@ -185,7 +154,7 @@ static void mmap_read(struct mmap_data *md)
185 write_output(buf, size); 154 write_output(buf, size);
186 155
187 md->prev = old; 156 md->prev = old;
188 mmap_write_tail(md, old); 157 perf_mmap__write_tail(md, old);
189} 158}
190 159
191static volatile int done = 0; 160static volatile int done = 0;
@@ -209,8 +178,6 @@ static void sig_atexit(void)
209 kill(getpid(), signr); 178 kill(getpid(), signr);
210} 179}
211 180
212static int group_fd;
213
214static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) 181static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
215{ 182{
216 struct perf_header_attr *h_attr; 183 struct perf_header_attr *h_attr;
@@ -234,28 +201,47 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
234 char *filter = evsel->filter; 201 char *filter = evsel->filter;
235 struct perf_event_attr *attr = &evsel->attr; 202 struct perf_event_attr *attr = &evsel->attr;
236 struct perf_header_attr *h_attr; 203 struct perf_header_attr *h_attr;
237 int track = !evsel->idx; /* only the first counter needs these */ 204 struct perf_sample_id *sid;
238 int thread_index; 205 int thread_index;
239 int ret; 206 int ret;
240 struct { 207
241 u64 count; 208 for (thread_index = 0; thread_index < threads->nr; thread_index++) {
242 u64 time_enabled; 209 h_attr = get_header_attr(attr, evsel->idx);
243 u64 time_running; 210 if (h_attr == NULL)
244 u64 id; 211 die("nomem\n");
245 } read_data; 212
246 /* 213 if (!file_new) {
247 * Check if parse_single_tracepoint_event has already asked for 214 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
248 * PERF_SAMPLE_TIME. 215 fprintf(stderr, "incompatible append\n");
249 * 216 exit(-1);
250 * XXX this is kludgy but short term fix for problems introduced by 217 }
251 * eac23d1c that broke 'perf script' by having different sample_types 218 }
252 * when using multiple tracepoint events when we use a perf binary 219
253 * that tries to use sample_id_all on an older kernel. 220 sid = SID(evsel, cpu, thread_index);
254 * 221 if (perf_header_attr__add_id(h_attr, sid->id) < 0) {
255 * We need to move counter creation to perf_session, support 222 pr_warning("Not enough memory to add id\n");
256 * different sample_types, etc. 223 exit(-1);
257 */ 224 }
258 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; 225
226 if (filter != NULL) {
227 ret = ioctl(FD(evsel, cpu, thread_index),
228 PERF_EVENT_IOC_SET_FILTER, filter);
229 if (ret) {
230 error("failed to set filter with %d (%s)\n", errno,
231 strerror(errno));
232 exit(-1);
233 }
234 }
235 }
236
237 if (!sample_type)
238 sample_type = attr->sample_type;
239}
240
241static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
242{
243 struct perf_event_attr *attr = &evsel->attr;
244 int track = !evsel->idx; /* only the first counter needs these */
259 245
260 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 246 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
261 PERF_FORMAT_TOTAL_TIME_RUNNING | 247 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -263,7 +249,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
263 249
264 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 250 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
265 251
266 if (nr_counters > 1) 252 if (evlist->nr_entries > 1)
267 attr->sample_type |= PERF_SAMPLE_ID; 253 attr->sample_type |= PERF_SAMPLE_ID;
268 254
269 /* 255 /*
@@ -315,19 +301,39 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
315 301
316 attr->mmap = track; 302 attr->mmap = track;
317 attr->comm = track; 303 attr->comm = track;
318 attr->inherit = !no_inherit; 304
319 if (target_pid == -1 && target_tid == -1 && !system_wide) { 305 if (target_pid == -1 && target_tid == -1 && !system_wide) {
320 attr->disabled = 1; 306 attr->disabled = 1;
321 attr->enable_on_exec = 1; 307 attr->enable_on_exec = 1;
322 } 308 }
323retry_sample_id: 309}
324 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
325 310
326 for (thread_index = 0; thread_index < threads->nr; thread_index++) { 311static void open_counters(struct perf_evlist *evlist)
327try_again: 312{
328 FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); 313 struct perf_evsel *pos;
314 int cpu;
329 315
330 if (FD(evsel, nr_cpu, thread_index) < 0) { 316 list_for_each_entry(pos, &evlist->entries, node) {
317 struct perf_event_attr *attr = &pos->attr;
318 /*
319 * Check if parse_single_tracepoint_event has already asked for
320 * PERF_SAMPLE_TIME.
321 *
322 * XXX this is kludgy but short term fix for problems introduced by
323 * eac23d1c that broke 'perf script' by having different sample_types
324 * when using multiple tracepoint events when we use a perf binary
325 * that tries to use sample_id_all on an older kernel.
326 *
327 * We need to move counter creation to perf_session, support
328 * different sample_types, etc.
329 */
330 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
331
332 config_attr(pos, evlist);
333retry_sample_id:
334 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
335try_again:
336 if (perf_evsel__open(pos, cpus, threads, group, !no_inherit) < 0) {
331 int err = errno; 337 int err = errno;
332 338
333 if (err == EPERM || err == EACCES) 339 if (err == EPERM || err == EACCES)
@@ -364,7 +370,7 @@ try_again:
364 } 370 }
365 printf("\n"); 371 printf("\n");
366 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 372 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
367 FD(evsel, nr_cpu, thread_index), strerror(err)); 373 err, strerror(err));
368 374
369#if defined(__i386__) || defined(__x86_64__) 375#if defined(__i386__) || defined(__x86_64__)
370 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 376 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -375,90 +381,16 @@ try_again:
375#endif 381#endif
376 382
377 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 383 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
378 exit(-1);
379 }
380
381 h_attr = get_header_attr(attr, evsel->idx);
382 if (h_attr == NULL)
383 die("nomem\n");
384
385 if (!file_new) {
386 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
387 fprintf(stderr, "incompatible append\n");
388 exit(-1);
389 }
390 }
391
392 if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
393 perror("Unable to read perf file descriptor");
394 exit(-1);
395 }
396
397 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
398 pr_warning("Not enough memory to add id\n");
399 exit(-1);
400 }
401
402 assert(FD(evsel, nr_cpu, thread_index) >= 0);
403 fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK);
404
405 /*
406 * First counter acts as the group leader:
407 */
408 if (group && group_fd == -1)
409 group_fd = FD(evsel, nr_cpu, thread_index);
410
411 if (evsel->idx || thread_index) {
412 struct perf_evsel *first;
413 first = list_entry(evsel_list.next, struct perf_evsel, node);
414 ret = ioctl(FD(evsel, nr_cpu, thread_index),
415 PERF_EVENT_IOC_SET_OUTPUT,
416 FD(first, nr_cpu, 0));
417 if (ret) {
418 error("failed to set output: %d (%s)\n", errno,
419 strerror(errno));
420 exit(-1);
421 }
422 } else {
423 mmap_array[nr_cpu].prev = 0;
424 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
425 mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
426 PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0);
427 if (mmap_array[nr_cpu].base == MAP_FAILED) {
428 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
429 exit(-1);
430 }
431
432 event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index);
433 event_array[nr_poll].events = POLLIN;
434 nr_poll++;
435 }
436
437 if (filter != NULL) {
438 ret = ioctl(FD(evsel, nr_cpu, thread_index),
439 PERF_EVENT_IOC_SET_FILTER, filter);
440 if (ret) {
441 error("failed to set filter with %d (%s)\n", errno,
442 strerror(errno));
443 exit(-1);
444 }
445 } 384 }
446 } 385 }
447 386
448 if (!sample_type) 387 if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, false) < 0)
449 sample_type = attr->sample_type; 388 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
450}
451
452static void open_counters(int cpu)
453{
454 struct perf_evsel *pos;
455
456 group_fd = -1;
457
458 list_for_each_entry(pos, &evsel_list, node)
459 create_counter(pos, cpu);
460 389
461 nr_cpu++; 390 for (cpu = 0; cpu < cpus->nr; ++cpu) {
391 list_for_each_entry(pos, &evlist->entries, node)
392 create_counter(pos, cpu);
393 }
462} 394}
463 395
464static int process_buildids(void) 396static int process_buildids(void)
@@ -481,9 +413,9 @@ static void atexit_header(void)
481 413
482 if (!no_buildid) 414 if (!no_buildid)
483 process_buildids(); 415 process_buildids();
484 perf_header__write(&session->header, output, true); 416 perf_header__write(&session->header, evsel_list, output, true);
485 perf_session__delete(session); 417 perf_session__delete(session);
486 perf_evsel_list__delete(); 418 perf_evlist__delete(evsel_list);
487 symbol__exit(); 419 symbol__exit();
488 } 420 }
489} 421}
@@ -533,9 +465,9 @@ static void mmap_read_all(void)
533{ 465{
534 int i; 466 int i;
535 467
536 for (i = 0; i < nr_cpu; i++) { 468 for (i = 0; i < cpus->nr; i++) {
537 if (mmap_array[i].base) 469 if (evsel_list->mmap[i].base)
538 mmap_read(&mmap_array[i]); 470 mmap_read(&evsel_list->mmap[i]);
539 } 471 }
540 472
541 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) 473 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
@@ -566,18 +498,26 @@ static int __cmd_record(int argc, const char **argv)
566 exit(-1); 498 exit(-1);
567 } 499 }
568 500
569 if (!strcmp(output_name, "-")) 501 if (!output_name) {
570 pipe_output = 1; 502 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
571 else if (!stat(output_name, &st) && st.st_size) { 503 pipe_output = 1;
572 if (write_mode == WRITE_FORCE) { 504 else
573 char oldname[PATH_MAX]; 505 output_name = "perf.data";
574 snprintf(oldname, sizeof(oldname), "%s.old", 506 }
575 output_name); 507 if (output_name) {
576 unlink(oldname); 508 if (!strcmp(output_name, "-"))
577 rename(output_name, oldname); 509 pipe_output = 1;
510 else if (!stat(output_name, &st) && st.st_size) {
511 if (write_mode == WRITE_FORCE) {
512 char oldname[PATH_MAX];
513 snprintf(oldname, sizeof(oldname), "%s.old",
514 output_name);
515 unlink(oldname);
516 rename(output_name, oldname);
517 }
518 } else if (write_mode == WRITE_APPEND) {
519 write_mode = WRITE_FORCE;
578 } 520 }
579 } else if (write_mode == WRITE_APPEND) {
580 write_mode = WRITE_FORCE;
581 } 521 }
582 522
583 flags = O_CREAT|O_RDWR; 523 flags = O_CREAT|O_RDWR;
@@ -611,7 +551,7 @@ static int __cmd_record(int argc, const char **argv)
611 goto out_delete_session; 551 goto out_delete_session;
612 } 552 }
613 553
614 if (have_tracepoints(&evsel_list)) 554 if (have_tracepoints(&evsel_list->entries))
615 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 555 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
616 556
617 /* 557 /*
@@ -673,12 +613,7 @@ static int __cmd_record(int argc, const char **argv)
673 close(child_ready_pipe[0]); 613 close(child_ready_pipe[0]);
674 } 614 }
675 615
676 if (!system_wide && no_inherit && !cpu_list) { 616 open_counters(evsel_list);
677 open_counters(-1);
678 } else {
679 for (i = 0; i < cpus->nr; i++)
680 open_counters(cpus->map[i]);
681 }
682 617
683 perf_session__set_sample_type(session, sample_type); 618 perf_session__set_sample_type(session, sample_type);
684 619
@@ -687,7 +622,8 @@ static int __cmd_record(int argc, const char **argv)
687 if (err < 0) 622 if (err < 0)
688 return err; 623 return err;
689 } else if (file_new) { 624 } else if (file_new) {
690 err = perf_header__write(&session->header, output, false); 625 err = perf_header__write(&session->header, evsel_list,
626 output, false);
691 if (err < 0) 627 if (err < 0)
692 return err; 628 return err;
693 } 629 }
@@ -712,7 +648,7 @@ static int __cmd_record(int argc, const char **argv)
712 return err; 648 return err;
713 } 649 }
714 650
715 if (have_tracepoints(&evsel_list)) { 651 if (have_tracepoints(&evsel_list->entries)) {
716 /* 652 /*
717 * FIXME err <= 0 here actually means that 653 * FIXME err <= 0 here actually means that
718 * there were no tracepoints so its not really 654 * there were no tracepoints so its not really
@@ -721,7 +657,7 @@ static int __cmd_record(int argc, const char **argv)
721 * return this more properly and also 657 * return this more properly and also
722 * propagate errors that now are calling die() 658 * propagate errors that now are calling die()
723 */ 659 */
724 err = event__synthesize_tracing_data(output, &evsel_list, 660 err = event__synthesize_tracing_data(output, evsel_list,
725 process_synthesized_event, 661 process_synthesized_event,
726 session); 662 session);
727 if (err <= 0) { 663 if (err <= 0) {
@@ -789,15 +725,15 @@ static int __cmd_record(int argc, const char **argv)
789 if (hits == samples) { 725 if (hits == samples) {
790 if (done) 726 if (done)
791 break; 727 break;
792 err = poll(event_array, nr_poll, -1); 728 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
793 waking++; 729 waking++;
794 } 730 }
795 731
796 if (done) { 732 if (done) {
797 for (i = 0; i < nr_cpu; i++) { 733 for (i = 0; i < cpus->nr; i++) {
798 struct perf_evsel *pos; 734 struct perf_evsel *pos;
799 735
800 list_for_each_entry(pos, &evsel_list, node) { 736 list_for_each_entry(pos, &evsel_list->entries, node) {
801 for (thread = 0; 737 for (thread = 0;
802 thread < threads->nr; 738 thread < threads->nr;
803 thread++) 739 thread++)
@@ -838,10 +774,10 @@ static const char * const record_usage[] = {
838static bool force, append_file; 774static bool force, append_file;
839 775
840const struct option record_options[] = { 776const struct option record_options[] = {
841 OPT_CALLBACK('e', "event", NULL, "event", 777 OPT_CALLBACK('e', "event", &evsel_list, "event",
842 "event selector. use 'perf list' to list available events", 778 "event selector. use 'perf list' to list available events",
843 parse_events), 779 parse_events),
844 OPT_CALLBACK(0, "filter", NULL, "filter", 780 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
845 "event filter", parse_filter), 781 "event filter", parse_filter),
846 OPT_INTEGER('p', "pid", &target_pid, 782 OPT_INTEGER('p', "pid", &target_pid,
847 "record events on existing process id"), 783 "record events on existing process id"),
@@ -892,6 +828,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
892 int err = -ENOMEM; 828 int err = -ENOMEM;
893 struct perf_evsel *pos; 829 struct perf_evsel *pos;
894 830
831 evsel_list = perf_evlist__new();
832 if (evsel_list == NULL)
833 return -ENOMEM;
834
895 argc = parse_options(argc, argv, record_options, record_usage, 835 argc = parse_options(argc, argv, record_options, record_usage,
896 PARSE_OPT_STOP_AT_NON_OPTION); 836 PARSE_OPT_STOP_AT_NON_OPTION);
897 if (!argc && target_pid == -1 && target_tid == -1 && 837 if (!argc && target_pid == -1 && target_tid == -1 &&
@@ -913,7 +853,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
913 if (no_buildid_cache || no_buildid) 853 if (no_buildid_cache || no_buildid)
914 disable_buildid_cache(); 854 disable_buildid_cache();
915 855
916 if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { 856 if (evsel_list->nr_entries == 0 &&
857 perf_evlist__add_default(evsel_list) < 0) {
917 pr_err("Not enough memory for event selector list\n"); 858 pr_err("Not enough memory for event selector list\n");
918 goto out_symbol_exit; 859 goto out_symbol_exit;
919 } 860 }
@@ -927,21 +868,22 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
927 usage_with_options(record_usage, record_options); 868 usage_with_options(record_usage, record_options);
928 } 869 }
929 870
930 cpus = cpu_map__new(cpu_list); 871 if (target_tid != -1)
931 if (cpus == NULL) { 872 cpus = cpu_map__dummy_new();
932 perror("failed to parse CPUs map"); 873 else
933 return -1; 874 cpus = cpu_map__new(cpu_list);
934 }
935 875
936 list_for_each_entry(pos, &evsel_list, node) { 876 if (cpus == NULL)
877 usage_with_options(record_usage, record_options);
878
879 list_for_each_entry(pos, &evsel_list->entries, node) {
937 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) 880 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
938 goto out_free_fd; 881 goto out_free_fd;
939 if (perf_header__push_event(pos->attr.config, event_name(pos))) 882 if (perf_header__push_event(pos->attr.config, event_name(pos)))
940 goto out_free_fd; 883 goto out_free_fd;
941 } 884 }
942 event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * 885
943 MAX_COUNTERS * threads->nr)); 886 if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0)
944 if (!event_array)
945 goto out_free_fd; 887 goto out_free_fd;
946 888
947 if (user_interval != ULLONG_MAX) 889 if (user_interval != ULLONG_MAX)
@@ -959,13 +901,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
959 } else { 901 } else {
960 fprintf(stderr, "frequency and count are zero, aborting\n"); 902 fprintf(stderr, "frequency and count are zero, aborting\n");
961 err = -EINVAL; 903 err = -EINVAL;
962 goto out_free_event_array; 904 goto out_free_fd;
963 } 905 }
964 906
965 err = __cmd_record(argc, argv); 907 err = __cmd_record(argc, argv);
966 908
967out_free_event_array:
968 free(event_array);
969out_free_fd: 909out_free_fd:
970 thread_map__delete(threads); 910 thread_map__delete(threads);
971 threads = NULL; 911 threads = NULL;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index c27e31f289e6..f6a43493d1d0 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -81,18 +81,17 @@ static int perf_session__add_hist_entry(struct perf_session *self,
81 struct addr_location *al, 81 struct addr_location *al,
82 struct sample_data *data) 82 struct sample_data *data)
83{ 83{
84 struct map_symbol *syms = NULL;
85 struct symbol *parent = NULL; 84 struct symbol *parent = NULL;
86 int err = -ENOMEM; 85 int err = 0;
87 struct hist_entry *he; 86 struct hist_entry *he;
88 struct hists *hists; 87 struct hists *hists;
89 struct perf_event_attr *attr; 88 struct perf_event_attr *attr;
90 89
91 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { 90 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
92 syms = perf_session__resolve_callchain(self, al->thread, 91 err = perf_session__resolve_callchain(self, al->thread,
93 data->callchain, &parent); 92 data->callchain, &parent);
94 if (syms == NULL) 93 if (err)
95 return -ENOMEM; 94 return err;
96 } 95 }
97 96
98 attr = perf_header__find_attr(data->id, &self->header); 97 attr = perf_header__find_attr(data->id, &self->header);
@@ -101,16 +100,17 @@ static int perf_session__add_hist_entry(struct perf_session *self,
101 else 100 else
102 hists = perf_session__hists_findnew(self, data->id, 0, 0); 101 hists = perf_session__hists_findnew(self, data->id, 0, 0);
103 if (hists == NULL) 102 if (hists == NULL)
104 goto out_free_syms; 103 return -ENOMEM;
104
105 he = __hists__add_entry(hists, al, parent, data->period); 105 he = __hists__add_entry(hists, al, parent, data->period);
106 if (he == NULL) 106 if (he == NULL)
107 goto out_free_syms; 107 return -ENOMEM;
108 err = 0; 108
109 if (symbol_conf.use_callchain) { 109 if (symbol_conf.use_callchain) {
110 err = callchain_append(he->callchain, data->callchain, syms, 110 err = callchain_append(he->callchain, &self->callchain_cursor,
111 data->period); 111 data->period);
112 if (err) 112 if (err)
113 goto out_free_syms; 113 return err;
114 } 114 }
115 /* 115 /*
116 * Only in the newt browser we are doing integrated annotation, 116 * Only in the newt browser we are doing integrated annotation,
@@ -119,8 +119,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
119 */ 119 */
120 if (use_browser > 0) 120 if (use_browser > 0)
121 err = hist_entry__inc_addr_samples(he, al->addr); 121 err = hist_entry__inc_addr_samples(he, al->addr);
122out_free_syms: 122
123 free(syms);
124 return err; 123 return err;
125} 124}
126 125
@@ -222,7 +221,7 @@ static int perf_session__setup_sample_type(struct perf_session *self)
222 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 221 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
223 !symbol_conf.use_callchain) { 222 !symbol_conf.use_callchain) {
224 symbol_conf.use_callchain = true; 223 symbol_conf.use_callchain = true;
225 if (register_callchain_param(&callchain_param) < 0) { 224 if (callchain_register_param(&callchain_param) < 0) {
226 fprintf(stderr, "Can't register callchain" 225 fprintf(stderr, "Can't register callchain"
227 " params\n"); 226 " params\n");
228 return -EINVAL; 227 return -EINVAL;
@@ -424,7 +423,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
424 if (tok2) 423 if (tok2)
425 callchain_param.print_limit = strtod(tok2, &endptr); 424 callchain_param.print_limit = strtod(tok2, &endptr);
426setup: 425setup:
427 if (register_callchain_param(&callchain_param) < 0) { 426 if (callchain_register_param(&callchain_param) < 0) {
428 fprintf(stderr, "Can't register callchain params\n"); 427 fprintf(stderr, "Can't register callchain params\n");
429 return -1; 428 return -1;
430 } 429 }
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a482a191a0ca..8906adfdbd8e 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -43,11 +43,13 @@
43#include "util/parse-options.h" 43#include "util/parse-options.h"
44#include "util/parse-events.h" 44#include "util/parse-events.h"
45#include "util/event.h" 45#include "util/event.h"
46#include "util/evlist.h"
46#include "util/evsel.h" 47#include "util/evsel.h"
47#include "util/debug.h" 48#include "util/debug.h"
48#include "util/header.h" 49#include "util/header.h"
49#include "util/cpumap.h" 50#include "util/cpumap.h"
50#include "util/thread.h" 51#include "util/thread.h"
52#include "util/thread_map.h"
51 53
52#include <sys/prctl.h> 54#include <sys/prctl.h>
53#include <math.h> 55#include <math.h>
@@ -71,6 +73,8 @@ static struct perf_event_attr default_attrs[] = {
71 73
72}; 74};
73 75
76struct perf_evlist *evsel_list;
77
74static bool system_wide = false; 78static bool system_wide = false;
75static struct cpu_map *cpus; 79static struct cpu_map *cpus;
76static int run_idx = 0; 80static int run_idx = 0;
@@ -166,7 +170,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
166 PERF_FORMAT_TOTAL_TIME_RUNNING; 170 PERF_FORMAT_TOTAL_TIME_RUNNING;
167 171
168 if (system_wide) 172 if (system_wide)
169 return perf_evsel__open_per_cpu(evsel, cpus); 173 return perf_evsel__open_per_cpu(evsel, cpus, false, false);
170 174
171 attr->inherit = !no_inherit; 175 attr->inherit = !no_inherit;
172 if (target_pid == -1 && target_tid == -1) { 176 if (target_pid == -1 && target_tid == -1) {
@@ -174,7 +178,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
174 attr->enable_on_exec = 1; 178 attr->enable_on_exec = 1;
175 } 179 }
176 180
177 return perf_evsel__open_per_thread(evsel, threads); 181 return perf_evsel__open_per_thread(evsel, threads, false, false);
178} 182}
179 183
180/* 184/*
@@ -309,7 +313,7 @@ static int run_perf_stat(int argc __used, const char **argv)
309 close(child_ready_pipe[0]); 313 close(child_ready_pipe[0]);
310 } 314 }
311 315
312 list_for_each_entry(counter, &evsel_list, node) { 316 list_for_each_entry(counter, &evsel_list->entries, node) {
313 if (create_perf_stat_counter(counter) < 0) { 317 if (create_perf_stat_counter(counter) < 0) {
314 if (errno == -EPERM || errno == -EACCES) { 318 if (errno == -EPERM || errno == -EACCES) {
315 error("You may not have permission to collect %sstats.\n" 319 error("You may not have permission to collect %sstats.\n"
@@ -347,12 +351,12 @@ static int run_perf_stat(int argc __used, const char **argv)
347 update_stats(&walltime_nsecs_stats, t1 - t0); 351 update_stats(&walltime_nsecs_stats, t1 - t0);
348 352
349 if (no_aggr) { 353 if (no_aggr) {
350 list_for_each_entry(counter, &evsel_list, node) { 354 list_for_each_entry(counter, &evsel_list->entries, node) {
351 read_counter(counter); 355 read_counter(counter);
352 perf_evsel__close_fd(counter, cpus->nr, 1); 356 perf_evsel__close_fd(counter, cpus->nr, 1);
353 } 357 }
354 } else { 358 } else {
355 list_for_each_entry(counter, &evsel_list, node) { 359 list_for_each_entry(counter, &evsel_list->entries, node) {
356 read_counter_aggr(counter); 360 read_counter_aggr(counter);
357 perf_evsel__close_fd(counter, cpus->nr, threads->nr); 361 perf_evsel__close_fd(counter, cpus->nr, threads->nr);
358 } 362 }
@@ -555,10 +559,10 @@ static void print_stat(int argc, const char **argv)
555 } 559 }
556 560
557 if (no_aggr) { 561 if (no_aggr) {
558 list_for_each_entry(counter, &evsel_list, node) 562 list_for_each_entry(counter, &evsel_list->entries, node)
559 print_counter(counter); 563 print_counter(counter);
560 } else { 564 } else {
561 list_for_each_entry(counter, &evsel_list, node) 565 list_for_each_entry(counter, &evsel_list->entries, node)
562 print_counter_aggr(counter); 566 print_counter_aggr(counter);
563 } 567 }
564 568
@@ -610,7 +614,7 @@ static int stat__set_big_num(const struct option *opt __used,
610} 614}
611 615
612static const struct option options[] = { 616static const struct option options[] = {
613 OPT_CALLBACK('e', "event", NULL, "event", 617 OPT_CALLBACK('e', "event", &evsel_list, "event",
614 "event selector. use 'perf list' to list available events", 618 "event selector. use 'perf list' to list available events",
615 parse_events), 619 parse_events),
616 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 620 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
@@ -648,6 +652,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
648 652
649 setlocale(LC_ALL, ""); 653 setlocale(LC_ALL, "");
650 654
655 evsel_list = perf_evlist__new();
656 if (evsel_list == NULL)
657 return -ENOMEM;
658
651 argc = parse_options(argc, argv, options, stat_usage, 659 argc = parse_options(argc, argv, options, stat_usage,
652 PARSE_OPT_STOP_AT_NON_OPTION); 660 PARSE_OPT_STOP_AT_NON_OPTION);
653 661
@@ -679,17 +687,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
679 usage_with_options(stat_usage, options); 687 usage_with_options(stat_usage, options);
680 688
681 /* Set attrs and nr_counters if no event is selected and !null_run */ 689 /* Set attrs and nr_counters if no event is selected and !null_run */
682 if (!null_run && !nr_counters) { 690 if (!null_run && !evsel_list->nr_entries) {
683 size_t c; 691 size_t c;
684 692
685 nr_counters = ARRAY_SIZE(default_attrs);
686
687 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { 693 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) {
688 pos = perf_evsel__new(&default_attrs[c], 694 pos = perf_evsel__new(&default_attrs[c], c);
689 nr_counters);
690 if (pos == NULL) 695 if (pos == NULL)
691 goto out; 696 goto out;
692 list_add(&pos->node, &evsel_list); 697 perf_evlist__add(evsel_list, pos);
693 } 698 }
694 } 699 }
695 700
@@ -713,7 +718,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
713 return -1; 718 return -1;
714 } 719 }
715 720
716 list_for_each_entry(pos, &evsel_list, node) { 721 list_for_each_entry(pos, &evsel_list->entries, node) {
717 if (perf_evsel__alloc_stat_priv(pos) < 0 || 722 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
718 perf_evsel__alloc_counts(pos, cpus->nr) < 0 || 723 perf_evsel__alloc_counts(pos, cpus->nr) < 0 ||
719 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) 724 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
@@ -741,9 +746,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
741 if (status != -1) 746 if (status != -1)
742 print_stat(argc, argv); 747 print_stat(argc, argv);
743out_free_fd: 748out_free_fd:
744 list_for_each_entry(pos, &evsel_list, node) 749 list_for_each_entry(pos, &evsel_list->entries, node)
745 perf_evsel__free_stat_priv(pos); 750 perf_evsel__free_stat_priv(pos);
746 perf_evsel_list__delete(); 751 perf_evlist__delete(evsel_list);
747out: 752out:
748 thread_map__delete(threads); 753 thread_map__delete(threads);
749 threads = NULL; 754 threads = NULL;
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 5dcdba653d70..231e3e21810c 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -7,10 +7,11 @@
7 7
8#include "util/cache.h" 8#include "util/cache.h"
9#include "util/debug.h" 9#include "util/debug.h"
10#include "util/evlist.h"
10#include "util/parse-options.h" 11#include "util/parse-options.h"
11#include "util/session.h" 12#include "util/parse-events.h"
12#include "util/symbol.h" 13#include "util/symbol.h"
13#include "util/thread.h" 14#include "util/thread_map.h"
14 15
15static long page_size; 16static long page_size;
16 17
@@ -238,14 +239,14 @@ out:
238#include "util/evsel.h" 239#include "util/evsel.h"
239#include <sys/types.h> 240#include <sys/types.h>
240 241
241static int trace_event__id(const char *event_name) 242static int trace_event__id(const char *evname)
242{ 243{
243 char *filename; 244 char *filename;
244 int err = -1, fd; 245 int err = -1, fd;
245 246
246 if (asprintf(&filename, 247 if (asprintf(&filename,
247 "/sys/kernel/debug/tracing/events/syscalls/%s/id", 248 "/sys/kernel/debug/tracing/events/syscalls/%s/id",
248 event_name) < 0) 249 evname) < 0)
249 return -1; 250 return -1;
250 251
251 fd = open(filename, O_RDONLY); 252 fd = open(filename, O_RDONLY);
@@ -289,7 +290,7 @@ static int test__open_syscall_event(void)
289 goto out_thread_map_delete; 290 goto out_thread_map_delete;
290 } 291 }
291 292
292 if (perf_evsel__open_per_thread(evsel, threads) < 0) { 293 if (perf_evsel__open_per_thread(evsel, threads, false, false) < 0) {
293 pr_debug("failed to open counter: %s, " 294 pr_debug("failed to open counter: %s, "
294 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 295 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
295 strerror(errno)); 296 strerror(errno));
@@ -347,9 +348,9 @@ static int test__open_syscall_event_on_all_cpus(void)
347 } 348 }
348 349
349 cpus = cpu_map__new(NULL); 350 cpus = cpu_map__new(NULL);
350 if (threads == NULL) { 351 if (cpus == NULL) {
351 pr_debug("thread_map__new\n"); 352 pr_debug("cpu_map__new\n");
352 return -1; 353 goto out_thread_map_delete;
353 } 354 }
354 355
355 356
@@ -364,7 +365,7 @@ static int test__open_syscall_event_on_all_cpus(void)
364 goto out_thread_map_delete; 365 goto out_thread_map_delete;
365 } 366 }
366 367
367 if (perf_evsel__open(evsel, cpus, threads) < 0) { 368 if (perf_evsel__open(evsel, cpus, threads, false, false) < 0) {
368 pr_debug("failed to open counter: %s, " 369 pr_debug("failed to open counter: %s, "
369 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 370 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
370 strerror(errno)); 371 strerror(errno));
@@ -408,6 +409,8 @@ static int test__open_syscall_event_on_all_cpus(void)
408 goto out_close_fd; 409 goto out_close_fd;
409 } 410 }
410 411
412 err = 0;
413
411 for (cpu = 0; cpu < cpus->nr; ++cpu) { 414 for (cpu = 0; cpu < cpus->nr; ++cpu) {
412 unsigned int expected; 415 unsigned int expected;
413 416
@@ -416,18 +419,18 @@ static int test__open_syscall_event_on_all_cpus(void)
416 419
417 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { 420 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
418 pr_debug("perf_evsel__open_read_on_cpu\n"); 421 pr_debug("perf_evsel__open_read_on_cpu\n");
419 goto out_close_fd; 422 err = -1;
423 break;
420 } 424 }
421 425
422 expected = nr_open_calls + cpu; 426 expected = nr_open_calls + cpu;
423 if (evsel->counts->cpu[cpu].val != expected) { 427 if (evsel->counts->cpu[cpu].val != expected) {
424 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n", 428 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
425 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val); 429 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
426 goto out_close_fd; 430 err = -1;
427 } 431 }
428 } 432 }
429 433
430 err = 0;
431out_close_fd: 434out_close_fd:
432 perf_evsel__close_fd(evsel, 1, threads->nr); 435 perf_evsel__close_fd(evsel, 1, threads->nr);
433out_evsel_delete: 436out_evsel_delete:
@@ -437,6 +440,159 @@ out_thread_map_delete:
437 return err; 440 return err;
438} 441}
439 442
443/*
444 * This test will generate random numbers of calls to some getpid syscalls,
445 * then establish an mmap for a group of events that are created to monitor
446 * the syscalls.
447 *
448 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
449 * sample.id field to map back to its respective perf_evsel instance.
450 *
451 * Then it checks if the number of syscalls reported as perf events by
452 * the kernel corresponds to the number of syscalls made.
453 */
454static int test__basic_mmap(void)
455{
456 int err = -1;
457 event_t *event;
458 struct thread_map *threads;
459 struct cpu_map *cpus;
460 struct perf_evlist *evlist;
461 struct perf_event_attr attr = {
462 .type = PERF_TYPE_TRACEPOINT,
463 .read_format = PERF_FORMAT_ID,
464 .sample_type = PERF_SAMPLE_ID,
465 .watermark = 0,
466 };
467 cpu_set_t cpu_set;
468 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
469 "getpgid", };
470 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
471 (void*)getpgid };
472#define nsyscalls ARRAY_SIZE(syscall_names)
473 int ids[nsyscalls];
474 unsigned int nr_events[nsyscalls],
475 expected_nr_events[nsyscalls], i, j;
476 struct perf_evsel *evsels[nsyscalls], *evsel;
477
478 for (i = 0; i < nsyscalls; ++i) {
479 char name[64];
480
481 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
482 ids[i] = trace_event__id(name);
483 if (ids[i] < 0) {
484 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
485 return -1;
486 }
487 nr_events[i] = 0;
488 expected_nr_events[i] = random() % 257;
489 }
490
491 threads = thread_map__new(-1, getpid());
492 if (threads == NULL) {
493 pr_debug("thread_map__new\n");
494 return -1;
495 }
496
497 cpus = cpu_map__new(NULL);
498 if (threads == NULL) {
499 pr_debug("thread_map__new\n");
500 goto out_free_threads;
501 }
502
503 CPU_ZERO(&cpu_set);
504 CPU_SET(cpus->map[0], &cpu_set);
505 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
506 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
507 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
508 cpus->map[0], strerror(errno));
509 goto out_free_cpus;
510 }
511
512 evlist = perf_evlist__new();
513 if (threads == NULL) {
514 pr_debug("perf_evlist__new\n");
515 goto out_free_cpus;
516 }
517
518 /* anonymous union fields, can't be initialized above */
519 attr.wakeup_events = 1;
520 attr.sample_period = 1;
521
522 for (i = 0; i < nsyscalls; ++i) {
523 attr.config = ids[i];
524 evsels[i] = perf_evsel__new(&attr, i);
525 if (evsels[i] == NULL) {
526 pr_debug("perf_evsel__new\n");
527 goto out_free_evlist;
528 }
529
530 perf_evlist__add(evlist, evsels[i]);
531
532 if (perf_evsel__open(evsels[i], cpus, threads, false, false) < 0) {
533 pr_debug("failed to open counter: %s, "
534 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
535 strerror(errno));
536 goto out_close_fd;
537 }
538 }
539
540 if (perf_evlist__mmap(evlist, cpus, threads, 128, true) < 0) {
541 pr_debug("failed to mmap events: %d (%s)\n", errno,
542 strerror(errno));
543 goto out_close_fd;
544 }
545
546 for (i = 0; i < nsyscalls; ++i)
547 for (j = 0; j < expected_nr_events[i]; ++j) {
548 int foo = syscalls[i]();
549 ++foo;
550 }
551
552 while ((event = perf_evlist__read_on_cpu(evlist, 0)) != NULL) {
553 struct sample_data sample;
554
555 if (event->header.type != PERF_RECORD_SAMPLE) {
556 pr_debug("unexpected %s event\n",
557 event__get_event_name(event->header.type));
558 goto out_munmap;
559 }
560
561 event__parse_sample(event, attr.sample_type, false, &sample);
562 evsel = perf_evlist__id2evsel(evlist, sample.id);
563 if (evsel == NULL) {
564 pr_debug("event with id %" PRIu64
565 " doesn't map to an evsel\n", sample.id);
566 goto out_munmap;
567 }
568 nr_events[evsel->idx]++;
569 }
570
571 list_for_each_entry(evsel, &evlist->entries, node) {
572 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
573 pr_debug("expected %d %s events, got %d\n",
574 expected_nr_events[evsel->idx],
575 event_name(evsel), nr_events[evsel->idx]);
576 goto out_munmap;
577 }
578 }
579
580 err = 0;
581out_munmap:
582 perf_evlist__munmap(evlist, 1);
583out_close_fd:
584 for (i = 0; i < nsyscalls; ++i)
585 perf_evsel__close_fd(evsels[i], 1, threads->nr);
586out_free_evlist:
587 perf_evlist__delete(evlist);
588out_free_cpus:
589 cpu_map__delete(cpus);
590out_free_threads:
591 thread_map__delete(threads);
592 return err;
593#undef nsyscalls
594}
595
440static struct test { 596static struct test {
441 const char *desc; 597 const char *desc;
442 int (*func)(void); 598 int (*func)(void);
@@ -454,6 +610,10 @@ static struct test {
454 .func = test__open_syscall_event_on_all_cpus, 610 .func = test__open_syscall_event_on_all_cpus,
455 }, 611 },
456 { 612 {
613 .desc = "read samples using the mmap interface",
614 .func = test__basic_mmap,
615 },
616 {
457 .func = NULL, 617 .func = NULL,
458 }, 618 },
459}; 619};
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index b6998e055767..ce2e50c891c7 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -21,10 +21,12 @@
21#include "perf.h" 21#include "perf.h"
22 22
23#include "util/color.h" 23#include "util/color.h"
24#include "util/evlist.h"
24#include "util/evsel.h" 25#include "util/evsel.h"
25#include "util/session.h" 26#include "util/session.h"
26#include "util/symbol.h" 27#include "util/symbol.h"
27#include "util/thread.h" 28#include "util/thread.h"
29#include "util/thread_map.h"
28#include "util/util.h" 30#include "util/util.h"
29#include <linux/rbtree.h> 31#include <linux/rbtree.h>
30#include "util/parse-options.h" 32#include "util/parse-options.h"
@@ -60,6 +62,8 @@
60 62
61#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 63#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
62 64
65struct perf_evlist *evsel_list;
66
63static bool system_wide = false; 67static bool system_wide = false;
64 68
65static int default_interval = 0; 69static int default_interval = 0;
@@ -75,7 +79,7 @@ static struct cpu_map *cpus;
75static int realtime_prio = 0; 79static int realtime_prio = 0;
76static bool group = false; 80static bool group = false;
77static unsigned int page_size; 81static unsigned int page_size;
78static unsigned int mmap_pages = 16; 82static unsigned int mmap_pages = 128;
79static int freq = 1000; /* 1 KHz */ 83static int freq = 1000; /* 1 KHz */
80 84
81static int delay_secs = 2; 85static int delay_secs = 2;
@@ -267,7 +271,7 @@ static void __zero_source_counters(struct sym_entry *syme)
267 271
268 line = syme->src->lines; 272 line = syme->src->lines;
269 while (line) { 273 while (line) {
270 for (i = 0; i < nr_counters; i++) 274 for (i = 0; i < evsel_list->nr_entries; i++)
271 line->count[i] = 0; 275 line->count[i] = 0;
272 line = line->next; 276 line = line->next;
273 } 277 }
@@ -414,7 +418,7 @@ static double sym_weight(const struct sym_entry *sym)
414 if (!display_weighted) 418 if (!display_weighted)
415 return weight; 419 return weight;
416 420
417 for (counter = 1; counter < nr_counters-1; counter++) 421 for (counter = 1; counter < evsel_list->nr_entries - 1; counter++)
418 weight *= sym->count[counter]; 422 weight *= sym->count[counter];
419 423
420 weight /= (sym->count[counter] + 1); 424 weight /= (sym->count[counter] + 1);
@@ -501,7 +505,7 @@ static void print_sym_table(void)
501 rb_insert_active_sym(&tmp, syme); 505 rb_insert_active_sym(&tmp, syme);
502 sum_ksamples += syme->snap_count; 506 sum_ksamples += syme->snap_count;
503 507
504 for (j = 0; j < nr_counters; j++) 508 for (j = 0; j < evsel_list->nr_entries; j++)
505 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; 509 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
506 } else 510 } else
507 list_remove_active_sym(syme); 511 list_remove_active_sym(syme);
@@ -535,9 +539,9 @@ static void print_sym_table(void)
535 esamples_percent); 539 esamples_percent);
536 } 540 }
537 541
538 if (nr_counters == 1 || !display_weighted) { 542 if (evsel_list->nr_entries == 1 || !display_weighted) {
539 struct perf_evsel *first; 543 struct perf_evsel *first;
540 first = list_entry(evsel_list.next, struct perf_evsel, node); 544 first = list_entry(evsel_list->entries.next, struct perf_evsel, node);
541 printf("%" PRIu64, (uint64_t)first->attr.sample_period); 545 printf("%" PRIu64, (uint64_t)first->attr.sample_period);
542 if (freq) 546 if (freq)
543 printf("Hz "); 547 printf("Hz ");
@@ -547,7 +551,7 @@ static void print_sym_table(void)
547 551
548 if (!display_weighted) 552 if (!display_weighted)
549 printf("%s", event_name(sym_evsel)); 553 printf("%s", event_name(sym_evsel));
550 else list_for_each_entry(counter, &evsel_list, node) { 554 else list_for_each_entry(counter, &evsel_list->entries, node) {
551 if (counter->idx) 555 if (counter->idx)
552 printf("/"); 556 printf("/");
553 557
@@ -606,7 +610,7 @@ static void print_sym_table(void)
606 sym_width = winsize.ws_col - dso_width - 29; 610 sym_width = winsize.ws_col - dso_width - 29;
607 } 611 }
608 putchar('\n'); 612 putchar('\n');
609 if (nr_counters == 1) 613 if (evsel_list->nr_entries == 1)
610 printf(" samples pcnt"); 614 printf(" samples pcnt");
611 else 615 else
612 printf(" weight samples pcnt"); 616 printf(" weight samples pcnt");
@@ -615,7 +619,7 @@ static void print_sym_table(void)
615 printf(" RIP "); 619 printf(" RIP ");
616 printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); 620 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
617 printf(" %s _______ _____", 621 printf(" %s _______ _____",
618 nr_counters == 1 ? " " : "______"); 622 evsel_list->nr_entries == 1 ? " " : "______");
619 if (verbose) 623 if (verbose)
620 printf(" ________________"); 624 printf(" ________________");
621 printf(" %-*.*s", sym_width, sym_width, graph_line); 625 printf(" %-*.*s", sym_width, sym_width, graph_line);
@@ -634,7 +638,7 @@ static void print_sym_table(void)
634 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 638 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
635 sum_ksamples)); 639 sum_ksamples));
636 640
637 if (nr_counters == 1 || !display_weighted) 641 if (evsel_list->nr_entries == 1 || !display_weighted)
638 printf("%20.2f ", syme->weight); 642 printf("%20.2f ", syme->weight);
639 else 643 else
640 printf("%9.1f %10ld ", syme->weight, syme->snap_count); 644 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
@@ -744,7 +748,7 @@ static void print_mapped_keys(void)
744 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); 748 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs);
745 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); 749 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries);
746 750
747 if (nr_counters > 1) 751 if (evsel_list->nr_entries > 1)
748 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); 752 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel));
749 753
750 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 754 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
@@ -753,7 +757,7 @@ static void print_mapped_keys(void)
753 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 757 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
754 fprintf(stdout, "\t[S] stop annotation.\n"); 758 fprintf(stdout, "\t[S] stop annotation.\n");
755 759
756 if (nr_counters > 1) 760 if (evsel_list->nr_entries > 1)
757 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 761 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
758 762
759 fprintf(stdout, 763 fprintf(stdout,
@@ -783,7 +787,7 @@ static int key_mapped(int c)
783 return 1; 787 return 1;
784 case 'E': 788 case 'E':
785 case 'w': 789 case 'w':
786 return nr_counters > 1 ? 1 : 0; 790 return evsel_list->nr_entries > 1 ? 1 : 0;
787 default: 791 default:
788 break; 792 break;
789 } 793 }
@@ -831,22 +835,22 @@ static void handle_keypress(struct perf_session *session, int c)
831 signal(SIGWINCH, SIG_DFL); 835 signal(SIGWINCH, SIG_DFL);
832 break; 836 break;
833 case 'E': 837 case 'E':
834 if (nr_counters > 1) { 838 if (evsel_list->nr_entries > 1) {
835 fprintf(stderr, "\nAvailable events:"); 839 fprintf(stderr, "\nAvailable events:");
836 840
837 list_for_each_entry(sym_evsel, &evsel_list, node) 841 list_for_each_entry(sym_evsel, &evsel_list->entries, node)
838 fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); 842 fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel));
839 843
840 prompt_integer(&sym_counter, "Enter details event counter"); 844 prompt_integer(&sym_counter, "Enter details event counter");
841 845
842 if (sym_counter >= nr_counters) { 846 if (sym_counter >= evsel_list->nr_entries) {
843 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); 847 sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node);
844 sym_counter = 0; 848 sym_counter = 0;
845 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel)); 849 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel));
846 sleep(1); 850 sleep(1);
847 break; 851 break;
848 } 852 }
849 list_for_each_entry(sym_evsel, &evsel_list, node) 853 list_for_each_entry(sym_evsel, &evsel_list->entries, node)
850 if (sym_evsel->idx == sym_counter) 854 if (sym_evsel->idx == sym_counter)
851 break; 855 break;
852 } else sym_counter = 0; 856 } else sym_counter = 0;
@@ -930,6 +934,7 @@ repeat:
930/* Tag samples to be skipped. */ 934/* Tag samples to be skipped. */
931static const char *skip_symbols[] = { 935static const char *skip_symbols[] = {
932 "default_idle", 936 "default_idle",
937 "native_safe_halt",
933 "cpu_idle", 938 "cpu_idle",
934 "enter_idle", 939 "enter_idle",
935 "exit_idle", 940 "exit_idle",
@@ -988,8 +993,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
988 993
989static void event__process_sample(const event_t *self, 994static void event__process_sample(const event_t *self,
990 struct sample_data *sample, 995 struct sample_data *sample,
991 struct perf_session *session, 996 struct perf_session *session)
992 struct perf_evsel *evsel)
993{ 997{
994 u64 ip = self->ip.ip; 998 u64 ip = self->ip.ip;
995 struct sym_entry *syme; 999 struct sym_entry *syme;
@@ -1082,8 +1086,12 @@ static void event__process_sample(const event_t *self,
1082 1086
1083 syme = symbol__priv(al.sym); 1087 syme = symbol__priv(al.sym);
1084 if (!syme->skip) { 1088 if (!syme->skip) {
1085 syme->count[evsel->idx]++; 1089 struct perf_evsel *evsel;
1090
1086 syme->origin = origin; 1091 syme->origin = origin;
1092 evsel = perf_evlist__id2evsel(evsel_list, sample->id);
1093 assert(evsel != NULL);
1094 syme->count[evsel->idx]++;
1087 record_precise_ip(syme, evsel->idx, ip); 1095 record_precise_ip(syme, evsel->idx, ip);
1088 pthread_mutex_lock(&active_symbols_lock); 1096 pthread_mutex_lock(&active_symbols_lock);
1089 if (list_empty(&syme->node) || !syme->node.next) 1097 if (list_empty(&syme->node) || !syme->node.next)
@@ -1092,156 +1100,52 @@ static void event__process_sample(const event_t *self,
1092 } 1100 }
1093} 1101}
1094 1102
1095struct mmap_data { 1103static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu)
1096 void *base;
1097 int mask;
1098 unsigned int prev;
1099};
1100
1101static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel,
1102 int ncpus, int nthreads)
1103{
1104 evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data));
1105 return evsel->priv != NULL ? 0 : -ENOMEM;
1106}
1107
1108static void perf_evsel__free_mmap(struct perf_evsel *evsel)
1109{
1110 xyarray__delete(evsel->priv);
1111 evsel->priv = NULL;
1112}
1113
1114static unsigned int mmap_read_head(struct mmap_data *md)
1115{
1116 struct perf_event_mmap_page *pc = md->base;
1117 int head;
1118
1119 head = pc->data_head;
1120 rmb();
1121
1122 return head;
1123}
1124
1125static void perf_session__mmap_read_counter(struct perf_session *self,
1126 struct perf_evsel *evsel,
1127 int cpu, int thread_idx)
1128{ 1104{
1129 struct xyarray *mmap_array = evsel->priv;
1130 struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx);
1131 unsigned int head = mmap_read_head(md);
1132 unsigned int old = md->prev;
1133 unsigned char *data = md->base + page_size;
1134 struct sample_data sample; 1105 struct sample_data sample;
1135 int diff; 1106 event_t *event;
1136
1137 /*
1138 * If we're further behind than half the buffer, there's a chance
1139 * the writer will bite our tail and mess up the samples under us.
1140 *
1141 * If we somehow ended up ahead of the head, we got messed up.
1142 *
1143 * In either case, truncate and restart at head.
1144 */
1145 diff = head - old;
1146 if (diff > md->mask / 2 || diff < 0) {
1147 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
1148
1149 /*
1150 * head points to a known good entry, start there.
1151 */
1152 old = head;
1153 }
1154
1155 for (; old != head;) {
1156 event_t *event = (event_t *)&data[old & md->mask];
1157 1107
1158 event_t event_copy; 1108 while ((event = perf_evlist__read_on_cpu(evsel_list, cpu)) != NULL) {
1159 1109 perf_session__parse_sample(self, event, &sample);
1160 size_t size = event->header.size;
1161
1162 /*
1163 * Event straddles the mmap boundary -- header should always
1164 * be inside due to u64 alignment of output.
1165 */
1166 if ((old & md->mask) + size != ((old + size) & md->mask)) {
1167 unsigned int offset = old;
1168 unsigned int len = min(sizeof(*event), size), cpy;
1169 void *dst = &event_copy;
1170
1171 do {
1172 cpy = min(md->mask + 1 - (offset & md->mask), len);
1173 memcpy(dst, &data[offset & md->mask], cpy);
1174 offset += cpy;
1175 dst += cpy;
1176 len -= cpy;
1177 } while (len);
1178
1179 event = &event_copy;
1180 }
1181 1110
1182 event__parse_sample(event, self, &sample);
1183 if (event->header.type == PERF_RECORD_SAMPLE) 1111 if (event->header.type == PERF_RECORD_SAMPLE)
1184 event__process_sample(event, &sample, self, evsel); 1112 event__process_sample(event, &sample, self);
1185 else 1113 else
1186 event__process(event, &sample, self); 1114 event__process(event, &sample, self);
1187 old += size;
1188 } 1115 }
1189
1190 md->prev = old;
1191} 1116}
1192 1117
1193static struct pollfd *event_array;
1194
1195static void perf_session__mmap_read(struct perf_session *self) 1118static void perf_session__mmap_read(struct perf_session *self)
1196{ 1119{
1197 struct perf_evsel *counter; 1120 int i;
1198 int i, thread_index;
1199
1200 for (i = 0; i < cpus->nr; i++) {
1201 list_for_each_entry(counter, &evsel_list, node) {
1202 for (thread_index = 0;
1203 thread_index < threads->nr;
1204 thread_index++) {
1205 perf_session__mmap_read_counter(self,
1206 counter, i, thread_index);
1207 }
1208 }
1209 }
1210}
1211 1121
1212int nr_poll; 1122 for (i = 0; i < cpus->nr; i++)
1213int group_fd; 1123 perf_session__mmap_read_cpu(self, i);
1124}
1214 1125
1215static void start_counter(int i, struct perf_evsel *evsel) 1126static void start_counters(struct perf_evlist *evlist)
1216{ 1127{
1217 struct xyarray *mmap_array = evsel->priv; 1128 struct perf_evsel *counter;
1218 struct mmap_data *mm;
1219 struct perf_event_attr *attr;
1220 int cpu = -1;
1221 int thread_index;
1222
1223 if (target_tid == -1)
1224 cpu = cpus->map[i];
1225 1129
1226 attr = &evsel->attr; 1130 list_for_each_entry(counter, &evlist->entries, node) {
1131 struct perf_event_attr *attr = &counter->attr;
1227 1132
1228 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1133 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1229 1134
1230 if (freq) { 1135 if (freq) {
1231 attr->sample_type |= PERF_SAMPLE_PERIOD; 1136 attr->sample_type |= PERF_SAMPLE_PERIOD;
1232 attr->freq = 1; 1137 attr->freq = 1;
1233 attr->sample_freq = freq; 1138 attr->sample_freq = freq;
1234 } 1139 }
1235 1140
1236 attr->inherit = (cpu < 0) && inherit; 1141 if (evlist->nr_entries > 1) {
1237 attr->mmap = 1; 1142 attr->sample_type |= PERF_SAMPLE_ID;
1143 attr->read_format |= PERF_FORMAT_ID;
1144 }
1238 1145
1239 for (thread_index = 0; thread_index < threads->nr; thread_index++) { 1146 attr->mmap = 1;
1240try_again: 1147try_again:
1241 FD(evsel, i, thread_index) = sys_perf_event_open(attr, 1148 if (perf_evsel__open(counter, cpus, threads, group, inherit) < 0) {
1242 threads->map[thread_index], cpu, group_fd, 0);
1243
1244 if (FD(evsel, i, thread_index) < 0) {
1245 int err = errno; 1149 int err = errno;
1246 1150
1247 if (err == EPERM || err == EACCES) 1151 if (err == EPERM || err == EACCES)
@@ -1253,8 +1157,8 @@ try_again:
1253 * based cpu-clock-tick sw counter, which 1157 * based cpu-clock-tick sw counter, which
1254 * is always available even if no PMU support: 1158 * is always available even if no PMU support:
1255 */ 1159 */
1256 if (attr->type == PERF_TYPE_HARDWARE 1160 if (attr->type == PERF_TYPE_HARDWARE &&
1257 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 1161 attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1258 1162
1259 if (verbose) 1163 if (verbose)
1260 warning(" ... trying to fall back to cpu-clock-ticks\n"); 1164 warning(" ... trying to fall back to cpu-clock-ticks\n");
@@ -1264,39 +1168,23 @@ try_again:
1264 goto try_again; 1168 goto try_again;
1265 } 1169 }
1266 printf("\n"); 1170 printf("\n");
1267 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 1171 error("sys_perf_event_open() syscall returned with %d "
1268 FD(evsel, i, thread_index), strerror(err)); 1172 "(%s). /bin/dmesg may provide additional information.\n",
1173 err, strerror(err));
1269 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 1174 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
1270 exit(-1); 1175 exit(-1);
1271 } 1176 }
1272 assert(FD(evsel, i, thread_index) >= 0);
1273 fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK);
1274
1275 /*
1276 * First counter acts as the group leader:
1277 */
1278 if (group && group_fd == -1)
1279 group_fd = FD(evsel, i, thread_index);
1280
1281 event_array[nr_poll].fd = FD(evsel, i, thread_index);
1282 event_array[nr_poll].events = POLLIN;
1283 nr_poll++;
1284
1285 mm = xyarray__entry(mmap_array, i, thread_index);
1286 mm->prev = 0;
1287 mm->mask = mmap_pages*page_size - 1;
1288 mm->base = mmap(NULL, (mmap_pages+1)*page_size,
1289 PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0);
1290 if (mm->base == MAP_FAILED)
1291 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1292 } 1177 }
1178
1179 if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, true) < 0)
1180 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1293} 1181}
1294 1182
1295static int __cmd_top(void) 1183static int __cmd_top(void)
1296{ 1184{
1297 pthread_t thread; 1185 pthread_t thread;
1298 struct perf_evsel *counter; 1186 struct perf_evsel *first;
1299 int i, ret; 1187 int ret;
1300 /* 1188 /*
1301 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 1189 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1302 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 1190 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
@@ -1310,14 +1198,12 @@ static int __cmd_top(void)
1310 else 1198 else
1311 event__synthesize_threads(event__process, session); 1199 event__synthesize_threads(event__process, session);
1312 1200
1313 for (i = 0; i < cpus->nr; i++) { 1201 start_counters(evsel_list);
1314 group_fd = -1; 1202 first = list_entry(evsel_list->entries.next, struct perf_evsel, node);
1315 list_for_each_entry(counter, &evsel_list, node) 1203 perf_session__set_sample_type(session, first->attr.sample_type);
1316 start_counter(i, counter);
1317 }
1318 1204
1319 /* Wait for a minimal set of events before starting the snapshot */ 1205 /* Wait for a minimal set of events before starting the snapshot */
1320 poll(&event_array[0], nr_poll, 100); 1206 poll(evsel_list->pollfd, evsel_list->nr_fds, 100);
1321 1207
1322 perf_session__mmap_read(session); 1208 perf_session__mmap_read(session);
1323 1209
@@ -1342,7 +1228,7 @@ static int __cmd_top(void)
1342 perf_session__mmap_read(session); 1228 perf_session__mmap_read(session);
1343 1229
1344 if (hits == samples) 1230 if (hits == samples)
1345 ret = poll(event_array, nr_poll, 100); 1231 ret = poll(evsel_list->pollfd, evsel_list->nr_fds, 100);
1346 } 1232 }
1347 1233
1348 return 0; 1234 return 0;
@@ -1354,7 +1240,7 @@ static const char * const top_usage[] = {
1354}; 1240};
1355 1241
1356static const struct option options[] = { 1242static const struct option options[] = {
1357 OPT_CALLBACK('e', "event", NULL, "event", 1243 OPT_CALLBACK('e', "event", &evsel_list, "event",
1358 "event selector. use 'perf list' to list available events", 1244 "event selector. use 'perf list' to list available events",
1359 parse_events), 1245 parse_events),
1360 OPT_INTEGER('c', "count", &default_interval, 1246 OPT_INTEGER('c', "count", &default_interval,
@@ -1404,6 +1290,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1404 struct perf_evsel *pos; 1290 struct perf_evsel *pos;
1405 int status = -ENOMEM; 1291 int status = -ENOMEM;
1406 1292
1293 evsel_list = perf_evlist__new();
1294 if (evsel_list == NULL)
1295 return -ENOMEM;
1296
1407 page_size = sysconf(_SC_PAGE_SIZE); 1297 page_size = sysconf(_SC_PAGE_SIZE);
1408 1298
1409 argc = parse_options(argc, argv, options, top_usage, 0); 1299 argc = parse_options(argc, argv, options, top_usage, 0);
@@ -1419,11 +1309,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1419 usage_with_options(top_usage, options); 1309 usage_with_options(top_usage, options);
1420 } 1310 }
1421 1311
1422 event_array = malloc((sizeof(struct pollfd) *
1423 MAX_NR_CPUS * MAX_COUNTERS * threads->nr));
1424 if (!event_array)
1425 return -ENOMEM;
1426
1427 /* CPU and PID are mutually exclusive */ 1312 /* CPU and PID are mutually exclusive */
1428 if (target_tid > 0 && cpu_list) { 1313 if (target_tid > 0 && cpu_list) {
1429 printf("WARNING: PID switch overriding CPU\n"); 1314 printf("WARNING: PID switch overriding CPU\n");
@@ -1431,7 +1316,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1431 cpu_list = NULL; 1316 cpu_list = NULL;
1432 } 1317 }
1433 1318
1434 if (!nr_counters && perf_evsel_list__create_default() < 0) { 1319 if (!evsel_list->nr_entries &&
1320 perf_evlist__add_default(evsel_list) < 0) {
1435 pr_err("Not enough memory for event selector list\n"); 1321 pr_err("Not enough memory for event selector list\n");
1436 return -ENOMEM; 1322 return -ENOMEM;
1437 } 1323 }
@@ -1459,9 +1345,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1459 if (cpus == NULL) 1345 if (cpus == NULL)
1460 usage_with_options(top_usage, options); 1346 usage_with_options(top_usage, options);
1461 1347
1462 list_for_each_entry(pos, &evsel_list, node) { 1348 list_for_each_entry(pos, &evsel_list->entries, node) {
1463 if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 || 1349 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
1464 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
1465 goto out_free_fd; 1350 goto out_free_fd;
1466 /* 1351 /*
1467 * Fill in the ones not specifically initialized via -c: 1352 * Fill in the ones not specifically initialized via -c:
@@ -1472,10 +1357,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1472 pos->attr.sample_period = default_interval; 1357 pos->attr.sample_period = default_interval;
1473 } 1358 }
1474 1359
1475 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); 1360 if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0 ||
1361 perf_evlist__alloc_mmap(evsel_list, cpus->nr) < 0)
1362 goto out_free_fd;
1363
1364 sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node);
1476 1365
1477 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1366 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1478 (nr_counters + 1) * sizeof(unsigned long)); 1367 (evsel_list->nr_entries + 1) * sizeof(unsigned long));
1479 1368
1480 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1369 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1481 if (symbol__init() < 0) 1370 if (symbol__init() < 0)
@@ -1489,9 +1378,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1489 1378
1490 status = __cmd_top(); 1379 status = __cmd_top();
1491out_free_fd: 1380out_free_fd:
1492 list_for_each_entry(pos, &evsel_list, node) 1381 perf_evlist__delete(evsel_list);
1493 perf_evsel__free_mmap(pos);
1494 perf_evsel_list__delete();
1495 1382
1496 return status; 1383 return status;
1497} 1384}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 95aaf565c704..a5fc660c1f12 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -94,6 +94,32 @@ void get_term_dimensions(struct winsize *ws);
94#include "util/types.h" 94#include "util/types.h"
95#include <stdbool.h> 95#include <stdbool.h>
96 96
97struct perf_mmap {
98 void *base;
99 int mask;
100 unsigned int prev;
101};
102
103static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
104{
105 struct perf_event_mmap_page *pc = mm->base;
106 int head = pc->data_head;
107 rmb();
108 return head;
109}
110
111static inline void perf_mmap__write_tail(struct perf_mmap *md,
112 unsigned long tail)
113{
114 struct perf_event_mmap_page *pc = md->base;
115
116 /*
117 * ensure all reads are done before we write the tail out.
118 */
119 /* mb(); */
120 pc->data_tail = tail;
121}
122
97/* 123/*
98 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all 124 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
99 * counters in the current task. 125 * counters in the current task.
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index e12d539417b2..f8c66d1435e0 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2009-2010, Frederic Weisbecker <fweisbec@gmail.com> 2 * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
3 * 3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then 4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree. 5 * sort them in an rbtree.
@@ -26,10 +26,10 @@ bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
26} 26}
27 27
28#define chain_for_each_child(child, parent) \ 28#define chain_for_each_child(child, parent) \
29 list_for_each_entry(child, &parent->children, brothers) 29 list_for_each_entry(child, &parent->children, siblings)
30 30
31#define chain_for_each_child_safe(child, next, parent) \ 31#define chain_for_each_child_safe(child, next, parent) \
32 list_for_each_entry_safe(child, next, &parent->children, brothers) 32 list_for_each_entry_safe(child, next, &parent->children, siblings)
33 33
34static void 34static void
35rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 35rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
@@ -38,14 +38,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
38 struct rb_node **p = &root->rb_node; 38 struct rb_node **p = &root->rb_node;
39 struct rb_node *parent = NULL; 39 struct rb_node *parent = NULL;
40 struct callchain_node *rnode; 40 struct callchain_node *rnode;
41 u64 chain_cumul = cumul_hits(chain); 41 u64 chain_cumul = callchain_cumul_hits(chain);
42 42
43 while (*p) { 43 while (*p) {
44 u64 rnode_cumul; 44 u64 rnode_cumul;
45 45
46 parent = *p; 46 parent = *p;
47 rnode = rb_entry(parent, struct callchain_node, rb_node); 47 rnode = rb_entry(parent, struct callchain_node, rb_node);
48 rnode_cumul = cumul_hits(rnode); 48 rnode_cumul = callchain_cumul_hits(rnode);
49 49
50 switch (mode) { 50 switch (mode) {
51 case CHAIN_FLAT: 51 case CHAIN_FLAT:
@@ -104,7 +104,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
104 104
105 chain_for_each_child(child, node) { 105 chain_for_each_child(child, node) {
106 __sort_chain_graph_abs(child, min_hit); 106 __sort_chain_graph_abs(child, min_hit);
107 if (cumul_hits(child) >= min_hit) 107 if (callchain_cumul_hits(child) >= min_hit)
108 rb_insert_callchain(&node->rb_root, child, 108 rb_insert_callchain(&node->rb_root, child,
109 CHAIN_GRAPH_ABS); 109 CHAIN_GRAPH_ABS);
110 } 110 }
@@ -129,7 +129,7 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
129 129
130 chain_for_each_child(child, node) { 130 chain_for_each_child(child, node) {
131 __sort_chain_graph_rel(child, min_percent); 131 __sort_chain_graph_rel(child, min_percent);
132 if (cumul_hits(child) >= min_hit) 132 if (callchain_cumul_hits(child) >= min_hit)
133 rb_insert_callchain(&node->rb_root, child, 133 rb_insert_callchain(&node->rb_root, child,
134 CHAIN_GRAPH_REL); 134 CHAIN_GRAPH_REL);
135 } 135 }
@@ -143,7 +143,7 @@ sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
143 rb_root->rb_node = chain_root->node.rb_root.rb_node; 143 rb_root->rb_node = chain_root->node.rb_root.rb_node;
144} 144}
145 145
146int register_callchain_param(struct callchain_param *param) 146int callchain_register_param(struct callchain_param *param)
147{ 147{
148 switch (param->mode) { 148 switch (param->mode) {
149 case CHAIN_GRAPH_ABS: 149 case CHAIN_GRAPH_ABS:
@@ -189,32 +189,27 @@ create_child(struct callchain_node *parent, bool inherit_children)
189 chain_for_each_child(next, new) 189 chain_for_each_child(next, new)
190 next->parent = new; 190 next->parent = new;
191 } 191 }
192 list_add_tail(&new->brothers, &parent->children); 192 list_add_tail(&new->siblings, &parent->children);
193 193
194 return new; 194 return new;
195} 195}
196 196
197 197
198struct resolved_ip {
199 u64 ip;
200 struct map_symbol ms;
201};
202
203struct resolved_chain {
204 u64 nr;
205 struct resolved_ip ips[0];
206};
207
208
209/* 198/*
210 * Fill the node with callchain values 199 * Fill the node with callchain values
211 */ 200 */
212static void 201static void
213fill_node(struct callchain_node *node, struct resolved_chain *chain, int start) 202fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
214{ 203{
215 unsigned int i; 204 struct callchain_cursor_node *cursor_node;
205
206 node->val_nr = cursor->nr - cursor->pos;
207 if (!node->val_nr)
208 pr_warning("Warning: empty node in callchain tree\n");
216 209
217 for (i = start; i < chain->nr; i++) { 210 cursor_node = callchain_cursor_current(cursor);
211
212 while (cursor_node) {
218 struct callchain_list *call; 213 struct callchain_list *call;
219 214
220 call = zalloc(sizeof(*call)); 215 call = zalloc(sizeof(*call));
@@ -222,23 +217,25 @@ fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
222 perror("not enough memory for the code path tree"); 217 perror("not enough memory for the code path tree");
223 return; 218 return;
224 } 219 }
225 call->ip = chain->ips[i].ip; 220 call->ip = cursor_node->ip;
226 call->ms = chain->ips[i].ms; 221 call->ms.sym = cursor_node->sym;
222 call->ms.map = cursor_node->map;
227 list_add_tail(&call->list, &node->val); 223 list_add_tail(&call->list, &node->val);
224
225 callchain_cursor_advance(cursor);
226 cursor_node = callchain_cursor_current(cursor);
228 } 227 }
229 node->val_nr = chain->nr - start;
230 if (!node->val_nr)
231 pr_warning("Warning: empty node in callchain tree\n");
232} 228}
233 229
234static void 230static void
235add_child(struct callchain_node *parent, struct resolved_chain *chain, 231add_child(struct callchain_node *parent,
236 int start, u64 period) 232 struct callchain_cursor *cursor,
233 u64 period)
237{ 234{
238 struct callchain_node *new; 235 struct callchain_node *new;
239 236
240 new = create_child(parent, false); 237 new = create_child(parent, false);
241 fill_node(new, chain, start); 238 fill_node(new, cursor);
242 239
243 new->children_hit = 0; 240 new->children_hit = 0;
244 new->hit = period; 241 new->hit = period;
@@ -250,9 +247,10 @@ add_child(struct callchain_node *parent, struct resolved_chain *chain,
250 * Then create another child to host the given callchain of new branch 247 * Then create another child to host the given callchain of new branch
251 */ 248 */
252static void 249static void
253split_add_child(struct callchain_node *parent, struct resolved_chain *chain, 250split_add_child(struct callchain_node *parent,
254 struct callchain_list *to_split, int idx_parents, int idx_local, 251 struct callchain_cursor *cursor,
255 u64 period) 252 struct callchain_list *to_split,
253 u64 idx_parents, u64 idx_local, u64 period)
256{ 254{
257 struct callchain_node *new; 255 struct callchain_node *new;
258 struct list_head *old_tail; 256 struct list_head *old_tail;
@@ -272,14 +270,14 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
272 /* split the hits */ 270 /* split the hits */
273 new->hit = parent->hit; 271 new->hit = parent->hit;
274 new->children_hit = parent->children_hit; 272 new->children_hit = parent->children_hit;
275 parent->children_hit = cumul_hits(new); 273 parent->children_hit = callchain_cumul_hits(new);
276 new->val_nr = parent->val_nr - idx_local; 274 new->val_nr = parent->val_nr - idx_local;
277 parent->val_nr = idx_local; 275 parent->val_nr = idx_local;
278 276
279 /* create a new child for the new branch if any */ 277 /* create a new child for the new branch if any */
280 if (idx_total < chain->nr) { 278 if (idx_total < cursor->nr) {
281 parent->hit = 0; 279 parent->hit = 0;
282 add_child(parent, chain, idx_total, period); 280 add_child(parent, cursor, period);
283 parent->children_hit += period; 281 parent->children_hit += period;
284 } else { 282 } else {
285 parent->hit = period; 283 parent->hit = period;
@@ -287,36 +285,41 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
287} 285}
288 286
289static int 287static int
290append_chain(struct callchain_node *root, struct resolved_chain *chain, 288append_chain(struct callchain_node *root,
291 unsigned int start, u64 period); 289 struct callchain_cursor *cursor,
290 u64 period);
292 291
293static void 292static void
294append_chain_children(struct callchain_node *root, struct resolved_chain *chain, 293append_chain_children(struct callchain_node *root,
295 unsigned int start, u64 period) 294 struct callchain_cursor *cursor,
295 u64 period)
296{ 296{
297 struct callchain_node *rnode; 297 struct callchain_node *rnode;
298 298
299 /* lookup in childrens */ 299 /* lookup in childrens */
300 chain_for_each_child(rnode, root) { 300 chain_for_each_child(rnode, root) {
301 unsigned int ret = append_chain(rnode, chain, start, period); 301 unsigned int ret = append_chain(rnode, cursor, period);
302 302
303 if (!ret) 303 if (!ret)
304 goto inc_children_hit; 304 goto inc_children_hit;
305 } 305 }
306 /* nothing in children, add to the current node */ 306 /* nothing in children, add to the current node */
307 add_child(root, chain, start, period); 307 add_child(root, cursor, period);
308 308
309inc_children_hit: 309inc_children_hit:
310 root->children_hit += period; 310 root->children_hit += period;
311} 311}
312 312
313static int 313static int
314append_chain(struct callchain_node *root, struct resolved_chain *chain, 314append_chain(struct callchain_node *root,
315 unsigned int start, u64 period) 315 struct callchain_cursor *cursor,
316 u64 period)
316{ 317{
318 struct callchain_cursor_node *curr_snap = cursor->curr;
317 struct callchain_list *cnode; 319 struct callchain_list *cnode;
318 unsigned int i = start; 320 u64 start = cursor->pos;
319 bool found = false; 321 bool found = false;
322 u64 matches;
320 323
321 /* 324 /*
322 * Lookup in the current node 325 * Lookup in the current node
@@ -324,141 +327,134 @@ append_chain(struct callchain_node *root, struct resolved_chain *chain,
324 * anywhere inside a function. 327 * anywhere inside a function.
325 */ 328 */
326 list_for_each_entry(cnode, &root->val, list) { 329 list_for_each_entry(cnode, &root->val, list) {
330 struct callchain_cursor_node *node;
327 struct symbol *sym; 331 struct symbol *sym;
328 332
329 if (i == chain->nr) 333 node = callchain_cursor_current(cursor);
334 if (!node)
330 break; 335 break;
331 336
332 sym = chain->ips[i].ms.sym; 337 sym = node->sym;
333 338
334 if (cnode->ms.sym && sym) { 339 if (cnode->ms.sym && sym) {
335 if (cnode->ms.sym->start != sym->start) 340 if (cnode->ms.sym->start != sym->start)
336 break; 341 break;
337 } else if (cnode->ip != chain->ips[i].ip) 342 } else if (cnode->ip != node->ip)
338 break; 343 break;
339 344
340 if (!found) 345 if (!found)
341 found = true; 346 found = true;
342 i++; 347
348 callchain_cursor_advance(cursor);
343 } 349 }
344 350
345 /* matches not, relay on the parent */ 351 /* matches not, relay on the parent */
346 if (!found) 352 if (!found) {
353 cursor->curr = curr_snap;
354 cursor->pos = start;
347 return -1; 355 return -1;
356 }
357
358 matches = cursor->pos - start;
348 359
349 /* we match only a part of the node. Split it and add the new chain */ 360 /* we match only a part of the node. Split it and add the new chain */
350 if (i - start < root->val_nr) { 361 if (matches < root->val_nr) {
351 split_add_child(root, chain, cnode, start, i - start, period); 362 split_add_child(root, cursor, cnode, start, matches, period);
352 return 0; 363 return 0;
353 } 364 }
354 365
355 /* we match 100% of the path, increment the hit */ 366 /* we match 100% of the path, increment the hit */
356 if (i - start == root->val_nr && i == chain->nr) { 367 if (matches == root->val_nr && cursor->pos == cursor->nr) {
357 root->hit += period; 368 root->hit += period;
358 return 0; 369 return 0;
359 } 370 }
360 371
361 /* We match the node and still have a part remaining */ 372 /* We match the node and still have a part remaining */
362 append_chain_children(root, chain, i, period); 373 append_chain_children(root, cursor, period);
363 374
364 return 0; 375 return 0;
365} 376}
366 377
367static void filter_context(struct ip_callchain *old, struct resolved_chain *new, 378int callchain_append(struct callchain_root *root,
368 struct map_symbol *syms) 379 struct callchain_cursor *cursor,
369{ 380 u64 period)
370 int i, j = 0;
371
372 for (i = 0; i < (int)old->nr; i++) {
373 if (old->ips[i] >= PERF_CONTEXT_MAX)
374 continue;
375
376 new->ips[j].ip = old->ips[i];
377 new->ips[j].ms = syms[i];
378 j++;
379 }
380
381 new->nr = j;
382}
383
384
385int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
386 struct map_symbol *syms, u64 period)
387{ 381{
388 struct resolved_chain *filtered; 382 if (!cursor->nr)
389
390 if (!chain->nr)
391 return 0; 383 return 0;
392 384
393 filtered = zalloc(sizeof(*filtered) + 385 callchain_cursor_commit(cursor);
394 chain->nr * sizeof(struct resolved_ip));
395 if (!filtered)
396 return -ENOMEM;
397
398 filter_context(chain, filtered, syms);
399
400 if (!filtered->nr)
401 goto end;
402 386
403 append_chain_children(&root->node, filtered, 0, period); 387 append_chain_children(&root->node, cursor, period);
404 388
405 if (filtered->nr > root->max_depth) 389 if (cursor->nr > root->max_depth)
406 root->max_depth = filtered->nr; 390 root->max_depth = cursor->nr;
407end:
408 free(filtered);
409 391
410 return 0; 392 return 0;
411} 393}
412 394
413static int 395static int
414merge_chain_branch(struct callchain_node *dst, struct callchain_node *src, 396merge_chain_branch(struct callchain_cursor *cursor,
415 struct resolved_chain *chain) 397 struct callchain_node *dst, struct callchain_node *src)
416{ 398{
399 struct callchain_cursor_node **old_last = cursor->last;
417 struct callchain_node *child, *next_child; 400 struct callchain_node *child, *next_child;
418 struct callchain_list *list, *next_list; 401 struct callchain_list *list, *next_list;
419 int old_pos = chain->nr; 402 int old_pos = cursor->nr;
420 int err = 0; 403 int err = 0;
421 404
422 list_for_each_entry_safe(list, next_list, &src->val, list) { 405 list_for_each_entry_safe(list, next_list, &src->val, list) {
423 chain->ips[chain->nr].ip = list->ip; 406 callchain_cursor_append(cursor, list->ip,
424 chain->ips[chain->nr].ms = list->ms; 407 list->ms.map, list->ms.sym);
425 chain->nr++;
426 list_del(&list->list); 408 list_del(&list->list);
427 free(list); 409 free(list);
428 } 410 }
429 411
430 if (src->hit) 412 if (src->hit) {
431 append_chain_children(dst, chain, 0, src->hit); 413 callchain_cursor_commit(cursor);
414 append_chain_children(dst, cursor, src->hit);
415 }
432 416
433 chain_for_each_child_safe(child, next_child, src) { 417 chain_for_each_child_safe(child, next_child, src) {
434 err = merge_chain_branch(dst, child, chain); 418 err = merge_chain_branch(cursor, dst, child);
435 if (err) 419 if (err)
436 break; 420 break;
437 421
438 list_del(&child->brothers); 422 list_del(&child->siblings);
439 free(child); 423 free(child);
440 } 424 }
441 425
442 chain->nr = old_pos; 426 cursor->nr = old_pos;
427 cursor->last = old_last;
443 428
444 return err; 429 return err;
445} 430}
446 431
447int callchain_merge(struct callchain_root *dst, struct callchain_root *src) 432int callchain_merge(struct callchain_cursor *cursor,
433 struct callchain_root *dst, struct callchain_root *src)
434{
435 return merge_chain_branch(cursor, &dst->node, &src->node);
436}
437
438int callchain_cursor_append(struct callchain_cursor *cursor,
439 u64 ip, struct map *map, struct symbol *sym)
448{ 440{
449 struct resolved_chain *chain; 441 struct callchain_cursor_node *node = *cursor->last;
450 int err;
451 442
452 chain = malloc(sizeof(*chain) + 443 if (!node) {
453 src->max_depth * sizeof(struct resolved_ip)); 444 node = calloc(sizeof(*node), 1);
454 if (!chain) 445 if (!node)
455 return -ENOMEM; 446 return -ENOMEM;
456 447
457 chain->nr = 0; 448 *cursor->last = node;
449 }
458 450
459 err = merge_chain_branch(&dst->node, &src->node, chain); 451 node->ip = ip;
452 node->map = map;
453 node->sym = sym;
460 454
461 free(chain); 455 cursor->nr++;
462 456
463 return err; 457 cursor->last = &node->next;
458
459 return 0;
464} 460}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index c15fb8c24ad2..67137256a1cd 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -16,7 +16,7 @@ enum chain_mode {
16 16
17struct callchain_node { 17struct callchain_node {
18 struct callchain_node *parent; 18 struct callchain_node *parent;
19 struct list_head brothers; 19 struct list_head siblings;
20 struct list_head children; 20 struct list_head children;
21 struct list_head val; 21 struct list_head val;
22 struct rb_node rb_node; /* to sort nodes in an rbtree */ 22 struct rb_node rb_node; /* to sort nodes in an rbtree */
@@ -49,9 +49,30 @@ struct callchain_list {
49 struct list_head list; 49 struct list_head list;
50}; 50};
51 51
52/*
53 * A callchain cursor is a single linked list that
54 * let one feed a callchain progressively.
55 * It keeps persitent allocated entries to minimize
56 * allocations.
57 */
58struct callchain_cursor_node {
59 u64 ip;
60 struct map *map;
61 struct symbol *sym;
62 struct callchain_cursor_node *next;
63};
64
65struct callchain_cursor {
66 u64 nr;
67 struct callchain_cursor_node *first;
68 struct callchain_cursor_node **last;
69 u64 pos;
70 struct callchain_cursor_node *curr;
71};
72
52static inline void callchain_init(struct callchain_root *root) 73static inline void callchain_init(struct callchain_root *root)
53{ 74{
54 INIT_LIST_HEAD(&root->node.brothers); 75 INIT_LIST_HEAD(&root->node.siblings);
55 INIT_LIST_HEAD(&root->node.children); 76 INIT_LIST_HEAD(&root->node.children);
56 INIT_LIST_HEAD(&root->node.val); 77 INIT_LIST_HEAD(&root->node.val);
57 78
@@ -61,15 +82,54 @@ static inline void callchain_init(struct callchain_root *root)
61 root->max_depth = 0; 82 root->max_depth = 0;
62} 83}
63 84
64static inline u64 cumul_hits(struct callchain_node *node) 85static inline u64 callchain_cumul_hits(struct callchain_node *node)
65{ 86{
66 return node->hit + node->children_hit; 87 return node->hit + node->children_hit;
67} 88}
68 89
69int register_callchain_param(struct callchain_param *param); 90int callchain_register_param(struct callchain_param *param);
70int callchain_append(struct callchain_root *root, struct ip_callchain *chain, 91int callchain_append(struct callchain_root *root,
71 struct map_symbol *syms, u64 period); 92 struct callchain_cursor *cursor,
72int callchain_merge(struct callchain_root *dst, struct callchain_root *src); 93 u64 period);
94
95int callchain_merge(struct callchain_cursor *cursor,
96 struct callchain_root *dst, struct callchain_root *src);
73 97
74bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); 98bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
99
100/*
101 * Initialize a cursor before adding entries inside, but keep
102 * the previously allocated entries as a cache.
103 */
104static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
105{
106 cursor->nr = 0;
107 cursor->last = &cursor->first;
108}
109
110int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
111 struct map *map, struct symbol *sym);
112
113/* Close a cursor writing session. Initialize for the reader */
114static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
115{
116 cursor->curr = cursor->first;
117 cursor->pos = 0;
118}
119
120/* Cursor reading iteration helpers */
121static inline struct callchain_cursor_node *
122callchain_cursor_current(struct callchain_cursor *cursor)
123{
124 if (cursor->pos == cursor->nr)
125 return NULL;
126
127 return cursor->curr;
128}
129
130static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
131{
132 cursor->curr = cursor->curr->next;
133 cursor->pos++;
134}
75#endif /* __PERF_CALLCHAIN_H */ 135#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 3ccaa1043383..6893eec693ab 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -177,3 +177,8 @@ struct cpu_map *cpu_map__dummy_new(void)
177 177
178 return cpus; 178 return cpus;
179} 179}
180
181void cpu_map__delete(struct cpu_map *map)
182{
183 free(map);
184}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index f7a4f42f6307..072c0a374794 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -8,6 +8,6 @@ struct cpu_map {
8 8
9struct cpu_map *cpu_map__new(const char *cpu_list); 9struct cpu_map *cpu_map__new(const char *cpu_list);
10struct cpu_map *cpu_map__dummy_new(void); 10struct cpu_map *cpu_map__dummy_new(void);
11void *cpu_map__delete(struct cpu_map *map); 11void cpu_map__delete(struct cpu_map *map);
12 12
13#endif /* __PERF_CPUMAP_H */ 13#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1478ab4ee222..e4db8b888546 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -826,128 +826,3 @@ out_filtered:
826 al->filtered = true; 826 al->filtered = true;
827 return 0; 827 return 0;
828} 828}
829
830static int event__parse_id_sample(const event_t *event,
831 struct perf_session *session,
832 struct sample_data *sample)
833{
834 const u64 *array;
835 u64 type;
836
837 sample->cpu = sample->pid = sample->tid = -1;
838 sample->stream_id = sample->id = sample->time = -1ULL;
839
840 if (!session->sample_id_all)
841 return 0;
842
843 array = event->sample.array;
844 array += ((event->header.size -
845 sizeof(event->header)) / sizeof(u64)) - 1;
846 type = session->sample_type;
847
848 if (type & PERF_SAMPLE_CPU) {
849 u32 *p = (u32 *)array;
850 sample->cpu = *p;
851 array--;
852 }
853
854 if (type & PERF_SAMPLE_STREAM_ID) {
855 sample->stream_id = *array;
856 array--;
857 }
858
859 if (type & PERF_SAMPLE_ID) {
860 sample->id = *array;
861 array--;
862 }
863
864 if (type & PERF_SAMPLE_TIME) {
865 sample->time = *array;
866 array--;
867 }
868
869 if (type & PERF_SAMPLE_TID) {
870 u32 *p = (u32 *)array;
871 sample->pid = p[0];
872 sample->tid = p[1];
873 }
874
875 return 0;
876}
877
878int event__parse_sample(const event_t *event, struct perf_session *session,
879 struct sample_data *data)
880{
881 const u64 *array;
882 u64 type;
883
884 if (event->header.type != PERF_RECORD_SAMPLE)
885 return event__parse_id_sample(event, session, data);
886
887 array = event->sample.array;
888 type = session->sample_type;
889
890 if (type & PERF_SAMPLE_IP) {
891 data->ip = event->ip.ip;
892 array++;
893 }
894
895 if (type & PERF_SAMPLE_TID) {
896 u32 *p = (u32 *)array;
897 data->pid = p[0];
898 data->tid = p[1];
899 array++;
900 }
901
902 if (type & PERF_SAMPLE_TIME) {
903 data->time = *array;
904 array++;
905 }
906
907 if (type & PERF_SAMPLE_ADDR) {
908 data->addr = *array;
909 array++;
910 }
911
912 data->id = -1ULL;
913 if (type & PERF_SAMPLE_ID) {
914 data->id = *array;
915 array++;
916 }
917
918 if (type & PERF_SAMPLE_STREAM_ID) {
919 data->stream_id = *array;
920 array++;
921 }
922
923 if (type & PERF_SAMPLE_CPU) {
924 u32 *p = (u32 *)array;
925 data->cpu = *p;
926 array++;
927 } else
928 data->cpu = -1;
929
930 if (type & PERF_SAMPLE_PERIOD) {
931 data->period = *array;
932 array++;
933 }
934
935 if (type & PERF_SAMPLE_READ) {
936 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
937 return -1;
938 }
939
940 if (type & PERF_SAMPLE_CALLCHAIN) {
941 data->callchain = (struct ip_callchain *)array;
942 array += 1 + data->callchain->nr;
943 }
944
945 if (type & PERF_SAMPLE_RAW) {
946 u32 *p = (u32 *)array;
947 data->raw_size = *p;
948 p++;
949 data->raw_data = p;
950 }
951
952 return 0;
953}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2b7e91902f10..d79e4edd82f9 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -169,9 +169,10 @@ struct addr_location;
169int event__preprocess_sample(const event_t *self, struct perf_session *session, 169int event__preprocess_sample(const event_t *self, struct perf_session *session,
170 struct addr_location *al, struct sample_data *data, 170 struct addr_location *al, struct sample_data *data,
171 symbol_filter_t filter); 171 symbol_filter_t filter);
172int event__parse_sample(const event_t *event, struct perf_session *session,
173 struct sample_data *sample);
174 172
175const char *event__get_event_name(unsigned int id); 173const char *event__get_event_name(unsigned int id);
176 174
175int event__parse_sample(const event_t *event, u64 type, bool sample_id_all,
176 struct sample_data *sample);
177
177#endif /* __PERF_RECORD_H */ 178#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
new file mode 100644
index 000000000000..df0610e9c61b
--- /dev/null
+++ b/tools/perf/util/evlist.c
@@ -0,0 +1,170 @@
1#include <poll.h>
2#include "evlist.h"
3#include "evsel.h"
4#include "util.h"
5
6#include <linux/bitops.h>
7#include <linux/hash.h>
8
9void perf_evlist__init(struct perf_evlist *evlist)
10{
11 int i;
12
13 for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
14 INIT_HLIST_HEAD(&evlist->heads[i]);
15 INIT_LIST_HEAD(&evlist->entries);
16}
17
18struct perf_evlist *perf_evlist__new(void)
19{
20 struct perf_evlist *evlist = zalloc(sizeof(*evlist));
21
22 if (evlist != NULL)
23 perf_evlist__init(evlist);
24
25 return evlist;
26}
27
28static void perf_evlist__purge(struct perf_evlist *evlist)
29{
30 struct perf_evsel *pos, *n;
31
32 list_for_each_entry_safe(pos, n, &evlist->entries, node) {
33 list_del_init(&pos->node);
34 perf_evsel__delete(pos);
35 }
36
37 evlist->nr_entries = 0;
38}
39
40void perf_evlist__exit(struct perf_evlist *evlist)
41{
42 free(evlist->mmap);
43 free(evlist->pollfd);
44 evlist->mmap = NULL;
45 evlist->pollfd = NULL;
46}
47
48void perf_evlist__delete(struct perf_evlist *evlist)
49{
50 perf_evlist__purge(evlist);
51 perf_evlist__exit(evlist);
52 free(evlist);
53}
54
55void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
56{
57 list_add_tail(&entry->node, &evlist->entries);
58 ++evlist->nr_entries;
59}
60
61int perf_evlist__add_default(struct perf_evlist *evlist)
62{
63 struct perf_event_attr attr = {
64 .type = PERF_TYPE_HARDWARE,
65 .config = PERF_COUNT_HW_CPU_CYCLES,
66 };
67 struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
68
69 if (evsel == NULL)
70 return -ENOMEM;
71
72 perf_evlist__add(evlist, evsel);
73 return 0;
74}
75
76int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads)
77{
78 int nfds = ncpus * nthreads * evlist->nr_entries;
79 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
80 return evlist->pollfd != NULL ? 0 : -ENOMEM;
81}
82
83void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
84{
85 fcntl(fd, F_SETFL, O_NONBLOCK);
86 evlist->pollfd[evlist->nr_fds].fd = fd;
87 evlist->pollfd[evlist->nr_fds].events = POLLIN;
88 evlist->nr_fds++;
89}
90
91struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
92{
93 struct hlist_head *head;
94 struct hlist_node *pos;
95 struct perf_sample_id *sid;
96 int hash;
97
98 if (evlist->nr_entries == 1)
99 return list_entry(evlist->entries.next, struct perf_evsel, node);
100
101 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
102 head = &evlist->heads[hash];
103
104 hlist_for_each_entry(sid, pos, head, node)
105 if (sid->id == id)
106 return sid->evsel;
107 return NULL;
108}
109
110event_t *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu)
111{
112 /* XXX Move this to perf.c, making it generally available */
113 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
114 struct perf_mmap *md = &evlist->mmap[cpu];
115 unsigned int head = perf_mmap__read_head(md);
116 unsigned int old = md->prev;
117 unsigned char *data = md->base + page_size;
118 event_t *event = NULL;
119 int diff;
120
121 /*
122 * If we're further behind than half the buffer, there's a chance
123 * the writer will bite our tail and mess up the samples under us.
124 *
125 * If we somehow ended up ahead of the head, we got messed up.
126 *
127 * In either case, truncate and restart at head.
128 */
129 diff = head - old;
130 if (diff > md->mask / 2 || diff < 0) {
131 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
132
133 /*
134 * head points to a known good entry, start there.
135 */
136 old = head;
137 }
138
139 if (old != head) {
140 size_t size;
141
142 event = (event_t *)&data[old & md->mask];
143 size = event->header.size;
144
145 /*
146 * Event straddles the mmap boundary -- header should always
147 * be inside due to u64 alignment of output.
148 */
149 if ((old & md->mask) + size != ((old + size) & md->mask)) {
150 unsigned int offset = old;
151 unsigned int len = min(sizeof(*event), size), cpy;
152 void *dst = &evlist->event_copy;
153
154 do {
155 cpy = min(md->mask + 1 - (offset & md->mask), len);
156 memcpy(dst, &data[offset & md->mask], cpy);
157 offset += cpy;
158 dst += cpy;
159 len -= cpy;
160 } while (len);
161
162 event = &evlist->event_copy;
163 }
164
165 old += size;
166 }
167
168 md->prev = old;
169 return event;
170}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
new file mode 100644
index 000000000000..acbe48eac608
--- /dev/null
+++ b/tools/perf/util/evlist.h
@@ -0,0 +1,41 @@
1#ifndef __PERF_EVLIST_H
2#define __PERF_EVLIST_H 1
3
4#include <linux/list.h>
5#include "../perf.h"
6#include "event.h"
7
8struct pollfd;
9
10#define PERF_EVLIST__HLIST_BITS 8
11#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
12
13struct perf_evlist {
14 struct list_head entries;
15 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
16 int nr_entries;
17 int nr_fds;
18 int mmap_len;
19 event_t event_copy;
20 struct perf_mmap *mmap;
21 struct pollfd *pollfd;
22};
23
24struct perf_evsel;
25
26struct perf_evlist *perf_evlist__new(void);
27void perf_evlist__init(struct perf_evlist *evlist);
28void perf_evlist__exit(struct perf_evlist *evlist);
29void perf_evlist__delete(struct perf_evlist *evlist);
30
31void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
32int perf_evlist__add_default(struct perf_evlist *evlist);
33
34int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads);
35void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
36
37struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
38
39event_t *perf_evlist__read_on_cpu(struct perf_evlist *self, int cpu);
40
41#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index f5cfed60af98..76ab553637d6 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1,20 +1,33 @@
1#include "evsel.h" 1#include "evsel.h"
2#include "evlist.h"
2#include "../perf.h" 3#include "../perf.h"
3#include "util.h" 4#include "util.h"
4#include "cpumap.h" 5#include "cpumap.h"
5#include "thread.h" 6#include "thread_map.h"
7
8#include <unistd.h>
9#include <sys/mman.h>
10
11#include <linux/bitops.h>
12#include <linux/hash.h>
6 13
7#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 14#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
15#define SID(e, x, y) xyarray__entry(e->id, x, y)
16
17void perf_evsel__init(struct perf_evsel *evsel,
18 struct perf_event_attr *attr, int idx)
19{
20 evsel->idx = idx;
21 evsel->attr = *attr;
22 INIT_LIST_HEAD(&evsel->node);
23}
8 24
9struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 25struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
10{ 26{
11 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 27 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
12 28
13 if (evsel != NULL) { 29 if (evsel != NULL)
14 evsel->idx = idx; 30 perf_evsel__init(evsel, attr, idx);
15 evsel->attr = *attr;
16 INIT_LIST_HEAD(&evsel->node);
17 }
18 31
19 return evsel; 32 return evsel;
20} 33}
@@ -25,6 +38,12 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
25 return evsel->fd != NULL ? 0 : -ENOMEM; 38 return evsel->fd != NULL ? 0 : -ENOMEM;
26} 39}
27 40
41int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
42{
43 evsel->id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
44 return evsel->id != NULL ? 0 : -ENOMEM;
45}
46
28int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 47int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
29{ 48{
30 evsel->counts = zalloc((sizeof(*evsel->counts) + 49 evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -38,6 +57,12 @@ void perf_evsel__free_fd(struct perf_evsel *evsel)
38 evsel->fd = NULL; 57 evsel->fd = NULL;
39} 58}
40 59
60void perf_evsel__free_id(struct perf_evsel *evsel)
61{
62 xyarray__delete(evsel->id);
63 evsel->id = NULL;
64}
65
41void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 66void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
42{ 67{
43 int cpu, thread; 68 int cpu, thread;
@@ -49,10 +74,34 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
49 } 74 }
50} 75}
51 76
52void perf_evsel__delete(struct perf_evsel *evsel) 77void perf_evlist__munmap(struct perf_evlist *evlist, int ncpus)
78{
79 int cpu;
80
81 for (cpu = 0; cpu < ncpus; cpu++) {
82 if (evlist->mmap[cpu].base != NULL) {
83 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
84 evlist->mmap[cpu].base = NULL;
85 }
86 }
87}
88
89int perf_evlist__alloc_mmap(struct perf_evlist *evlist, int ncpus)
90{
91 evlist->mmap = zalloc(ncpus * sizeof(struct perf_mmap));
92 return evlist->mmap != NULL ? 0 : -ENOMEM;
93}
94
95void perf_evsel__exit(struct perf_evsel *evsel)
53{ 96{
54 assert(list_empty(&evsel->node)); 97 assert(list_empty(&evsel->node));
55 xyarray__delete(evsel->fd); 98 xyarray__delete(evsel->fd);
99 xyarray__delete(evsel->id);
100}
101
102void perf_evsel__delete(struct perf_evsel *evsel)
103{
104 perf_evsel__exit(evsel);
56 free(evsel); 105 free(evsel);
57} 106}
58 107
@@ -128,7 +177,7 @@ int __perf_evsel__read(struct perf_evsel *evsel,
128} 177}
129 178
130static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 179static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
131 struct thread_map *threads) 180 struct thread_map *threads, bool group, bool inherit)
132{ 181{
133 int cpu, thread; 182 int cpu, thread;
134 183
@@ -137,12 +186,20 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
137 return -1; 186 return -1;
138 187
139 for (cpu = 0; cpu < cpus->nr; cpu++) { 188 for (cpu = 0; cpu < cpus->nr; cpu++) {
189 int group_fd = -1;
190
191 evsel->attr.inherit = (cpus->map[cpu] < 0) && inherit;
192
140 for (thread = 0; thread < threads->nr; thread++) { 193 for (thread = 0; thread < threads->nr; thread++) {
141 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 194 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
142 threads->map[thread], 195 threads->map[thread],
143 cpus->map[cpu], -1, 0); 196 cpus->map[cpu],
197 group_fd, 0);
144 if (FD(evsel, cpu, thread) < 0) 198 if (FD(evsel, cpu, thread) < 0)
145 goto out_close; 199 goto out_close;
200
201 if (group && group_fd == -1)
202 group_fd = FD(evsel, cpu, thread);
146 } 203 }
147 } 204 }
148 205
@@ -175,10 +232,9 @@ static struct {
175 .threads = { -1, }, 232 .threads = { -1, },
176}; 233};
177 234
178int perf_evsel__open(struct perf_evsel *evsel, 235int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
179 struct cpu_map *cpus, struct thread_map *threads) 236 struct thread_map *threads, bool group, bool inherit)
180{ 237{
181
182 if (cpus == NULL) { 238 if (cpus == NULL) {
183 /* Work around old compiler warnings about strict aliasing */ 239 /* Work around old compiler warnings about strict aliasing */
184 cpus = &empty_cpu_map.map; 240 cpus = &empty_cpu_map.map;
@@ -187,15 +243,243 @@ int perf_evsel__open(struct perf_evsel *evsel,
187 if (threads == NULL) 243 if (threads == NULL)
188 threads = &empty_thread_map.map; 244 threads = &empty_thread_map.map;
189 245
190 return __perf_evsel__open(evsel, cpus, threads); 246 return __perf_evsel__open(evsel, cpus, threads, group, inherit);
247}
248
249int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
250 struct cpu_map *cpus, bool group, bool inherit)
251{
252 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit);
253}
254
255int perf_evsel__open_per_thread(struct perf_evsel *evsel,
256 struct thread_map *threads, bool group, bool inherit)
257{
258 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit);
259}
260
261static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, int prot,
262 int mask, int fd)
263{
264 evlist->mmap[cpu].prev = 0;
265 evlist->mmap[cpu].mask = mask;
266 evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot,
267 MAP_SHARED, fd, 0);
268 if (evlist->mmap[cpu].base == MAP_FAILED)
269 return -1;
270
271 perf_evlist__add_pollfd(evlist, fd);
272 return 0;
273}
274
275static int perf_evlist__id_hash(struct perf_evlist *evlist, struct perf_evsel *evsel,
276 int cpu, int thread, int fd)
277{
278 struct perf_sample_id *sid;
279 u64 read_data[4] = { 0, };
280 int hash, id_idx = 1; /* The first entry is the counter value */
281
282 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
283 read(fd, &read_data, sizeof(read_data)) == -1)
284 return -1;
285
286 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
287 ++id_idx;
288 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
289 ++id_idx;
290
291 sid = SID(evsel, cpu, thread);
292 sid->id = read_data[id_idx];
293 sid->evsel = evsel;
294 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
295 hlist_add_head(&sid->node, &evlist->heads[hash]);
296 return 0;
297}
298
299/** perf_evlist__mmap - Create per cpu maps to receive events
300 *
301 * @evlist - list of events
302 * @cpus - cpu map being monitored
303 * @threads - threads map being monitored
304 * @pages - map length in pages
305 * @overwrite - overwrite older events?
306 *
307 * If overwrite is false the user needs to signal event consuption using:
308 *
309 * struct perf_mmap *m = &evlist->mmap[cpu];
310 * unsigned int head = perf_mmap__read_head(m);
311 *
312 * perf_mmap__write_tail(m, head)
313 */
314int perf_evlist__mmap(struct perf_evlist *evlist, struct cpu_map *cpus,
315 struct thread_map *threads, int pages, bool overwrite)
316{
317 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
318 int mask = pages * page_size - 1, cpu;
319 struct perf_evsel *first_evsel, *evsel;
320 int thread, prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
321
322 if (evlist->mmap == NULL &&
323 perf_evlist__alloc_mmap(evlist, cpus->nr) < 0)
324 return -ENOMEM;
325
326 if (evlist->pollfd == NULL &&
327 perf_evlist__alloc_pollfd(evlist, cpus->nr, threads->nr) < 0)
328 return -ENOMEM;
329
330 evlist->mmap_len = (pages + 1) * page_size;
331 first_evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
332
333 list_for_each_entry(evsel, &evlist->entries, node) {
334 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
335 evsel->id == NULL &&
336 perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
337 return -ENOMEM;
338
339 for (cpu = 0; cpu < cpus->nr; cpu++) {
340 for (thread = 0; thread < threads->nr; thread++) {
341 int fd = FD(evsel, cpu, thread);
342
343 if (evsel->idx || thread) {
344 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT,
345 FD(first_evsel, cpu, 0)) != 0)
346 goto out_unmap;
347 } else if (__perf_evlist__mmap(evlist, cpu, prot, mask, fd) < 0)
348 goto out_unmap;
349
350 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
351 perf_evlist__id_hash(evlist, evsel, cpu, thread, fd) < 0)
352 goto out_unmap;
353 }
354 }
355 }
356
357 return 0;
358
359out_unmap:
360 for (cpu = 0; cpu < cpus->nr; cpu++) {
361 if (evlist->mmap[cpu].base != NULL) {
362 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
363 evlist->mmap[cpu].base = NULL;
364 }
365 }
366 return -1;
191} 367}
192 368
193int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) 369static int event__parse_id_sample(const event_t *event, u64 type,
370 struct sample_data *sample)
194{ 371{
195 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); 372 const u64 *array = event->sample.array;
373
374 array += ((event->header.size -
375 sizeof(event->header)) / sizeof(u64)) - 1;
376
377 if (type & PERF_SAMPLE_CPU) {
378 u32 *p = (u32 *)array;
379 sample->cpu = *p;
380 array--;
381 }
382
383 if (type & PERF_SAMPLE_STREAM_ID) {
384 sample->stream_id = *array;
385 array--;
386 }
387
388 if (type & PERF_SAMPLE_ID) {
389 sample->id = *array;
390 array--;
391 }
392
393 if (type & PERF_SAMPLE_TIME) {
394 sample->time = *array;
395 array--;
396 }
397
398 if (type & PERF_SAMPLE_TID) {
399 u32 *p = (u32 *)array;
400 sample->pid = p[0];
401 sample->tid = p[1];
402 }
403
404 return 0;
196} 405}
197 406
198int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) 407int event__parse_sample(const event_t *event, u64 type, bool sample_id_all,
408 struct sample_data *data)
199{ 409{
200 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); 410 const u64 *array;
411
412 data->cpu = data->pid = data->tid = -1;
413 data->stream_id = data->id = data->time = -1ULL;
414
415 if (event->header.type != PERF_RECORD_SAMPLE) {
416 if (!sample_id_all)
417 return 0;
418 return event__parse_id_sample(event, type, data);
419 }
420
421 array = event->sample.array;
422
423 if (type & PERF_SAMPLE_IP) {
424 data->ip = event->ip.ip;
425 array++;
426 }
427
428 if (type & PERF_SAMPLE_TID) {
429 u32 *p = (u32 *)array;
430 data->pid = p[0];
431 data->tid = p[1];
432 array++;
433 }
434
435 if (type & PERF_SAMPLE_TIME) {
436 data->time = *array;
437 array++;
438 }
439
440 if (type & PERF_SAMPLE_ADDR) {
441 data->addr = *array;
442 array++;
443 }
444
445 data->id = -1ULL;
446 if (type & PERF_SAMPLE_ID) {
447 data->id = *array;
448 array++;
449 }
450
451 if (type & PERF_SAMPLE_STREAM_ID) {
452 data->stream_id = *array;
453 array++;
454 }
455
456 if (type & PERF_SAMPLE_CPU) {
457 u32 *p = (u32 *)array;
458 data->cpu = *p;
459 array++;
460 }
461
462 if (type & PERF_SAMPLE_PERIOD) {
463 data->period = *array;
464 array++;
465 }
466
467 if (type & PERF_SAMPLE_READ) {
468 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
469 return -1;
470 }
471
472 if (type & PERF_SAMPLE_CALLCHAIN) {
473 data->callchain = (struct ip_callchain *)array;
474 array += 1 + data->callchain->nr;
475 }
476
477 if (type & PERF_SAMPLE_RAW) {
478 u32 *p = (u32 *)array;
479 data->raw_size = *p;
480 p++;
481 data->raw_data = p;
482 }
483
484 return 0;
201} 485}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b2d755fe88a5..7962e7587dea 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -24,11 +24,24 @@ struct perf_counts {
24 struct perf_counts_values cpu[]; 24 struct perf_counts_values cpu[];
25}; 25};
26 26
27struct perf_evsel;
28
29/*
30 * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are
31 * more than one entry in the evlist.
32 */
33struct perf_sample_id {
34 struct hlist_node node;
35 u64 id;
36 struct perf_evsel *evsel;
37};
38
27struct perf_evsel { 39struct perf_evsel {
28 struct list_head node; 40 struct list_head node;
29 struct perf_event_attr attr; 41 struct perf_event_attr attr;
30 char *filter; 42 char *filter;
31 struct xyarray *fd; 43 struct xyarray *fd;
44 struct xyarray *id;
32 struct perf_counts *counts; 45 struct perf_counts *counts;
33 int idx; 46 int idx;
34 void *priv; 47 void *priv;
@@ -36,19 +49,31 @@ struct perf_evsel {
36 49
37struct cpu_map; 50struct cpu_map;
38struct thread_map; 51struct thread_map;
52struct perf_evlist;
39 53
40struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); 54struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
55void perf_evsel__init(struct perf_evsel *evsel,
56 struct perf_event_attr *attr, int idx);
57void perf_evsel__exit(struct perf_evsel *evsel);
41void perf_evsel__delete(struct perf_evsel *evsel); 58void perf_evsel__delete(struct perf_evsel *evsel);
42 59
43int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 60int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
61int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
44int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 62int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
63int perf_evlist__alloc_mmap(struct perf_evlist *evlist, int ncpus);
45void perf_evsel__free_fd(struct perf_evsel *evsel); 64void perf_evsel__free_fd(struct perf_evsel *evsel);
65void perf_evsel__free_id(struct perf_evsel *evsel);
46void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 66void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
47 67
48int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus); 68int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
49int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads); 69 struct cpu_map *cpus, bool group, bool inherit);
50int perf_evsel__open(struct perf_evsel *evsel, 70int perf_evsel__open_per_thread(struct perf_evsel *evsel,
51 struct cpu_map *cpus, struct thread_map *threads); 71 struct thread_map *threads, bool group, bool inherit);
72int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
73 struct thread_map *threads, bool group, bool inherit);
74int perf_evlist__mmap(struct perf_evlist *evlist, struct cpu_map *cpus,
75 struct thread_map *threads, int pages, bool overwrite);
76void perf_evlist__munmap(struct perf_evlist *evlist, int ncpus);
52 77
53#define perf_evsel__match(evsel, t, c) \ 78#define perf_evsel__match(evsel, t, c) \
54 (evsel->attr.type == PERF_TYPE_##t && \ 79 (evsel->attr.type == PERF_TYPE_##t && \
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f6a929e74981..f0138d472339 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -8,6 +8,7 @@
8#include <linux/list.h> 8#include <linux/list.h>
9#include <linux/kernel.h> 9#include <linux/kernel.h>
10 10
11#include "evlist.h"
11#include "util.h" 12#include "util.h"
12#include "header.h" 13#include "header.h"
13#include "../perf.h" 14#include "../perf.h"
@@ -428,7 +429,8 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi
428 return ret; 429 return ret;
429} 430}
430 431
431static int perf_header__adds_write(struct perf_header *self, int fd) 432static int perf_header__adds_write(struct perf_header *self,
433 struct perf_evlist *evlist, int fd)
432{ 434{
433 int nr_sections; 435 int nr_sections;
434 struct perf_session *session; 436 struct perf_session *session;
@@ -463,7 +465,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
463 465
464 /* Write trace info */ 466 /* Write trace info */
465 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 467 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
466 read_tracing_data(fd, &evsel_list); 468 read_tracing_data(fd, &evlist->entries);
467 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 469 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
468 } 470 }
469 471
@@ -513,7 +515,8 @@ int perf_header__write_pipe(int fd)
513 return 0; 515 return 0;
514} 516}
515 517
516int perf_header__write(struct perf_header *self, int fd, bool at_exit) 518int perf_header__write(struct perf_header *self, struct perf_evlist *evlist,
519 int fd, bool at_exit)
517{ 520{
518 struct perf_file_header f_header; 521 struct perf_file_header f_header;
519 struct perf_file_attr f_attr; 522 struct perf_file_attr f_attr;
@@ -566,7 +569,7 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
566 self->data_offset = lseek(fd, 0, SEEK_CUR); 569 self->data_offset = lseek(fd, 0, SEEK_CUR);
567 570
568 if (at_exit) { 571 if (at_exit) {
569 err = perf_header__adds_write(self, fd); 572 err = perf_header__adds_write(self, evlist, fd);
570 if (err < 0) 573 if (err < 0)
571 return err; 574 return err;
572 } 575 }
@@ -1133,7 +1136,7 @@ int event__process_event_type(event_t *self,
1133 return 0; 1136 return 0;
1134} 1137}
1135 1138
1136int event__synthesize_tracing_data(int fd, struct list_head *pattrs, 1139int event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
1137 event__handler_t process, 1140 event__handler_t process,
1138 struct perf_session *session __unused) 1141 struct perf_session *session __unused)
1139{ 1142{
@@ -1144,7 +1147,7 @@ int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
1144 memset(&ev, 0, sizeof(ev)); 1147 memset(&ev, 0, sizeof(ev));
1145 1148
1146 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1149 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1147 size = read_tracing_data_size(fd, pattrs); 1150 size = read_tracing_data_size(fd, &evlist->entries);
1148 if (size <= 0) 1151 if (size <= 0)
1149 return size; 1152 return size;
1150 aligned_size = ALIGN(size, sizeof(u64)); 1153 aligned_size = ALIGN(size, sizeof(u64));
@@ -1154,7 +1157,7 @@ int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
1154 1157
1155 process(&ev, NULL, session); 1158 process(&ev, NULL, session);
1156 1159
1157 err = read_tracing_data(fd, pattrs); 1160 err = read_tracing_data(fd, &evlist->entries);
1158 write_padded(fd, NULL, 0, padding); 1161 write_padded(fd, NULL, 0, padding);
1159 1162
1160 return aligned_size; 1163 return aligned_size;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 33f16be7b72f..65afd7f74e0d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -65,8 +65,11 @@ struct perf_header {
65int perf_header__init(struct perf_header *self); 65int perf_header__init(struct perf_header *self);
66void perf_header__exit(struct perf_header *self); 66void perf_header__exit(struct perf_header *self);
67 67
68struct perf_evlist;
69
68int perf_header__read(struct perf_session *session, int fd); 70int perf_header__read(struct perf_session *session, int fd);
69int perf_header__write(struct perf_header *self, int fd, bool at_exit); 71int perf_header__write(struct perf_header *self, struct perf_evlist *evlist,
72 int fd, bool at_exit);
70int perf_header__write_pipe(int fd); 73int perf_header__write_pipe(int fd);
71 74
72int perf_header__add_attr(struct perf_header *self, 75int perf_header__add_attr(struct perf_header *self,
@@ -113,7 +116,7 @@ int event__synthesize_event_types(event__handler_t process,
113int event__process_event_type(event_t *self, 116int event__process_event_type(event_t *self,
114 struct perf_session *session); 117 struct perf_session *session);
115 118
116int event__synthesize_tracing_data(int fd, struct list_head *pattrs, 119int event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
117 event__handler_t process, 120 event__handler_t process,
118 struct perf_session *session); 121 struct perf_session *session);
119int event__process_tracing_data(event_t *self, 122int event__process_tracing_data(event_t *self,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 32f4f1f2f6e4..02ed318d7312 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -211,7 +211,9 @@ void hist_entry__free(struct hist_entry *he)
211 * collapse the histogram 211 * collapse the histogram
212 */ 212 */
213 213
214static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he) 214static bool hists__collapse_insert_entry(struct hists *self,
215 struct rb_root *root,
216 struct hist_entry *he)
215{ 217{
216 struct rb_node **p = &root->rb_node; 218 struct rb_node **p = &root->rb_node;
217 struct rb_node *parent = NULL; 219 struct rb_node *parent = NULL;
@@ -226,8 +228,11 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
226 228
227 if (!cmp) { 229 if (!cmp) {
228 iter->period += he->period; 230 iter->period += he->period;
229 if (symbol_conf.use_callchain) 231 if (symbol_conf.use_callchain) {
230 callchain_merge(iter->callchain, he->callchain); 232 callchain_cursor_reset(&self->callchain_cursor);
233 callchain_merge(&self->callchain_cursor, iter->callchain,
234 he->callchain);
235 }
231 hist_entry__free(he); 236 hist_entry__free(he);
232 return false; 237 return false;
233 } 238 }
@@ -262,7 +267,7 @@ void hists__collapse_resort(struct hists *self)
262 next = rb_next(&n->rb_node); 267 next = rb_next(&n->rb_node);
263 268
264 rb_erase(&n->rb_node, &self->entries); 269 rb_erase(&n->rb_node, &self->entries);
265 if (collapse__insert_entry(&tmp, n)) 270 if (hists__collapse_insert_entry(self, &tmp, n))
266 hists__inc_nr_entries(self, n); 271 hists__inc_nr_entries(self, n);
267 } 272 }
268 273
@@ -425,7 +430,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
425 u64 cumul; 430 u64 cumul;
426 431
427 child = rb_entry(node, struct callchain_node, rb_node); 432 child = rb_entry(node, struct callchain_node, rb_node);
428 cumul = cumul_hits(child); 433 cumul = callchain_cumul_hits(child);
429 remaining -= cumul; 434 remaining -= cumul;
430 435
431 /* 436 /*
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index ee789856a8c9..889559b86492 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -77,6 +77,8 @@ struct hists {
77 u64 event_stream; 77 u64 event_stream;
78 u32 type; 78 u32 type;
79 u16 col_len[HISTC_NR_COLS]; 79 u16 col_len[HISTC_NR_COLS];
80 /* Best would be to reuse the session callchain cursor */
81 struct callchain_cursor callchain_cursor;
80}; 82};
81 83
82struct hist_entry *__hists__add_entry(struct hists *self, 84struct hist_entry *__hists__add_entry(struct hists *self,
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index f5ca26e53fbb..356c7e467b83 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,3 +1,4 @@
1#include <linux/kernel.h>
1#include "../../../../include/linux/list.h" 2#include "../../../../include/linux/list.h"
2 3
3#ifndef PERF_LIST_H 4#ifndef PERF_LIST_H
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 135f69baf966..cf082daa43e3 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,6 +1,7 @@
1#include "../../../include/linux/hw_breakpoint.h" 1#include "../../../include/linux/hw_breakpoint.h"
2#include "util.h" 2#include "util.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "evlist.h"
4#include "evsel.h" 5#include "evsel.h"
5#include "parse-options.h" 6#include "parse-options.h"
6#include "parse-events.h" 7#include "parse-events.h"
@@ -11,10 +12,6 @@
11#include "header.h" 12#include "header.h"
12#include "debugfs.h" 13#include "debugfs.h"
13 14
14int nr_counters;
15
16LIST_HEAD(evsel_list);
17
18struct event_symbol { 15struct event_symbol {
19 u8 type; 16 u8 type;
20 u64 config; 17 u64 config;
@@ -449,8 +446,8 @@ parse_single_tracepoint_event(char *sys_name,
449/* sys + ':' + event + ':' + flags*/ 446/* sys + ':' + event + ':' + flags*/
450#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 447#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
451static enum event_result 448static enum event_result
452parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, 449parse_multiple_tracepoint_event(const struct option *opt, char *sys_name,
453 char *flags) 450 const char *evt_exp, char *flags)
454{ 451{
455 char evt_path[MAXPATHLEN]; 452 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 453 struct dirent *evt_ent;
@@ -483,15 +480,16 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
483 if (len < 0) 480 if (len < 0)
484 return EVT_FAILED; 481 return EVT_FAILED;
485 482
486 if (parse_events(NULL, event_opt, 0)) 483 if (parse_events(opt, event_opt, 0))
487 return EVT_FAILED; 484 return EVT_FAILED;
488 } 485 }
489 486
490 return EVT_HANDLED_ALL; 487 return EVT_HANDLED_ALL;
491} 488}
492 489
493static enum event_result parse_tracepoint_event(const char **strp, 490static enum event_result
494 struct perf_event_attr *attr) 491parse_tracepoint_event(const struct option *opt, const char **strp,
492 struct perf_event_attr *attr)
495{ 493{
496 const char *evt_name; 494 const char *evt_name;
497 char *flags = NULL, *comma_loc; 495 char *flags = NULL, *comma_loc;
@@ -530,7 +528,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
530 return EVT_FAILED; 528 return EVT_FAILED;
531 if (strpbrk(evt_name, "*?")) { 529 if (strpbrk(evt_name, "*?")) {
532 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ 530 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
533 return parse_multiple_tracepoint_event(sys_name, evt_name, 531 return parse_multiple_tracepoint_event(opt, sys_name, evt_name,
534 flags); 532 flags);
535 } else { 533 } else {
536 return parse_single_tracepoint_event(sys_name, evt_name, 534 return parse_single_tracepoint_event(sys_name, evt_name,
@@ -740,11 +738,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
740 * Symbolic names are (almost) exactly matched. 738 * Symbolic names are (almost) exactly matched.
741 */ 739 */
742static enum event_result 740static enum event_result
743parse_event_symbols(const char **str, struct perf_event_attr *attr) 741parse_event_symbols(const struct option *opt, const char **str,
742 struct perf_event_attr *attr)
744{ 743{
745 enum event_result ret; 744 enum event_result ret;
746 745
747 ret = parse_tracepoint_event(str, attr); 746 ret = parse_tracepoint_event(opt, str, attr);
748 if (ret != EVT_FAILED) 747 if (ret != EVT_FAILED)
749 goto modifier; 748 goto modifier;
750 749
@@ -778,14 +777,15 @@ modifier:
778 return ret; 777 return ret;
779} 778}
780 779
781int parse_events(const struct option *opt __used, const char *str, int unset __used) 780int parse_events(const struct option *opt, const char *str, int unset __used)
782{ 781{
782 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
783 struct perf_event_attr attr; 783 struct perf_event_attr attr;
784 enum event_result ret; 784 enum event_result ret;
785 785
786 for (;;) { 786 for (;;) {
787 memset(&attr, 0, sizeof(attr)); 787 memset(&attr, 0, sizeof(attr));
788 ret = parse_event_symbols(&str, &attr); 788 ret = parse_event_symbols(opt, &str, &attr);
789 if (ret == EVT_FAILED) 789 if (ret == EVT_FAILED)
790 return -1; 790 return -1;
791 791
@@ -794,12 +794,10 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
794 794
795 if (ret != EVT_HANDLED_ALL) { 795 if (ret != EVT_HANDLED_ALL) {
796 struct perf_evsel *evsel; 796 struct perf_evsel *evsel;
797 evsel = perf_evsel__new(&attr, 797 evsel = perf_evsel__new(&attr, evlist->nr_entries);
798 nr_counters);
799 if (evsel == NULL) 798 if (evsel == NULL)
800 return -1; 799 return -1;
801 list_add_tail(&evsel->node, &evsel_list); 800 perf_evlist__add(evlist, evsel);
802 ++nr_counters;
803 } 801 }
804 802
805 if (*str == 0) 803 if (*str == 0)
@@ -813,13 +811,14 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
813 return 0; 811 return 0;
814} 812}
815 813
816int parse_filter(const struct option *opt __used, const char *str, 814int parse_filter(const struct option *opt, const char *str,
817 int unset __used) 815 int unset __used)
818{ 816{
817 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
819 struct perf_evsel *last = NULL; 818 struct perf_evsel *last = NULL;
820 819
821 if (!list_empty(&evsel_list)) 820 if (evlist->nr_entries > 0)
822 last = list_entry(evsel_list.prev, struct perf_evsel, node); 821 last = list_entry(evlist->entries.prev, struct perf_evsel, node);
823 822
824 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { 823 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
825 fprintf(stderr, 824 fprintf(stderr,
@@ -981,33 +980,3 @@ void print_events(void)
981 980
982 exit(129); 981 exit(129);
983} 982}
984
985int perf_evsel_list__create_default(void)
986{
987 struct perf_evsel *evsel;
988 struct perf_event_attr attr;
989
990 memset(&attr, 0, sizeof(attr));
991 attr.type = PERF_TYPE_HARDWARE;
992 attr.config = PERF_COUNT_HW_CPU_CYCLES;
993
994 evsel = perf_evsel__new(&attr, 0);
995
996 if (evsel == NULL)
997 return -ENOMEM;
998
999 list_add(&evsel->node, &evsel_list);
1000 ++nr_counters;
1001 return 0;
1002}
1003
1004void perf_evsel_list__delete(void)
1005{
1006 struct perf_evsel *pos, *n;
1007
1008 list_for_each_entry_safe(pos, n, &evsel_list, node) {
1009 list_del_init(&pos->node);
1010 perf_evsel__delete(pos);
1011 }
1012 nr_counters = 0;
1013}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 458e3ecf17af..cf7e94abb676 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -9,11 +9,6 @@
9struct list_head; 9struct list_head;
10struct perf_evsel; 10struct perf_evsel;
11 11
12extern struct list_head evsel_list;
13
14int perf_evsel_list__create_default(void);
15void perf_evsel_list__delete(void);
16
17struct option; 12struct option;
18 13
19struct tracepoint_path { 14struct tracepoint_path {
@@ -25,8 +20,6 @@ struct tracepoint_path {
25extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 20extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern bool have_tracepoints(struct list_head *evlist); 21extern bool have_tracepoints(struct list_head *evlist);
27 22
28extern int nr_counters;
29
30const char *event_name(struct perf_evsel *event); 23const char *event_name(struct perf_evsel *event);
31extern const char *__event_name(int type, u64 config); 24extern const char *__event_name(int type, u64 config);
32 25
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6e29d9c9dccc..859d377a3df3 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -31,6 +31,7 @@
31#include <string.h> 31#include <string.h>
32#include <stdarg.h> 32#include <stdarg.h>
33#include <limits.h> 33#include <limits.h>
34#include <elf.h>
34 35
35#undef _GNU_SOURCE 36#undef _GNU_SOURCE
36#include "util.h" 37#include "util.h"
@@ -111,7 +112,25 @@ static struct symbol *__find_kernel_function_by_name(const char *name,
111 NULL); 112 NULL);
112} 113}
113 114
114const char *kernel_get_module_path(const char *module) 115static struct map *kernel_get_module_map(const char *module)
116{
117 struct rb_node *nd;
118 struct map_groups *grp = &machine.kmaps;
119
120 if (!module)
121 module = "kernel";
122
123 for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
124 struct map *pos = rb_entry(nd, struct map, rb_node);
125 if (strncmp(pos->dso->short_name + 1, module,
126 pos->dso->short_name_len - 2) == 0) {
127 return pos;
128 }
129 }
130 return NULL;
131}
132
133static struct dso *kernel_get_module_dso(const char *module)
115{ 134{
116 struct dso *dso; 135 struct dso *dso;
117 struct map *map; 136 struct map *map;
@@ -141,7 +160,13 @@ const char *kernel_get_module_path(const char *module)
141 } 160 }
142 } 161 }
143found: 162found:
144 return dso->long_name; 163 return dso;
164}
165
166const char *kernel_get_module_path(const char *module)
167{
168 struct dso *dso = kernel_get_module_dso(module);
169 return (dso) ? dso->long_name : NULL;
145} 170}
146 171
147#ifdef DWARF_SUPPORT 172#ifdef DWARF_SUPPORT
@@ -1913,3 +1938,42 @@ int del_perf_probe_events(struct strlist *dellist)
1913 return ret; 1938 return ret;
1914} 1939}
1915 1940
1941/*
1942 * If a symbol corresponds to a function with global binding return 0.
1943 * For all others return 1.
1944 */
1945static int filter_non_global_functions(struct map *map __unused,
1946 struct symbol *sym)
1947{
1948 if (sym->binding != STB_GLOBAL)
1949 return 1;
1950
1951 return 0;
1952}
1953
1954int show_available_funcs(const char *module)
1955{
1956 struct map *map;
1957 int ret;
1958
1959 setup_pager();
1960
1961 ret = init_vmlinux();
1962 if (ret < 0)
1963 return ret;
1964
1965 map = kernel_get_module_map(module);
1966 if (!map) {
1967 pr_err("Failed to find %s map.\n", (module) ? : "kernel");
1968 return -EINVAL;
1969 }
1970 if (map__load(map, filter_non_global_functions)) {
1971 pr_err("Failed to load map.\n");
1972 return -EINVAL;
1973 }
1974 if (!dso__sorted_by_name(map->dso, map->type))
1975 dso__sort_by_name(map->dso, map->type);
1976
1977 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
1978 return 0;
1979}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5accbedfea37..1fb4f18337d3 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -127,6 +127,7 @@ extern int show_line_range(struct line_range *lr, const char *module);
127extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 127extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
128 int max_probe_points, const char *module, 128 int max_probe_points, const char *module,
129 bool externs); 129 bool externs);
130extern int show_available_funcs(const char *module);
130 131
131 132
132/* Maximum index number of event-name postfix */ 133/* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index ab83b6ac5d65..69215bff17e9 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -280,6 +280,19 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
280 return name ? (strcmp(tname, name) == 0) : false; 280 return name ? (strcmp(tname, name) == 0) : false;
281} 281}
282 282
283/* Get callsite line number of inline-function instance */
284static int die_get_call_lineno(Dwarf_Die *in_die)
285{
286 Dwarf_Attribute attr;
287 Dwarf_Word ret;
288
289 if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
290 return -ENOENT;
291
292 dwarf_formudata(&attr, &ret);
293 return (int)ret;
294}
295
283/* Get type die */ 296/* Get type die */
284static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 297static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
285{ 298{
@@ -458,6 +471,151 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
458 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); 471 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
459} 472}
460 473
474/* Walker on lines (Note: line number will not be sorted) */
475typedef int (* line_walk_handler_t) (const char *fname, int lineno,
476 Dwarf_Addr addr, void *data);
477
478struct __line_walk_param {
479 const char *fname;
480 line_walk_handler_t handler;
481 void *data;
482 int retval;
483};
484
485static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
486{
487 struct __line_walk_param *lw = data;
488 Dwarf_Addr addr;
489 int lineno;
490
491 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
492 lineno = die_get_call_lineno(in_die);
493 if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
494 lw->retval = lw->handler(lw->fname, lineno, addr,
495 lw->data);
496 if (lw->retval != 0)
497 return DIE_FIND_CB_FOUND;
498 }
499 }
500 return DIE_FIND_CB_SIBLING;
501}
502
503/* Walk on lines of blocks included in given DIE */
504static int __die_walk_funclines(Dwarf_Die *sp_die,
505 line_walk_handler_t handler, void *data)
506{
507 struct __line_walk_param lw = {
508 .handler = handler,
509 .data = data,
510 .retval = 0,
511 };
512 Dwarf_Die die_mem;
513 Dwarf_Addr addr;
514 int lineno;
515
516 /* Handle function declaration line */
517 lw.fname = dwarf_decl_file(sp_die);
518 if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
519 dwarf_entrypc(sp_die, &addr) == 0) {
520 lw.retval = handler(lw.fname, lineno, addr, data);
521 if (lw.retval != 0)
522 goto done;
523 }
524 die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
525done:
526 return lw.retval;
527}
528
529static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
530{
531 struct __line_walk_param *lw = data;
532
533 lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
534 if (lw->retval != 0)
535 return DWARF_CB_ABORT;
536
537 return DWARF_CB_OK;
538}
539
540/*
541 * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
542 * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
543 */
544static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
545 void *data)
546{
547 Dwarf_Lines *lines;
548 Dwarf_Line *line;
549 Dwarf_Addr addr;
550 const char *fname;
551 int lineno, ret = 0;
552 Dwarf_Die die_mem, *cu_die;
553 size_t nlines, i;
554
555 /* Get the CU die */
556 if (dwarf_tag(pdie) == DW_TAG_subprogram)
557 cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
558 else
559 cu_die = pdie;
560 if (!cu_die) {
561 pr_debug2("Failed to get CU from subprogram\n");
562 return -EINVAL;
563 }
564
565 /* Get lines list in the CU */
566 if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
567 pr_debug2("Failed to get source lines on this CU.\n");
568 return -ENOENT;
569 }
570 pr_debug2("Get %zd lines from this CU\n", nlines);
571
572 /* Walk on the lines on lines list */
573 for (i = 0; i < nlines; i++) {
574 line = dwarf_onesrcline(lines, i);
575 if (line == NULL ||
576 dwarf_lineno(line, &lineno) != 0 ||
577 dwarf_lineaddr(line, &addr) != 0) {
578 pr_debug2("Failed to get line info. "
579 "Possible error in debuginfo.\n");
580 continue;
581 }
582 /* Filter lines based on address */
583 if (pdie != cu_die)
584 /*
585 * Address filtering
586 * The line is included in given function, and
587 * no inline block includes it.
588 */
589 if (!dwarf_haspc(pdie, addr) ||
590 die_find_inlinefunc(pdie, addr, &die_mem))
591 continue;
592 /* Get source line */
593 fname = dwarf_linesrc(line, NULL, NULL);
594
595 ret = handler(fname, lineno, addr, data);
596 if (ret != 0)
597 return ret;
598 }
599
600 /*
601 * Dwarf lines doesn't include function declarations and inlined
602 * subroutines. We have to check functions list or given function.
603 */
604 if (pdie != cu_die)
605 ret = __die_walk_funclines(pdie, handler, data);
606 else {
607 struct __line_walk_param param = {
608 .handler = handler,
609 .data = data,
610 .retval = 0,
611 };
612 dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
613 ret = param.retval;
614 }
615
616 return ret;
617}
618
461struct __find_variable_param { 619struct __find_variable_param {
462 const char *name; 620 const char *name;
463 Dwarf_Addr addr; 621 Dwarf_Addr addr;
@@ -1050,43 +1208,26 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1050 return ret; 1208 return ret;
1051} 1209}
1052 1210
1053/* Find probe point from its line number */ 1211static int probe_point_line_walker(const char *fname, int lineno,
1054static int find_probe_point_by_line(struct probe_finder *pf) 1212 Dwarf_Addr addr, void *data)
1055{ 1213{
1056 Dwarf_Lines *lines; 1214 struct probe_finder *pf = data;
1057 Dwarf_Line *line; 1215 int ret;
1058 size_t nlines, i;
1059 Dwarf_Addr addr;
1060 int lineno;
1061 int ret = 0;
1062
1063 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
1064 pr_warning("No source lines found.\n");
1065 return -ENOENT;
1066 }
1067 1216
1068 for (i = 0; i < nlines && ret == 0; i++) { 1217 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
1069 line = dwarf_onesrcline(lines, i); 1218 return 0;
1070 if (dwarf_lineno(line, &lineno) != 0 ||
1071 lineno != pf->lno)
1072 continue;
1073 1219
1074 /* TODO: Get fileno from line, but how? */ 1220 pf->addr = addr;
1075 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) 1221 ret = call_probe_finder(NULL, pf);
1076 continue;
1077 1222
1078 if (dwarf_lineaddr(line, &addr) != 0) { 1223 /* Continue if no error, because the line will be in inline function */
1079 pr_warning("Failed to get the address of the line.\n"); 1224 return ret < 0 ?: 0;
1080 return -ENOENT; 1225}
1081 }
1082 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
1083 (int)i, lineno, (uintmax_t)addr);
1084 pf->addr = addr;
1085 1226
1086 ret = call_probe_finder(NULL, pf); 1227/* Find probe point from its line number */
1087 /* Continuing, because target line might be inlined. */ 1228static int find_probe_point_by_line(struct probe_finder *pf)
1088 } 1229{
1089 return ret; 1230 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
1090} 1231}
1091 1232
1092/* Find lines which match lazy pattern */ 1233/* Find lines which match lazy pattern */
@@ -1140,15 +1281,31 @@ out_close:
1140 return nlines; 1281 return nlines;
1141} 1282}
1142 1283
1284static int probe_point_lazy_walker(const char *fname, int lineno,
1285 Dwarf_Addr addr, void *data)
1286{
1287 struct probe_finder *pf = data;
1288 int ret;
1289
1290 if (!line_list__has_line(&pf->lcache, lineno) ||
1291 strtailcmp(fname, pf->fname) != 0)
1292 return 0;
1293
1294 pr_debug("Probe line found: line:%d addr:0x%llx\n",
1295 lineno, (unsigned long long)addr);
1296 pf->addr = addr;
1297 ret = call_probe_finder(NULL, pf);
1298
1299 /*
1300 * Continue if no error, because the lazy pattern will match
1301 * to other lines
1302 */
1303 return ret < 0 ?: 0;
1304}
1305
1143/* Find probe points from lazy pattern */ 1306/* Find probe points from lazy pattern */
1144static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 1307static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
1145{ 1308{
1146 Dwarf_Lines *lines;
1147 Dwarf_Line *line;
1148 size_t nlines, i;
1149 Dwarf_Addr addr;
1150 Dwarf_Die die_mem;
1151 int lineno;
1152 int ret = 0; 1309 int ret = 0;
1153 1310
1154 if (list_empty(&pf->lcache)) { 1311 if (list_empty(&pf->lcache)) {
@@ -1162,45 +1319,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
1162 return ret; 1319 return ret;
1163 } 1320 }
1164 1321
1165 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { 1322 return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
1166 pr_warning("No source lines found.\n");
1167 return -ENOENT;
1168 }
1169
1170 for (i = 0; i < nlines && ret >= 0; i++) {
1171 line = dwarf_onesrcline(lines, i);
1172
1173 if (dwarf_lineno(line, &lineno) != 0 ||
1174 !line_list__has_line(&pf->lcache, lineno))
1175 continue;
1176
1177 /* TODO: Get fileno from line, but how? */
1178 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
1179 continue;
1180
1181 if (dwarf_lineaddr(line, &addr) != 0) {
1182 pr_debug("Failed to get the address of line %d.\n",
1183 lineno);
1184 continue;
1185 }
1186 if (sp_die) {
1187 /* Address filtering 1: does sp_die include addr? */
1188 if (!dwarf_haspc(sp_die, addr))
1189 continue;
1190 /* Address filtering 2: No child include addr? */
1191 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1192 continue;
1193 }
1194
1195 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
1196 (int)i, lineno, (unsigned long long)addr);
1197 pf->addr = addr;
1198
1199 ret = call_probe_finder(sp_die, pf);
1200 /* Continuing, because target line might be inlined. */
1201 }
1202 /* TODO: deallocate lines, but how? */
1203 return ret;
1204} 1323}
1205 1324
1206/* Callback parameter with return value */ 1325/* Callback parameter with return value */
@@ -1644,91 +1763,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
1644 return line_list__add_line(&lr->line_list, lineno); 1763 return line_list__add_line(&lr->line_list, lineno);
1645} 1764}
1646 1765
1647/* Search function declaration lines */ 1766static int line_range_walk_cb(const char *fname, int lineno,
1648static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) 1767 Dwarf_Addr addr __used,
1768 void *data)
1649{ 1769{
1650 struct dwarf_callback_param *param = data; 1770 struct line_finder *lf = data;
1651 struct line_finder *lf = param->data;
1652 const char *src;
1653 int lineno;
1654 1771
1655 src = dwarf_decl_file(sp_die); 1772 if ((strtailcmp(fname, lf->fname) != 0) ||
1656 if (src && strtailcmp(src, lf->fname) != 0)
1657 return DWARF_CB_OK;
1658
1659 if (dwarf_decl_line(sp_die, &lineno) != 0 ||
1660 (lf->lno_s > lineno || lf->lno_e < lineno)) 1773 (lf->lno_s > lineno || lf->lno_e < lineno))
1661 return DWARF_CB_OK; 1774 return 0;
1662 1775
1663 param->retval = line_range_add_line(src, lineno, lf->lr); 1776 if (line_range_add_line(fname, lineno, lf->lr) < 0)
1664 if (param->retval < 0) 1777 return -EINVAL;
1665 return DWARF_CB_ABORT;
1666 return DWARF_CB_OK;
1667}
1668 1778
1669static int find_line_range_func_decl_lines(struct line_finder *lf) 1779 return 0;
1670{
1671 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1672 dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
1673 return param.retval;
1674} 1780}
1675 1781
1676/* Find line range from its line number */ 1782/* Find line range from its line number */
1677static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1783static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1678{ 1784{
1679 Dwarf_Lines *lines; 1785 int ret;
1680 Dwarf_Line *line;
1681 size_t nlines, i;
1682 Dwarf_Addr addr;
1683 int lineno, ret = 0;
1684 const char *src;
1685 Dwarf_Die die_mem;
1686
1687 line_list__init(&lf->lr->line_list);
1688 if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
1689 pr_warning("No source lines found.\n");
1690 return -ENOENT;
1691 }
1692
1693 /* Search probable lines on lines list */
1694 for (i = 0; i < nlines; i++) {
1695 line = dwarf_onesrcline(lines, i);
1696 if (dwarf_lineno(line, &lineno) != 0 ||
1697 (lf->lno_s > lineno || lf->lno_e < lineno))
1698 continue;
1699
1700 if (sp_die) {
1701 /* Address filtering 1: does sp_die include addr? */
1702 if (dwarf_lineaddr(line, &addr) != 0 ||
1703 !dwarf_haspc(sp_die, addr))
1704 continue;
1705
1706 /* Address filtering 2: No child include addr? */
1707 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1708 continue;
1709 }
1710
1711 /* TODO: Get fileno from line, but how? */
1712 src = dwarf_linesrc(line, NULL, NULL);
1713 if (strtailcmp(src, lf->fname) != 0)
1714 continue;
1715
1716 ret = line_range_add_line(src, lineno, lf->lr);
1717 if (ret < 0)
1718 return ret;
1719 }
1720 1786
1721 /* 1787 ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
1722 * Dwarf lines doesn't include function declarations. We have to
1723 * check functions list or given function.
1724 */
1725 if (sp_die) {
1726 src = dwarf_decl_file(sp_die);
1727 if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
1728 (lf->lno_s <= lineno && lf->lno_e >= lineno))
1729 ret = line_range_add_line(src, lineno, lf->lr);
1730 } else
1731 ret = find_line_range_func_decl_lines(lf);
1732 1788
1733 /* Update status */ 1789 /* Update status */
1734 if (ret >= 0) 1790 if (ret >= 0)
@@ -1758,9 +1814,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1758 struct line_finder *lf = param->data; 1814 struct line_finder *lf = param->data;
1759 struct line_range *lr = lf->lr; 1815 struct line_range *lr = lf->lr;
1760 1816
1761 pr_debug("find (%llx) %s\n",
1762 (unsigned long long)dwarf_dieoffset(sp_die),
1763 dwarf_diename(sp_die));
1764 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1817 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1765 die_compare_name(sp_die, lr->function)) { 1818 die_compare_name(sp_die, lr->function)) {
1766 lf->fname = dwarf_decl_file(sp_die); 1819 lf->fname = dwarf_decl_file(sp_die);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 105f00bfd555..e6a07408669e 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -242,17 +242,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
242 return 0; 242 return 0;
243} 243}
244 244
245struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 245int perf_session__resolve_callchain(struct perf_session *self,
246 struct thread *thread, 246 struct thread *thread,
247 struct ip_callchain *chain, 247 struct ip_callchain *chain,
248 struct symbol **parent) 248 struct symbol **parent)
249{ 249{
250 u8 cpumode = PERF_RECORD_MISC_USER; 250 u8 cpumode = PERF_RECORD_MISC_USER;
251 unsigned int i; 251 unsigned int i;
252 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); 252 int err;
253 253
254 if (!syms) 254 callchain_cursor_reset(&self->callchain_cursor);
255 return NULL;
256 255
257 for (i = 0; i < chain->nr; i++) { 256 for (i = 0; i < chain->nr; i++) {
258 u64 ip = chain->ips[i]; 257 u64 ip = chain->ips[i];
@@ -281,12 +280,15 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
281 *parent = al.sym; 280 *parent = al.sym;
282 if (!symbol_conf.use_callchain) 281 if (!symbol_conf.use_callchain)
283 break; 282 break;
284 syms[i].map = al.map;
285 syms[i].sym = al.sym;
286 } 283 }
284
285 err = callchain_cursor_append(&self->callchain_cursor,
286 ip, al.map, al.sym);
287 if (err)
288 return err;
287 } 289 }
288 290
289 return syms; 291 return 0;
290} 292}
291 293
292static int process_event_synth_stub(event_t *event __used, 294static int process_event_synth_stub(event_t *event __used,
@@ -494,7 +496,7 @@ static void flush_sample_queue(struct perf_session *s,
494 if (iter->timestamp > limit) 496 if (iter->timestamp > limit)
495 break; 497 break;
496 498
497 event__parse_sample(iter->event, s, &sample); 499 perf_session__parse_sample(s, iter->event, &sample);
498 perf_session_deliver_event(s, iter->event, &sample, ops, 500 perf_session_deliver_event(s, iter->event, &sample, ops,
499 iter->file_offset); 501 iter->file_offset);
500 502
@@ -804,7 +806,7 @@ static int perf_session__process_event(struct perf_session *session,
804 /* 806 /*
805 * For all kernel events we get the sample data 807 * For all kernel events we get the sample data
806 */ 808 */
807 event__parse_sample(event, session, &sample); 809 perf_session__parse_sample(session, event, &sample);
808 810
809 /* Preprocess sample records - precheck callchains */ 811 /* Preprocess sample records - precheck callchains */
810 if (perf_session__preprocess_sample(session, event, &sample)) 812 if (perf_session__preprocess_sample(session, event, &sample))
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index decd83f274fd..78239767011e 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -51,7 +51,8 @@ struct perf_session {
51 int cwdlen; 51 int cwdlen;
52 char *cwd; 52 char *cwd;
53 struct ordered_samples ordered_samples; 53 struct ordered_samples ordered_samples;
54 char filename[0]; 54 struct callchain_cursor callchain_cursor;
55 char filename[0];
55}; 56};
56 57
57struct perf_event_ops; 58struct perf_event_ops;
@@ -94,10 +95,10 @@ int __perf_session__process_events(struct perf_session *self,
94int perf_session__process_events(struct perf_session *self, 95int perf_session__process_events(struct perf_session *self,
95 struct perf_event_ops *event_ops); 96 struct perf_event_ops *event_ops);
96 97
97struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 98int perf_session__resolve_callchain(struct perf_session *self,
98 struct thread *thread, 99 struct thread *thread,
99 struct ip_callchain *chain, 100 struct ip_callchain *chain,
100 struct symbol **parent); 101 struct symbol **parent);
101 102
102bool perf_session__has_traces(struct perf_session *self, const char *msg); 103bool perf_session__has_traces(struct perf_session *self, const char *msg);
103 104
@@ -154,4 +155,13 @@ size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp)
154{ 155{
155 return hists__fprintf_nr_events(&self->hists, fp); 156 return hists__fprintf_nr_events(&self->hists, fp);
156} 157}
158
159static inline int perf_session__parse_sample(struct perf_session *session,
160 const event_t *event,
161 struct sample_data *sample)
162{
163 return event__parse_sample(event, session->sample_type,
164 session->sample_id_all, sample);
165}
166
157#endif /* __PERF_SESSION_H */ 167#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 00f4eade2e3e..d5d3b22250f3 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,61 +7,6 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10/* Skip "." and ".." directories */
11static int filter(const struct dirent *dir)
12{
13 if (dir->d_name[0] == '.')
14 return 0;
15 else
16 return 1;
17}
18
19struct thread_map *thread_map__new_by_pid(pid_t pid)
20{
21 struct thread_map *threads;
22 char name[256];
23 int items;
24 struct dirent **namelist = NULL;
25 int i;
26
27 sprintf(name, "/proc/%d/task", pid);
28 items = scandir(name, &namelist, filter, NULL);
29 if (items <= 0)
30 return NULL;
31
32 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
33 if (threads != NULL) {
34 for (i = 0; i < items; i++)
35 threads->map[i] = atoi(namelist[i]->d_name);
36 threads->nr = items;
37 }
38
39 for (i=0; i<items; i++)
40 free(namelist[i]);
41 free(namelist);
42
43 return threads;
44}
45
46struct thread_map *thread_map__new_by_tid(pid_t tid)
47{
48 struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
49
50 if (threads != NULL) {
51 threads->map[0] = tid;
52 threads->nr = 1;
53 }
54
55 return threads;
56}
57
58struct thread_map *thread_map__new(pid_t pid, pid_t tid)
59{
60 if (pid != -1)
61 return thread_map__new_by_pid(pid);
62 return thread_map__new_by_tid(tid);
63}
64
65static struct thread *thread__new(pid_t pid) 10static struct thread *thread__new(pid_t pid)
66{ 11{
67 struct thread *self = zalloc(sizeof(*self)); 12 struct thread *self = zalloc(sizeof(*self));
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index d7574101054a..e5f2401c1b5e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -18,24 +18,10 @@ struct thread {
18 int comm_len; 18 int comm_len;
19}; 19};
20 20
21struct thread_map {
22 int nr;
23 int map[];
24};
25
26struct perf_session; 21struct perf_session;
27 22
28void thread__delete(struct thread *self); 23void thread__delete(struct thread *self);
29 24
30struct thread_map *thread_map__new_by_pid(pid_t pid);
31struct thread_map *thread_map__new_by_tid(pid_t tid);
32struct thread_map *thread_map__new(pid_t pid, pid_t tid);
33
34static inline void thread_map__delete(struct thread_map *threads)
35{
36 free(threads);
37}
38
39int thread__set_comm(struct thread *self, const char *comm); 25int thread__set_comm(struct thread *self, const char *comm);
40int thread__comm_len(struct thread *self); 26int thread__comm_len(struct thread *self);
41struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 27struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
new file mode 100644
index 000000000000..a5df131b77c3
--- /dev/null
+++ b/tools/perf/util/thread_map.c
@@ -0,0 +1,64 @@
1#include <dirent.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include "thread_map.h"
5
6/* Skip "." and ".." directories */
7static int filter(const struct dirent *dir)
8{
9 if (dir->d_name[0] == '.')
10 return 0;
11 else
12 return 1;
13}
14
15struct thread_map *thread_map__new_by_pid(pid_t pid)
16{
17 struct thread_map *threads;
18 char name[256];
19 int items;
20 struct dirent **namelist = NULL;
21 int i;
22
23 sprintf(name, "/proc/%d/task", pid);
24 items = scandir(name, &namelist, filter, NULL);
25 if (items <= 0)
26 return NULL;
27
28 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
29 if (threads != NULL) {
30 for (i = 0; i < items; i++)
31 threads->map[i] = atoi(namelist[i]->d_name);
32 threads->nr = items;
33 }
34
35 for (i=0; i<items; i++)
36 free(namelist[i]);
37 free(namelist);
38
39 return threads;
40}
41
42struct thread_map *thread_map__new_by_tid(pid_t tid)
43{
44 struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
45
46 if (threads != NULL) {
47 threads->map[0] = tid;
48 threads->nr = 1;
49 }
50
51 return threads;
52}
53
54struct thread_map *thread_map__new(pid_t pid, pid_t tid)
55{
56 if (pid != -1)
57 return thread_map__new_by_pid(pid);
58 return thread_map__new_by_tid(tid);
59}
60
61void thread_map__delete(struct thread_map *threads)
62{
63 free(threads);
64}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
new file mode 100644
index 000000000000..3cb907311409
--- /dev/null
+++ b/tools/perf/util/thread_map.h
@@ -0,0 +1,15 @@
1#ifndef __PERF_THREAD_MAP_H
2#define __PERF_THREAD_MAP_H
3
4#include <sys/types.h>
5
6struct thread_map {
7 int nr;
8 int map[];
9};
10
11struct thread_map *thread_map__new_by_pid(pid_t pid);
12struct thread_map *thread_map__new_by_tid(pid_t tid);
13struct thread_map *thread_map__new(pid_t pid, pid_t tid);
14void thread_map__delete(struct thread_map *threads);
15#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 60c463c16028..86428239fa65 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -377,7 +377,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
377 while (node) { 377 while (node) {
378 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 378 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
379 struct rb_node *next = rb_next(node); 379 struct rb_node *next = rb_next(node);
380 u64 cumul = cumul_hits(child); 380 u64 cumul = callchain_cumul_hits(child);
381 struct callchain_list *chain; 381 struct callchain_list *chain;
382 char folded_sign = ' '; 382 char folded_sign = ' ';
383 int first = true; 383 int first = true;