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/builtin-record.c | 11 | ||||
| -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 | 49 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 2 |
12 files changed, 215 insertions, 91 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 52462ae2645..e032716c839 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 1b9b13ee2a7..2b5387d53ba 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/builtin-record.c b/tools/perf/builtin-record.c index 7bc04903548..fcd29e8af29 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, |
| @@ -927,6 +936,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
| 927 | list_for_each_entry(pos, &evsel_list, node) { | 936 | list_for_each_entry(pos, &evsel_list, node) { |
| 928 | if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) | 937 | if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) |
| 929 | goto out_free_fd; | 938 | goto out_free_fd; |
| 939 | if (perf_header__push_event(pos->attr.config, event_name(pos))) | ||
| 940 | goto out_free_fd; | ||
| 930 | } | 941 | } |
| 931 | event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * | 942 | event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * |
| 932 | MAX_COUNTERS * threads->nr)); | 943 | MAX_COUNTERS * threads->nr)); |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 7a4ebeb8b01..29e7ffd8569 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 02b2d8013a6..0ff11d9b13b 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 1c984342a57..ed5696198d3 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 1e67ab9c7eb..05344c6210a 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 5b1ecd66bb3..595d0f4a710 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 c95267e63c5..f5cfed60af9 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 a0ccd69c3fc..b2d755fe88a 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 649083f27e0..bc2732ee23e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -490,7 +490,6 @@ 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 | |||
| 494 | static enum event_result parse_tracepoint_event(const char **strp, | 493 | static enum event_result parse_tracepoint_event(const char **strp, |
| 495 | struct perf_event_attr *attr) | 494 | struct perf_event_attr *attr) |
| 496 | { | 495 | { |
| @@ -530,12 +529,13 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
| 530 | if (evt_length >= MAX_EVENT_LENGTH) | 529 | if (evt_length >= MAX_EVENT_LENGTH) |
| 531 | return EVT_FAILED; | 530 | return EVT_FAILED; |
| 532 | if (strpbrk(evt_name, "*?")) { | 531 | if (strpbrk(evt_name, "*?")) { |
| 533 | *strp += strlen(sys_name) + evt_length; | 532 | *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ |
| 534 | return parse_multiple_tracepoint_event(sys_name, evt_name, | 533 | return parse_multiple_tracepoint_event(sys_name, evt_name, |
| 535 | flags); | 534 | flags); |
| 536 | } else | 535 | } else { |
| 537 | return parse_single_tracepoint_event(sys_name, evt_name, | 536 | return parse_single_tracepoint_event(sys_name, evt_name, |
| 538 | evt_length, attr, strp); | 537 | evt_length, attr, strp); |
| 538 | } | ||
| 539 | } | 539 | } |
| 540 | 540 | ||
| 541 | static enum event_result | 541 | static enum event_result |
| @@ -778,41 +778,11 @@ modifier: | |||
| 778 | return ret; | 778 | return ret; |
| 779 | } | 779 | } |
| 780 | 780 | ||
| 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) | 781 | int parse_events(const struct option *opt __used, const char *str, int unset __used) |
| 808 | { | 782 | { |
| 809 | struct perf_event_attr attr; | 783 | struct perf_event_attr attr; |
| 810 | enum event_result ret; | 784 | enum event_result ret; |
| 811 | 785 | ||
| 812 | if (strchr(str, ':')) | ||
| 813 | if (store_event_type(str) < 0) | ||
| 814 | return -1; | ||
| 815 | |||
| 816 | for (;;) { | 786 | for (;;) { |
| 817 | memset(&attr, 0, sizeof(attr)); | 787 | memset(&attr, 0, sizeof(attr)); |
| 818 | ret = parse_event_symbols(&str, &attr); | 788 | ret = parse_event_symbols(&str, &attr); |
| @@ -824,7 +794,7 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u | |||
| 824 | 794 | ||
| 825 | if (ret != EVT_HANDLED_ALL) { | 795 | if (ret != EVT_HANDLED_ALL) { |
| 826 | struct perf_evsel *evsel; | 796 | struct perf_evsel *evsel; |
| 827 | evsel = perf_evsel__new(attr.type, attr.config, | 797 | evsel = perf_evsel__new(&attr, |
| 828 | nr_counters); | 798 | nr_counters); |
| 829 | if (evsel == NULL) | 799 | if (evsel == NULL) |
| 830 | return -1; | 800 | return -1; |
| @@ -1014,8 +984,15 @@ void print_events(void) | |||
| 1014 | 984 | ||
| 1015 | int perf_evsel_list__create_default(void) | 985 | int perf_evsel_list__create_default(void) |
| 1016 | { | 986 | { |
| 1017 | struct perf_evsel *evsel = perf_evsel__new(PERF_TYPE_HARDWARE, | 987 | struct perf_evsel *evsel; |
| 1018 | PERF_COUNT_HW_CPU_CYCLES, 0); | 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 | |||
| 1019 | if (evsel == NULL) | 996 | if (evsel == NULL) |
| 1020 | return -ENOMEM; | 997 | return -ENOMEM; |
| 1021 | 998 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 6fb4694d05f..313dac2d94c 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; |
