diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 3 | ||||
-rw-r--r-- | tools/perf/Makefile | 2 | ||||
-rw-r--r-- | tools/perf/arch/s390/Makefile | 4 | ||||
-rw-r--r-- | tools/perf/arch/s390/util/dwarf-regs.c | 22 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 9 | ||||
-rw-r--r-- | tools/perf/builtin-sched.c | 23 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 6 | ||||
-rw-r--r-- | tools/perf/builtin-test.c | 116 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 3 | ||||
-rw-r--r-- | tools/perf/perf.c | 2 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 87 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 2 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 74 | ||||
-rw-r--r-- | tools/perf/util/session.c | 2 |
14 files changed, 266 insertions, 89 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 52462ae26455..e032716c839b 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -61,6 +61,9 @@ OPTIONS | |||
61 | -r:: | 61 | -r:: |
62 | --realtime=:: | 62 | --realtime=:: |
63 | Collect data with this RT SCHED_FIFO priority. | 63 | Collect data with this RT SCHED_FIFO priority. |
64 | -D:: | ||
65 | --no-delay:: | ||
66 | Collect data without buffering. | ||
64 | -A:: | 67 | -A:: |
65 | --append:: | 68 | --append:: |
66 | Append to the output file to do incremental profiling. | 69 | Append to the output file to do incremental profiling. |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 1b9b13ee2a72..2b5387d53ba5 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -227,7 +227,7 @@ ifndef PERF_DEBUG | |||
227 | CFLAGS_OPTIMIZE = -O6 | 227 | CFLAGS_OPTIMIZE = -O6 |
228 | endif | 228 | endif |
229 | 229 | ||
230 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) | 230 | CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) |
231 | EXTLIBS = -lpthread -lrt -lelf -lm | 231 | EXTLIBS = -lpthread -lrt -lelf -lm |
232 | ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 | 232 | ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 |
233 | ALL_LDFLAGS = $(LDFLAGS) | 233 | ALL_LDFLAGS = $(LDFLAGS) |
diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile new file mode 100644 index 000000000000..15130b50dfe3 --- /dev/null +++ b/tools/perf/arch/s390/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | ifndef NO_DWARF | ||
2 | PERF_HAVE_DWARF_REGS := 1 | ||
3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o | ||
4 | endif | ||
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c new file mode 100644 index 000000000000..e19653e025fa --- /dev/null +++ b/tools/perf/arch/s390/util/dwarf-regs.c | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Mapping of DWARF debug register numbers into register names. | ||
3 | * | ||
4 | * Copyright IBM Corp. 2010 | ||
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <libio.h> | ||
10 | #include <dwarf-regs.h> | ||
11 | |||
12 | #define NUM_GPRS 16 | ||
13 | |||
14 | static const char *gpr_names[NUM_GPRS] = { | ||
15 | "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", | ||
16 | "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", | ||
17 | }; | ||
18 | |||
19 | const char *get_arch_regstr(unsigned int n) | ||
20 | { | ||
21 | return (n >= NUM_GPRS) ? NULL : gpr_names[n]; | ||
22 | } | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 7bc049035484..df6064ad9bf2 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -49,6 +49,7 @@ static int pipe_output = 0; | |||
49 | static const char *output_name = "perf.data"; | 49 | static const char *output_name = "perf.data"; |
50 | static int group = 0; | 50 | static int group = 0; |
51 | static int realtime_prio = 0; | 51 | static int realtime_prio = 0; |
52 | static bool nodelay = false; | ||
52 | static bool raw_samples = false; | 53 | static bool raw_samples = false; |
53 | static bool sample_id_all_avail = true; | 54 | static bool sample_id_all_avail = true; |
54 | static bool system_wide = false; | 55 | static bool system_wide = false; |
@@ -307,6 +308,11 @@ static void create_counter(struct perf_evsel *evsel, int cpu) | |||
307 | attr->sample_type |= PERF_SAMPLE_CPU; | 308 | attr->sample_type |= PERF_SAMPLE_CPU; |
308 | } | 309 | } |
309 | 310 | ||
311 | if (nodelay) { | ||
312 | attr->watermark = 0; | ||
313 | attr->wakeup_events = 1; | ||
314 | } | ||
315 | |||
310 | attr->mmap = track; | 316 | attr->mmap = track; |
311 | attr->comm = track; | 317 | attr->comm = track; |
312 | attr->inherit = !no_inherit; | 318 | attr->inherit = !no_inherit; |
@@ -477,6 +483,7 @@ static void atexit_header(void) | |||
477 | process_buildids(); | 483 | process_buildids(); |
478 | perf_header__write(&session->header, output, true); | 484 | perf_header__write(&session->header, output, true); |
479 | perf_session__delete(session); | 485 | perf_session__delete(session); |
486 | perf_evsel_list__delete(); | ||
480 | symbol__exit(); | 487 | symbol__exit(); |
481 | } | 488 | } |
482 | } | 489 | } |
@@ -842,6 +849,8 @@ const struct option record_options[] = { | |||
842 | "record events on existing thread id"), | 849 | "record events on existing thread id"), |
843 | OPT_INTEGER('r', "realtime", &realtime_prio, | 850 | OPT_INTEGER('r', "realtime", &realtime_prio, |
844 | "collect data with this RT SCHED_FIFO priority"), | 851 | "collect data with this RT SCHED_FIFO priority"), |
852 | OPT_BOOLEAN('D', "no-delay", &nodelay, | ||
853 | "collect data without buffering"), | ||
845 | OPT_BOOLEAN('R', "raw-samples", &raw_samples, | 854 | OPT_BOOLEAN('R', "raw-samples", &raw_samples, |
846 | "collect raw sample records from all opened counters"), | 855 | "collect raw sample records from all opened counters"), |
847 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 856 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 7a4ebeb8b016..29e7ffd85690 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -489,7 +489,8 @@ static void create_tasks(void) | |||
489 | 489 | ||
490 | err = pthread_attr_init(&attr); | 490 | err = pthread_attr_init(&attr); |
491 | BUG_ON(err); | 491 | BUG_ON(err); |
492 | err = pthread_attr_setstacksize(&attr, (size_t)(16*1024)); | 492 | err = pthread_attr_setstacksize(&attr, |
493 | (size_t) max(16 * 1024, PTHREAD_STACK_MIN)); | ||
493 | BUG_ON(err); | 494 | BUG_ON(err); |
494 | err = pthread_mutex_lock(&start_work_mutex); | 495 | err = pthread_mutex_lock(&start_work_mutex); |
495 | BUG_ON(err); | 496 | BUG_ON(err); |
@@ -1842,15 +1843,15 @@ static const char *record_args[] = { | |||
1842 | "-f", | 1843 | "-f", |
1843 | "-m", "1024", | 1844 | "-m", "1024", |
1844 | "-c", "1", | 1845 | "-c", "1", |
1845 | "-e", "sched:sched_switch:r", | 1846 | "-e", "sched:sched_switch", |
1846 | "-e", "sched:sched_stat_wait:r", | 1847 | "-e", "sched:sched_stat_wait", |
1847 | "-e", "sched:sched_stat_sleep:r", | 1848 | "-e", "sched:sched_stat_sleep", |
1848 | "-e", "sched:sched_stat_iowait:r", | 1849 | "-e", "sched:sched_stat_iowait", |
1849 | "-e", "sched:sched_stat_runtime:r", | 1850 | "-e", "sched:sched_stat_runtime", |
1850 | "-e", "sched:sched_process_exit:r", | 1851 | "-e", "sched:sched_process_exit", |
1851 | "-e", "sched:sched_process_fork:r", | 1852 | "-e", "sched:sched_process_fork", |
1852 | "-e", "sched:sched_wakeup:r", | 1853 | "-e", "sched:sched_wakeup", |
1853 | "-e", "sched:sched_migrate_task:r", | 1854 | "-e", "sched:sched_migrate_task", |
1854 | }; | 1855 | }; |
1855 | 1856 | ||
1856 | static int __cmd_record(int argc, const char **argv) | 1857 | static int __cmd_record(int argc, const char **argv) |
@@ -1861,7 +1862,7 @@ static int __cmd_record(int argc, const char **argv) | |||
1861 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 1862 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; |
1862 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1863 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
1863 | 1864 | ||
1864 | if (rec_argv) | 1865 | if (rec_argv == NULL) |
1865 | return -ENOMEM; | 1866 | return -ENOMEM; |
1866 | 1867 | ||
1867 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 1868 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 02b2d8013a61..0ff11d9b13be 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -316,6 +316,8 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
316 | "\t Consider tweaking" | 316 | "\t Consider tweaking" |
317 | " /proc/sys/kernel/perf_event_paranoid or running as root.", | 317 | " /proc/sys/kernel/perf_event_paranoid or running as root.", |
318 | system_wide ? "system-wide " : ""); | 318 | system_wide ? "system-wide " : ""); |
319 | } else if (errno == ENOENT) { | ||
320 | error("%s event is not supported. ", event_name(counter)); | ||
319 | } else { | 321 | } else { |
320 | error("open_counter returned with %d (%s). " | 322 | error("open_counter returned with %d (%s). " |
321 | "/bin/dmesg may provide additional information.\n", | 323 | "/bin/dmesg may provide additional information.\n", |
@@ -683,8 +685,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
683 | nr_counters = ARRAY_SIZE(default_attrs); | 685 | nr_counters = ARRAY_SIZE(default_attrs); |
684 | 686 | ||
685 | for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { | 687 | for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { |
686 | pos = perf_evsel__new(default_attrs[c].type, | 688 | pos = perf_evsel__new(&default_attrs[c], |
687 | default_attrs[c].config, | ||
688 | nr_counters); | 689 | nr_counters); |
689 | if (pos == NULL) | 690 | if (pos == NULL) |
690 | goto out; | 691 | goto out; |
@@ -742,6 +743,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
742 | out_free_fd: | 743 | out_free_fd: |
743 | list_for_each_entry(pos, &evsel_list, node) | 744 | list_for_each_entry(pos, &evsel_list, node) |
744 | perf_evsel__free_stat_priv(pos); | 745 | perf_evsel__free_stat_priv(pos); |
746 | perf_evsel_list__delete(); | ||
745 | out: | 747 | out: |
746 | thread_map__delete(threads); | 748 | thread_map__delete(threads); |
747 | threads = NULL; | 749 | threads = NULL; |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 1c984342a579..ed5696198d3d 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -234,6 +234,7 @@ out: | |||
234 | return err; | 234 | return err; |
235 | } | 235 | } |
236 | 236 | ||
237 | #include "util/cpumap.h" | ||
237 | #include "util/evsel.h" | 238 | #include "util/evsel.h" |
238 | #include <sys/types.h> | 239 | #include <sys/types.h> |
239 | 240 | ||
@@ -264,6 +265,7 @@ static int test__open_syscall_event(void) | |||
264 | int err = -1, fd; | 265 | int err = -1, fd; |
265 | struct thread_map *threads; | 266 | struct thread_map *threads; |
266 | struct perf_evsel *evsel; | 267 | struct perf_evsel *evsel; |
268 | struct perf_event_attr attr; | ||
267 | unsigned int nr_open_calls = 111, i; | 269 | unsigned int nr_open_calls = 111, i; |
268 | int id = trace_event__id("sys_enter_open"); | 270 | int id = trace_event__id("sys_enter_open"); |
269 | 271 | ||
@@ -278,7 +280,10 @@ static int test__open_syscall_event(void) | |||
278 | return -1; | 280 | return -1; |
279 | } | 281 | } |
280 | 282 | ||
281 | evsel = perf_evsel__new(PERF_TYPE_TRACEPOINT, id, 0); | 283 | memset(&attr, 0, sizeof(attr)); |
284 | attr.type = PERF_TYPE_TRACEPOINT; | ||
285 | attr.config = id; | ||
286 | evsel = perf_evsel__new(&attr, 0); | ||
282 | if (evsel == NULL) { | 287 | if (evsel == NULL) { |
283 | pr_debug("perf_evsel__new\n"); | 288 | pr_debug("perf_evsel__new\n"); |
284 | goto out_thread_map_delete; | 289 | goto out_thread_map_delete; |
@@ -317,6 +322,111 @@ out_thread_map_delete: | |||
317 | return err; | 322 | return err; |
318 | } | 323 | } |
319 | 324 | ||
325 | #include <sched.h> | ||
326 | |||
327 | static int test__open_syscall_event_on_all_cpus(void) | ||
328 | { | ||
329 | int err = -1, fd, cpu; | ||
330 | struct thread_map *threads; | ||
331 | struct cpu_map *cpus; | ||
332 | struct perf_evsel *evsel; | ||
333 | struct perf_event_attr attr; | ||
334 | unsigned int nr_open_calls = 111, i; | ||
335 | cpu_set_t *cpu_set; | ||
336 | size_t cpu_set_size; | ||
337 | int id = trace_event__id("sys_enter_open"); | ||
338 | |||
339 | if (id < 0) { | ||
340 | pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); | ||
341 | return -1; | ||
342 | } | ||
343 | |||
344 | threads = thread_map__new(-1, getpid()); | ||
345 | if (threads == NULL) { | ||
346 | pr_debug("thread_map__new\n"); | ||
347 | return -1; | ||
348 | } | ||
349 | |||
350 | cpus = cpu_map__new(NULL); | ||
351 | if (threads == NULL) { | ||
352 | pr_debug("thread_map__new\n"); | ||
353 | return -1; | ||
354 | } | ||
355 | |||
356 | cpu_set = CPU_ALLOC(cpus->nr); | ||
357 | |||
358 | if (cpu_set == NULL) | ||
359 | goto out_thread_map_delete; | ||
360 | |||
361 | cpu_set_size = CPU_ALLOC_SIZE(cpus->nr); | ||
362 | CPU_ZERO_S(cpu_set_size, cpu_set); | ||
363 | |||
364 | memset(&attr, 0, sizeof(attr)); | ||
365 | attr.type = PERF_TYPE_TRACEPOINT; | ||
366 | attr.config = id; | ||
367 | evsel = perf_evsel__new(&attr, 0); | ||
368 | if (evsel == NULL) { | ||
369 | pr_debug("perf_evsel__new\n"); | ||
370 | goto out_cpu_free; | ||
371 | } | ||
372 | |||
373 | if (perf_evsel__open(evsel, cpus, threads) < 0) { | ||
374 | pr_debug("failed to open counter: %s, " | ||
375 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | ||
376 | strerror(errno)); | ||
377 | goto out_evsel_delete; | ||
378 | } | ||
379 | |||
380 | for (cpu = 0; cpu < cpus->nr; ++cpu) { | ||
381 | unsigned int ncalls = nr_open_calls + cpu; | ||
382 | |||
383 | CPU_SET(cpu, cpu_set); | ||
384 | sched_setaffinity(0, cpu_set_size, cpu_set); | ||
385 | for (i = 0; i < ncalls; ++i) { | ||
386 | fd = open("/etc/passwd", O_RDONLY); | ||
387 | close(fd); | ||
388 | } | ||
389 | CPU_CLR(cpu, cpu_set); | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Here we need to explicitely preallocate the counts, as if | ||
394 | * we use the auto allocation it will allocate just for 1 cpu, | ||
395 | * as we start by cpu 0. | ||
396 | */ | ||
397 | if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) { | ||
398 | pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr); | ||
399 | goto out_close_fd; | ||
400 | } | ||
401 | |||
402 | for (cpu = 0; cpu < cpus->nr; ++cpu) { | ||
403 | unsigned int expected; | ||
404 | |||
405 | if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { | ||
406 | pr_debug("perf_evsel__open_read_on_cpu\n"); | ||
407 | goto out_close_fd; | ||
408 | } | ||
409 | |||
410 | expected = nr_open_calls + cpu; | ||
411 | if (evsel->counts->cpu[cpu].val != expected) { | ||
412 | pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %Ld\n", | ||
413 | expected, cpu, evsel->counts->cpu[cpu].val); | ||
414 | goto out_close_fd; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | err = 0; | ||
419 | out_close_fd: | ||
420 | perf_evsel__close_fd(evsel, 1, threads->nr); | ||
421 | out_evsel_delete: | ||
422 | perf_evsel__delete(evsel); | ||
423 | out_cpu_free: | ||
424 | CPU_FREE(cpu_set); | ||
425 | out_thread_map_delete: | ||
426 | thread_map__delete(threads); | ||
427 | return err; | ||
428 | } | ||
429 | |||
320 | static struct test { | 430 | static struct test { |
321 | const char *desc; | 431 | const char *desc; |
322 | int (*func)(void); | 432 | int (*func)(void); |
@@ -330,6 +440,10 @@ static struct test { | |||
330 | .func = test__open_syscall_event, | 440 | .func = test__open_syscall_event, |
331 | }, | 441 | }, |
332 | { | 442 | { |
443 | .desc = "detect open syscall event on all cpus", | ||
444 | .func = test__open_syscall_event_on_all_cpus, | ||
445 | }, | ||
446 | { | ||
333 | .func = NULL, | 447 | .func = NULL, |
334 | }, | 448 | }, |
335 | }; | 449 | }; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1e67ab9c7ebc..05344c6210ac 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -1471,6 +1471,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1471 | pos->attr.sample_period = default_interval; | 1471 | pos->attr.sample_period = default_interval; |
1472 | } | 1472 | } |
1473 | 1473 | ||
1474 | sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); | ||
1475 | |||
1474 | symbol_conf.priv_size = (sizeof(struct sym_entry) + | 1476 | symbol_conf.priv_size = (sizeof(struct sym_entry) + |
1475 | (nr_counters + 1) * sizeof(unsigned long)); | 1477 | (nr_counters + 1) * sizeof(unsigned long)); |
1476 | 1478 | ||
@@ -1488,6 +1490,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1488 | out_free_fd: | 1490 | out_free_fd: |
1489 | list_for_each_entry(pos, &evsel_list, node) | 1491 | list_for_each_entry(pos, &evsel_list, node) |
1490 | perf_evsel__free_mmap(pos); | 1492 | perf_evsel__free_mmap(pos); |
1493 | perf_evsel_list__delete(); | ||
1491 | 1494 | ||
1492 | return status; | 1495 | return status; |
1493 | } | 1496 | } |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 5b1ecd66bb36..595d0f4a7103 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -286,8 +286,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) | |||
286 | status = p->fn(argc, argv, prefix); | 286 | status = p->fn(argc, argv, prefix); |
287 | exit_browser(status); | 287 | exit_browser(status); |
288 | 288 | ||
289 | perf_evsel_list__delete(); | ||
290 | |||
291 | if (status) | 289 | if (status) |
292 | return status & 0xff; | 290 | return status & 0xff; |
293 | 291 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index c95267e63c5b..f5cfed60af98 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -6,14 +6,13 @@ | |||
6 | 6 | ||
7 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 7 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
8 | 8 | ||
9 | struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx) | 9 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) |
10 | { | 10 | { |
11 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); | 11 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); |
12 | 12 | ||
13 | if (evsel != NULL) { | 13 | if (evsel != NULL) { |
14 | evsel->idx = idx; | 14 | evsel->idx = idx; |
15 | evsel->attr.type = type; | 15 | evsel->attr = *attr; |
16 | evsel->attr.config = config; | ||
17 | INIT_LIST_HEAD(&evsel->node); | 16 | INIT_LIST_HEAD(&evsel->node); |
18 | } | 17 | } |
19 | 18 | ||
@@ -128,59 +127,75 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
128 | return 0; | 127 | return 0; |
129 | } | 128 | } |
130 | 129 | ||
131 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) | 130 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
131 | struct thread_map *threads) | ||
132 | { | 132 | { |
133 | int cpu; | 133 | int cpu, thread; |
134 | 134 | ||
135 | if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, cpus->nr, 1) < 0) | 135 | if (evsel->fd == NULL && |
136 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) | ||
136 | return -1; | 137 | return -1; |
137 | 138 | ||
138 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 139 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
139 | FD(evsel, cpu, 0) = sys_perf_event_open(&evsel->attr, -1, | 140 | for (thread = 0; thread < threads->nr; thread++) { |
140 | cpus->map[cpu], -1, 0); | 141 | FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, |
141 | if (FD(evsel, cpu, 0) < 0) | 142 | threads->map[thread], |
142 | goto out_close; | 143 | cpus->map[cpu], -1, 0); |
144 | if (FD(evsel, cpu, thread) < 0) | ||
145 | goto out_close; | ||
146 | } | ||
143 | } | 147 | } |
144 | 148 | ||
145 | return 0; | 149 | return 0; |
146 | 150 | ||
147 | out_close: | 151 | out_close: |
148 | while (--cpu >= 0) { | 152 | do { |
149 | close(FD(evsel, cpu, 0)); | 153 | while (--thread >= 0) { |
150 | FD(evsel, cpu, 0) = -1; | 154 | close(FD(evsel, cpu, thread)); |
151 | } | 155 | FD(evsel, cpu, thread) = -1; |
156 | } | ||
157 | thread = threads->nr; | ||
158 | } while (--cpu >= 0); | ||
152 | return -1; | 159 | return -1; |
153 | } | 160 | } |
154 | 161 | ||
155 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) | 162 | static struct { |
163 | struct cpu_map map; | ||
164 | int cpus[1]; | ||
165 | } empty_cpu_map = { | ||
166 | .map.nr = 1, | ||
167 | .cpus = { -1, }, | ||
168 | }; | ||
169 | |||
170 | static struct { | ||
171 | struct thread_map map; | ||
172 | int threads[1]; | ||
173 | } empty_thread_map = { | ||
174 | .map.nr = 1, | ||
175 | .threads = { -1, }, | ||
176 | }; | ||
177 | |||
178 | int perf_evsel__open(struct perf_evsel *evsel, | ||
179 | struct cpu_map *cpus, struct thread_map *threads) | ||
156 | { | 180 | { |
157 | int thread; | ||
158 | |||
159 | if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, 1, threads->nr)) | ||
160 | return -1; | ||
161 | 181 | ||
162 | for (thread = 0; thread < threads->nr; thread++) { | 182 | if (cpus == NULL) { |
163 | FD(evsel, 0, thread) = sys_perf_event_open(&evsel->attr, | 183 | /* Work around old compiler warnings about strict aliasing */ |
164 | threads->map[thread], -1, -1, 0); | 184 | cpus = &empty_cpu_map.map; |
165 | if (FD(evsel, 0, thread) < 0) | ||
166 | goto out_close; | ||
167 | } | 185 | } |
168 | 186 | ||
169 | return 0; | 187 | if (threads == NULL) |
188 | threads = &empty_thread_map.map; | ||
170 | 189 | ||
171 | out_close: | 190 | return __perf_evsel__open(evsel, cpus, threads); |
172 | while (--thread >= 0) { | ||
173 | close(FD(evsel, 0, thread)); | ||
174 | FD(evsel, 0, thread) = -1; | ||
175 | } | ||
176 | return -1; | ||
177 | } | 191 | } |
178 | 192 | ||
179 | int perf_evsel__open(struct perf_evsel *evsel, | 193 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) |
180 | struct cpu_map *cpus, struct thread_map *threads) | ||
181 | { | 194 | { |
182 | if (threads == NULL) | 195 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); |
183 | return perf_evsel__open_per_cpu(evsel, cpus); | 196 | } |
184 | 197 | ||
185 | return perf_evsel__open_per_thread(evsel, threads); | 198 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) |
199 | { | ||
200 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); | ||
186 | } | 201 | } |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index a0ccd69c3fc2..b2d755fe88a5 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -37,7 +37,7 @@ struct perf_evsel { | |||
37 | struct cpu_map; | 37 | struct cpu_map; |
38 | struct thread_map; | 38 | struct thread_map; |
39 | 39 | ||
40 | struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx); | 40 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); |
41 | void perf_evsel__delete(struct perf_evsel *evsel); | 41 | void perf_evsel__delete(struct perf_evsel *evsel); |
42 | 42 | ||
43 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 43 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 649083f27e08..5cb6f4bde905 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -490,6 +490,31 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, | |||
490 | return EVT_HANDLED_ALL; | 490 | return EVT_HANDLED_ALL; |
491 | } | 491 | } |
492 | 492 | ||
493 | static int store_event_type(const char *orgname) | ||
494 | { | ||
495 | char filename[PATH_MAX], *c; | ||
496 | FILE *file; | ||
497 | int id, n; | ||
498 | |||
499 | sprintf(filename, "%s/", debugfs_path); | ||
500 | strncat(filename, orgname, strlen(orgname)); | ||
501 | strcat(filename, "/id"); | ||
502 | |||
503 | c = strchr(filename, ':'); | ||
504 | if (c) | ||
505 | *c = '/'; | ||
506 | |||
507 | file = fopen(filename, "r"); | ||
508 | if (!file) | ||
509 | return 0; | ||
510 | n = fscanf(file, "%i", &id); | ||
511 | fclose(file); | ||
512 | if (n < 1) { | ||
513 | pr_err("cannot store event ID\n"); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | return perf_header__push_event(id, orgname); | ||
517 | } | ||
493 | 518 | ||
494 | static enum event_result parse_tracepoint_event(const char **strp, | 519 | static enum event_result parse_tracepoint_event(const char **strp, |
495 | struct perf_event_attr *attr) | 520 | struct perf_event_attr *attr) |
@@ -533,9 +558,13 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
533 | *strp += strlen(sys_name) + evt_length; | 558 | *strp += strlen(sys_name) + evt_length; |
534 | return parse_multiple_tracepoint_event(sys_name, evt_name, | 559 | return parse_multiple_tracepoint_event(sys_name, evt_name, |
535 | flags); | 560 | flags); |
536 | } else | 561 | } else { |
562 | if (store_event_type(evt_name) < 0) | ||
563 | return EVT_FAILED; | ||
564 | |||
537 | return parse_single_tracepoint_event(sys_name, evt_name, | 565 | return parse_single_tracepoint_event(sys_name, evt_name, |
538 | evt_length, attr, strp); | 566 | evt_length, attr, strp); |
567 | } | ||
539 | } | 568 | } |
540 | 569 | ||
541 | static enum event_result | 570 | static enum event_result |
@@ -778,41 +807,11 @@ modifier: | |||
778 | return ret; | 807 | return ret; |
779 | } | 808 | } |
780 | 809 | ||
781 | static int store_event_type(const char *orgname) | ||
782 | { | ||
783 | char filename[PATH_MAX], *c; | ||
784 | FILE *file; | ||
785 | int id, n; | ||
786 | |||
787 | sprintf(filename, "%s/", debugfs_path); | ||
788 | strncat(filename, orgname, strlen(orgname)); | ||
789 | strcat(filename, "/id"); | ||
790 | |||
791 | c = strchr(filename, ':'); | ||
792 | if (c) | ||
793 | *c = '/'; | ||
794 | |||
795 | file = fopen(filename, "r"); | ||
796 | if (!file) | ||
797 | return 0; | ||
798 | n = fscanf(file, "%i", &id); | ||
799 | fclose(file); | ||
800 | if (n < 1) { | ||
801 | pr_err("cannot store event ID\n"); | ||
802 | return -EINVAL; | ||
803 | } | ||
804 | return perf_header__push_event(id, orgname); | ||
805 | } | ||
806 | |||
807 | int parse_events(const struct option *opt __used, const char *str, int unset __used) | 810 | int parse_events(const struct option *opt __used, const char *str, int unset __used) |
808 | { | 811 | { |
809 | struct perf_event_attr attr; | 812 | struct perf_event_attr attr; |
810 | enum event_result ret; | 813 | enum event_result ret; |
811 | 814 | ||
812 | if (strchr(str, ':')) | ||
813 | if (store_event_type(str) < 0) | ||
814 | return -1; | ||
815 | |||
816 | for (;;) { | 815 | for (;;) { |
817 | memset(&attr, 0, sizeof(attr)); | 816 | memset(&attr, 0, sizeof(attr)); |
818 | ret = parse_event_symbols(&str, &attr); | 817 | ret = parse_event_symbols(&str, &attr); |
@@ -824,7 +823,7 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
824 | 823 | ||
825 | if (ret != EVT_HANDLED_ALL) { | 824 | if (ret != EVT_HANDLED_ALL) { |
826 | struct perf_evsel *evsel; | 825 | struct perf_evsel *evsel; |
827 | evsel = perf_evsel__new(attr.type, attr.config, | 826 | evsel = perf_evsel__new(&attr, |
828 | nr_counters); | 827 | nr_counters); |
829 | if (evsel == NULL) | 828 | if (evsel == NULL) |
830 | return -1; | 829 | return -1; |
@@ -1014,8 +1013,15 @@ void print_events(void) | |||
1014 | 1013 | ||
1015 | int perf_evsel_list__create_default(void) | 1014 | int perf_evsel_list__create_default(void) |
1016 | { | 1015 | { |
1017 | struct perf_evsel *evsel = perf_evsel__new(PERF_TYPE_HARDWARE, | 1016 | struct perf_evsel *evsel; |
1018 | PERF_COUNT_HW_CPU_CYCLES, 0); | 1017 | struct perf_event_attr attr; |
1018 | |||
1019 | memset(&attr, 0, sizeof(attr)); | ||
1020 | attr.type = PERF_TYPE_HARDWARE; | ||
1021 | attr.config = PERF_COUNT_HW_CPU_CYCLES; | ||
1022 | |||
1023 | evsel = perf_evsel__new(&attr, 0); | ||
1024 | |||
1019 | if (evsel == NULL) | 1025 | if (evsel == NULL) |
1020 | return -ENOMEM; | 1026 | return -ENOMEM; |
1021 | 1027 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 6fb4694d05fa..313dac2d94ce 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1007,7 +1007,7 @@ more: | |||
1007 | if (size == 0) | 1007 | if (size == 0) |
1008 | size = 8; | 1008 | size = 8; |
1009 | 1009 | ||
1010 | if (head + event->header.size >= mmap_size) { | 1010 | if (head + event->header.size > mmap_size) { |
1011 | if (mmaps[map_idx]) { | 1011 | if (mmaps[map_idx]) { |
1012 | munmap(mmaps[map_idx], mmap_size); | 1012 | munmap(mmaps[map_idx], mmap_size); |
1013 | mmaps[map_idx] = NULL; | 1013 | mmaps[map_idx] = NULL; |