diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-04-08 11:03:47 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-04-08 11:03:47 -0400 |
commit | 51ab7155c08baf45cc2aa911961e5b78422e478f (patch) | |
tree | f6b0c0d524a376fa4e0411d08bac307d931f35c9 /tools/perf | |
parent | 6645f3187f5beb64f7a40515cfa18f3889264ece (diff) | |
parent | a1e12da4796a4ddd0e911687a290eb396d1c64bf (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
- Teach 'perf record' about perf_event_attr.clockid (Peter Zijlstra)
- Improve 'perf sched replay' on high CPU core count machines (Yunlong Song)
- Consider PERF_RECORD_ events with cpumode == 0 in 'perf top', removing one
cause of long term memory usage buildup, i.e. not processing PERF_RECORD_EXIT
events (Arnaldo Carvalho de Melo)
- Add 'I' event modifier for perf_event_attr.exclude_idle bit (Jiri Olsa)
- Respect -i option 'in perf kmem' (Jiri Olsa)
Infrastructure changes:
- Honor operator priority in libtraceevent (Namhyung Kim)
- Merge all perf_event_attr print functions (Peter Zijlstra)
- Check kmaps access to make code more robust (Wang Nan)
- Fix inverted logic in perf_mmap__empty() (He Kuang)
- Fix ARM 32 'perf probe' building error (Wang Nan)
- Fix perf_event_attr tests (Jiri Olsa)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/perf-list.txt | 1 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 7 | ||||
-rw-r--r-- | tools/perf/builtin-kmem.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 87 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-sched.c | 67 | ||||
-rw-r--r-- | tools/perf/perf.h | 2 | ||||
-rw-r--r-- | tools/perf/tests/attr/base-record | 2 | ||||
-rw-r--r-- | tools/perf/tests/attr/base-stat | 2 | ||||
-rw-r--r-- | tools/perf/tests/parse-events.c | 40 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 2 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 325 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 6 | ||||
-rw-r--r-- | tools/perf/util/header.c | 28 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 5 | ||||
-rw-r--r-- | tools/perf/util/map.c | 20 | ||||
-rw-r--r-- | tools/perf/util/map.h | 6 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 8 | ||||
-rw-r--r-- | tools/perf/util/parse-events.l | 2 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 5 | ||||
-rw-r--r-- | tools/perf/util/session.c | 3 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 16 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 34 |
23 files changed, 461 insertions, 212 deletions
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 4692d277980b..bada8933fdd4 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt | |||
@@ -26,6 +26,7 @@ counted. The following modifiers exist: | |||
26 | u - user-space counting | 26 | u - user-space counting |
27 | k - kernel counting | 27 | k - kernel counting |
28 | h - hypervisor counting | 28 | h - hypervisor counting |
29 | I - non idle counting | ||
29 | G - guest counting (in KVM guests) | 30 | G - guest counting (in KVM guests) |
30 | H - host counting (not in KVM guests) | 31 | H - host counting (not in KVM guests) |
31 | p - precise level | 32 | p - precise level |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 355c4f5569b5..4847a793de65 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -250,6 +250,13 @@ is off by default. | |||
250 | --running-time:: | 250 | --running-time:: |
251 | Record running and enabled time for read events (:S) | 251 | Record running and enabled time for read events (:S) |
252 | 252 | ||
253 | -k:: | ||
254 | --clockid:: | ||
255 | Sets the clock id to use for the various time fields in the perf_event_type | ||
256 | records. See clock_gettime(). In particular CLOCK_MONOTONIC and | ||
257 | CLOCK_MONOTONIC_RAW are supported, some events might also allow | ||
258 | CLOCK_BOOTTIME, CLOCK_REALTIME and CLOCK_TAI. | ||
259 | |||
253 | SEE ALSO | 260 | SEE ALSO |
254 | -------- | 261 | -------- |
255 | linkperf:perf-stat[1], linkperf:perf-list[1] | 262 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index ac303ef9f2f0..4ebf65c79434 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -663,7 +663,6 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
663 | { | 663 | { |
664 | const char * const default_sort_order = "frag,hit,bytes"; | 664 | const char * const default_sort_order = "frag,hit,bytes"; |
665 | struct perf_data_file file = { | 665 | struct perf_data_file file = { |
666 | .path = input_name, | ||
667 | .mode = PERF_DATA_MODE_READ, | 666 | .mode = PERF_DATA_MODE_READ, |
668 | }; | 667 | }; |
669 | const struct option kmem_options[] = { | 668 | const struct option kmem_options[] = { |
@@ -701,6 +700,8 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
701 | return __cmd_record(argc, argv); | 700 | return __cmd_record(argc, argv); |
702 | } | 701 | } |
703 | 702 | ||
703 | file.path = input_name; | ||
704 | |||
704 | session = perf_session__new(&file, false, &perf_kmem); | 705 | session = perf_session__new(&file, false, &perf_kmem); |
705 | if (session == NULL) | 706 | if (session == NULL) |
706 | return -1; | 707 | return -1; |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 18aad239b401..ac610488d2e1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -711,6 +711,90 @@ static int perf_record_config(const char *var, const char *value, void *cb) | |||
711 | return perf_default_config(var, value, cb); | 711 | return perf_default_config(var, value, cb); |
712 | } | 712 | } |
713 | 713 | ||
714 | struct clockid_map { | ||
715 | const char *name; | ||
716 | int clockid; | ||
717 | }; | ||
718 | |||
719 | #define CLOCKID_MAP(n, c) \ | ||
720 | { .name = n, .clockid = (c), } | ||
721 | |||
722 | #define CLOCKID_END { .name = NULL, } | ||
723 | |||
724 | |||
725 | /* | ||
726 | * Add the missing ones, we need to build on many distros... | ||
727 | */ | ||
728 | #ifndef CLOCK_MONOTONIC_RAW | ||
729 | #define CLOCK_MONOTONIC_RAW 4 | ||
730 | #endif | ||
731 | #ifndef CLOCK_BOOTTIME | ||
732 | #define CLOCK_BOOTTIME 7 | ||
733 | #endif | ||
734 | #ifndef CLOCK_TAI | ||
735 | #define CLOCK_TAI 11 | ||
736 | #endif | ||
737 | |||
738 | static const struct clockid_map clockids[] = { | ||
739 | /* available for all events, NMI safe */ | ||
740 | CLOCKID_MAP("monotonic", CLOCK_MONOTONIC), | ||
741 | CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW), | ||
742 | |||
743 | /* available for some events */ | ||
744 | CLOCKID_MAP("realtime", CLOCK_REALTIME), | ||
745 | CLOCKID_MAP("boottime", CLOCK_BOOTTIME), | ||
746 | CLOCKID_MAP("tai", CLOCK_TAI), | ||
747 | |||
748 | /* available for the lazy */ | ||
749 | CLOCKID_MAP("mono", CLOCK_MONOTONIC), | ||
750 | CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW), | ||
751 | CLOCKID_MAP("real", CLOCK_REALTIME), | ||
752 | CLOCKID_MAP("boot", CLOCK_BOOTTIME), | ||
753 | |||
754 | CLOCKID_END, | ||
755 | }; | ||
756 | |||
757 | static int parse_clockid(const struct option *opt, const char *str, int unset) | ||
758 | { | ||
759 | struct record_opts *opts = (struct record_opts *)opt->value; | ||
760 | const struct clockid_map *cm; | ||
761 | const char *ostr = str; | ||
762 | |||
763 | if (unset) { | ||
764 | opts->use_clockid = 0; | ||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | /* no arg passed */ | ||
769 | if (!str) | ||
770 | return 0; | ||
771 | |||
772 | /* no setting it twice */ | ||
773 | if (opts->use_clockid) | ||
774 | return -1; | ||
775 | |||
776 | opts->use_clockid = true; | ||
777 | |||
778 | /* if its a number, we're done */ | ||
779 | if (sscanf(str, "%d", &opts->clockid) == 1) | ||
780 | return 0; | ||
781 | |||
782 | /* allow a "CLOCK_" prefix to the name */ | ||
783 | if (!strncasecmp(str, "CLOCK_", 6)) | ||
784 | str += 6; | ||
785 | |||
786 | for (cm = clockids; cm->name; cm++) { | ||
787 | if (!strcasecmp(str, cm->name)) { | ||
788 | opts->clockid = cm->clockid; | ||
789 | return 0; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | opts->use_clockid = false; | ||
794 | ui__warning("unknown clockid %s, check man page\n", ostr); | ||
795 | return -1; | ||
796 | } | ||
797 | |||
714 | static const char * const __record_usage[] = { | 798 | static const char * const __record_usage[] = { |
715 | "perf record [<options>] [<command>]", | 799 | "perf record [<options>] [<command>]", |
716 | "perf record [<options>] -- <command> [<options>]", | 800 | "perf record [<options>] -- <command> [<options>]", |
@@ -842,6 +926,9 @@ struct option __record_options[] = { | |||
842 | "Sample machine registers on interrupt"), | 926 | "Sample machine registers on interrupt"), |
843 | OPT_BOOLEAN(0, "running-time", &record.opts.running_time, | 927 | OPT_BOOLEAN(0, "running-time", &record.opts.running_time, |
844 | "Record running/enabled time of read (:S) events"), | 928 | "Record running/enabled time of read (:S) events"), |
929 | OPT_CALLBACK('k', "clockid", &record.opts, | ||
930 | "clockid", "clockid to use for events, see clock_gettime()", | ||
931 | parse_clockid), | ||
845 | OPT_END() | 932 | OPT_END() |
846 | }; | 933 | }; |
847 | 934 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index b5b2ad4ca9c4..476cdf7afcca 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -347,7 +347,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
347 | static void report__warn_kptr_restrict(const struct report *rep) | 347 | static void report__warn_kptr_restrict(const struct report *rep) |
348 | { | 348 | { |
349 | struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION]; | 349 | struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION]; |
350 | struct kmap *kernel_kmap = map__kmap(kernel_map); | 350 | struct kmap *kernel_kmap = kernel_map ? map__kmap(kernel_map) : NULL; |
351 | 351 | ||
352 | if (kernel_map == NULL || | 352 | if (kernel_map == NULL || |
353 | (kernel_map->dso->hit && | 353 | (kernel_map->dso->hit && |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 3b3a5bb97059..5275bab70313 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -23,12 +23,13 @@ | |||
23 | #include <semaphore.h> | 23 | #include <semaphore.h> |
24 | #include <pthread.h> | 24 | #include <pthread.h> |
25 | #include <math.h> | 25 | #include <math.h> |
26 | #include <api/fs/fs.h> | ||
26 | 27 | ||
27 | #define PR_SET_NAME 15 /* Set process name */ | 28 | #define PR_SET_NAME 15 /* Set process name */ |
28 | #define MAX_CPUS 4096 | 29 | #define MAX_CPUS 4096 |
29 | #define COMM_LEN 20 | 30 | #define COMM_LEN 20 |
30 | #define SYM_LEN 129 | 31 | #define SYM_LEN 129 |
31 | #define MAX_PID 65536 | 32 | #define MAX_PID 1024000 |
32 | 33 | ||
33 | struct sched_atom; | 34 | struct sched_atom; |
34 | 35 | ||
@@ -124,7 +125,7 @@ struct perf_sched { | |||
124 | struct perf_tool tool; | 125 | struct perf_tool tool; |
125 | const char *sort_order; | 126 | const char *sort_order; |
126 | unsigned long nr_tasks; | 127 | unsigned long nr_tasks; |
127 | struct task_desc *pid_to_task[MAX_PID]; | 128 | struct task_desc **pid_to_task; |
128 | struct task_desc **tasks; | 129 | struct task_desc **tasks; |
129 | const struct trace_sched_handler *tp_handler; | 130 | const struct trace_sched_handler *tp_handler; |
130 | pthread_mutex_t start_work_mutex; | 131 | pthread_mutex_t start_work_mutex; |
@@ -169,6 +170,7 @@ struct perf_sched { | |||
169 | u64 cpu_last_switched[MAX_CPUS]; | 170 | u64 cpu_last_switched[MAX_CPUS]; |
170 | struct rb_root atom_root, sorted_atom_root; | 171 | struct rb_root atom_root, sorted_atom_root; |
171 | struct list_head sort_list, cmp_pid; | 172 | struct list_head sort_list, cmp_pid; |
173 | bool force; | ||
172 | }; | 174 | }; |
173 | 175 | ||
174 | static u64 get_nsecs(void) | 176 | static u64 get_nsecs(void) |
@@ -326,8 +328,19 @@ static struct task_desc *register_pid(struct perf_sched *sched, | |||
326 | unsigned long pid, const char *comm) | 328 | unsigned long pid, const char *comm) |
327 | { | 329 | { |
328 | struct task_desc *task; | 330 | struct task_desc *task; |
331 | static int pid_max; | ||
329 | 332 | ||
330 | BUG_ON(pid >= MAX_PID); | 333 | if (sched->pid_to_task == NULL) { |
334 | if (sysctl__read_int("kernel/pid_max", &pid_max) < 0) | ||
335 | pid_max = MAX_PID; | ||
336 | BUG_ON((sched->pid_to_task = calloc(pid_max, sizeof(struct task_desc *))) == NULL); | ||
337 | } | ||
338 | if (pid >= (unsigned long)pid_max) { | ||
339 | BUG_ON((sched->pid_to_task = realloc(sched->pid_to_task, (pid + 1) * | ||
340 | sizeof(struct task_desc *))) == NULL); | ||
341 | while (pid >= (unsigned long)pid_max) | ||
342 | sched->pid_to_task[pid_max++] = NULL; | ||
343 | } | ||
331 | 344 | ||
332 | task = sched->pid_to_task[pid]; | 345 | task = sched->pid_to_task[pid]; |
333 | 346 | ||
@@ -346,7 +359,7 @@ static struct task_desc *register_pid(struct perf_sched *sched, | |||
346 | 359 | ||
347 | sched->pid_to_task[pid] = task; | 360 | sched->pid_to_task[pid] = task; |
348 | sched->nr_tasks++; | 361 | sched->nr_tasks++; |
349 | sched->tasks = realloc(sched->tasks, sched->nr_tasks * sizeof(struct task_task *)); | 362 | sched->tasks = realloc(sched->tasks, sched->nr_tasks * sizeof(struct task_desc *)); |
350 | BUG_ON(!sched->tasks); | 363 | BUG_ON(!sched->tasks); |
351 | sched->tasks[task->nr] = task; | 364 | sched->tasks[task->nr] = task; |
352 | 365 | ||
@@ -425,24 +438,45 @@ static u64 get_cpu_usage_nsec_parent(void) | |||
425 | return sum; | 438 | return sum; |
426 | } | 439 | } |
427 | 440 | ||
428 | static int self_open_counters(void) | 441 | static int self_open_counters(struct perf_sched *sched, unsigned long cur_task) |
429 | { | 442 | { |
430 | struct perf_event_attr attr; | 443 | struct perf_event_attr attr; |
431 | char sbuf[STRERR_BUFSIZE]; | 444 | char sbuf[STRERR_BUFSIZE], info[STRERR_BUFSIZE]; |
432 | int fd; | 445 | int fd; |
446 | struct rlimit limit; | ||
447 | bool need_privilege = false; | ||
433 | 448 | ||
434 | memset(&attr, 0, sizeof(attr)); | 449 | memset(&attr, 0, sizeof(attr)); |
435 | 450 | ||
436 | attr.type = PERF_TYPE_SOFTWARE; | 451 | attr.type = PERF_TYPE_SOFTWARE; |
437 | attr.config = PERF_COUNT_SW_TASK_CLOCK; | 452 | attr.config = PERF_COUNT_SW_TASK_CLOCK; |
438 | 453 | ||
454 | force_again: | ||
439 | fd = sys_perf_event_open(&attr, 0, -1, -1, | 455 | fd = sys_perf_event_open(&attr, 0, -1, -1, |
440 | perf_event_open_cloexec_flag()); | 456 | perf_event_open_cloexec_flag()); |
441 | 457 | ||
442 | if (fd < 0) | 458 | if (fd < 0) { |
459 | if (errno == EMFILE) { | ||
460 | if (sched->force) { | ||
461 | BUG_ON(getrlimit(RLIMIT_NOFILE, &limit) == -1); | ||
462 | limit.rlim_cur += sched->nr_tasks - cur_task; | ||
463 | if (limit.rlim_cur > limit.rlim_max) { | ||
464 | limit.rlim_max = limit.rlim_cur; | ||
465 | need_privilege = true; | ||
466 | } | ||
467 | if (setrlimit(RLIMIT_NOFILE, &limit) == -1) { | ||
468 | if (need_privilege && errno == EPERM) | ||
469 | strcpy(info, "Need privilege\n"); | ||
470 | } else | ||
471 | goto force_again; | ||
472 | } else | ||
473 | strcpy(info, "Have a try with -f option\n"); | ||
474 | } | ||
443 | pr_err("Error: sys_perf_event_open() syscall returned " | 475 | pr_err("Error: sys_perf_event_open() syscall returned " |
444 | "with %d (%s)\n", fd, | 476 | "with %d (%s)\n%s", fd, |
445 | strerror_r(errno, sbuf, sizeof(sbuf))); | 477 | strerror_r(errno, sbuf, sizeof(sbuf)), info); |
478 | exit(EXIT_FAILURE); | ||
479 | } | ||
446 | return fd; | 480 | return fd; |
447 | } | 481 | } |
448 | 482 | ||
@@ -460,6 +494,7 @@ static u64 get_cpu_usage_nsec_self(int fd) | |||
460 | struct sched_thread_parms { | 494 | struct sched_thread_parms { |
461 | struct task_desc *task; | 495 | struct task_desc *task; |
462 | struct perf_sched *sched; | 496 | struct perf_sched *sched; |
497 | int fd; | ||
463 | }; | 498 | }; |
464 | 499 | ||
465 | static void *thread_func(void *ctx) | 500 | static void *thread_func(void *ctx) |
@@ -470,13 +505,12 @@ static void *thread_func(void *ctx) | |||
470 | u64 cpu_usage_0, cpu_usage_1; | 505 | u64 cpu_usage_0, cpu_usage_1; |
471 | unsigned long i, ret; | 506 | unsigned long i, ret; |
472 | char comm2[22]; | 507 | char comm2[22]; |
473 | int fd; | 508 | int fd = parms->fd; |
474 | 509 | ||
475 | zfree(&parms); | 510 | zfree(&parms); |
476 | 511 | ||
477 | sprintf(comm2, ":%s", this_task->comm); | 512 | sprintf(comm2, ":%s", this_task->comm); |
478 | prctl(PR_SET_NAME, comm2); | 513 | prctl(PR_SET_NAME, comm2); |
479 | fd = self_open_counters(); | ||
480 | if (fd < 0) | 514 | if (fd < 0) |
481 | return NULL; | 515 | return NULL; |
482 | again: | 516 | again: |
@@ -528,6 +562,7 @@ static void create_tasks(struct perf_sched *sched) | |||
528 | BUG_ON(parms == NULL); | 562 | BUG_ON(parms == NULL); |
529 | parms->task = task = sched->tasks[i]; | 563 | parms->task = task = sched->tasks[i]; |
530 | parms->sched = sched; | 564 | parms->sched = sched; |
565 | parms->fd = self_open_counters(sched, i); | ||
531 | sem_init(&task->sleep_sem, 0, 0); | 566 | sem_init(&task->sleep_sem, 0, 0); |
532 | sem_init(&task->ready_for_work, 0, 0); | 567 | sem_init(&task->ready_for_work, 0, 0); |
533 | sem_init(&task->work_done_sem, 0, 0); | 568 | sem_init(&task->work_done_sem, 0, 0); |
@@ -572,13 +607,13 @@ static void wait_for_tasks(struct perf_sched *sched) | |||
572 | cpu_usage_1 = get_cpu_usage_nsec_parent(); | 607 | cpu_usage_1 = get_cpu_usage_nsec_parent(); |
573 | if (!sched->runavg_cpu_usage) | 608 | if (!sched->runavg_cpu_usage) |
574 | sched->runavg_cpu_usage = sched->cpu_usage; | 609 | sched->runavg_cpu_usage = sched->cpu_usage; |
575 | sched->runavg_cpu_usage = (sched->runavg_cpu_usage * 9 + sched->cpu_usage) / 10; | 610 | sched->runavg_cpu_usage = (sched->runavg_cpu_usage * (sched->replay_repeat - 1) + sched->cpu_usage) / sched->replay_repeat; |
576 | 611 | ||
577 | sched->parent_cpu_usage = cpu_usage_1 - cpu_usage_0; | 612 | sched->parent_cpu_usage = cpu_usage_1 - cpu_usage_0; |
578 | if (!sched->runavg_parent_cpu_usage) | 613 | if (!sched->runavg_parent_cpu_usage) |
579 | sched->runavg_parent_cpu_usage = sched->parent_cpu_usage; | 614 | sched->runavg_parent_cpu_usage = sched->parent_cpu_usage; |
580 | sched->runavg_parent_cpu_usage = (sched->runavg_parent_cpu_usage * 9 + | 615 | sched->runavg_parent_cpu_usage = (sched->runavg_parent_cpu_usage * (sched->replay_repeat - 1) + |
581 | sched->parent_cpu_usage)/10; | 616 | sched->parent_cpu_usage)/sched->replay_repeat; |
582 | 617 | ||
583 | ret = pthread_mutex_lock(&sched->start_work_mutex); | 618 | ret = pthread_mutex_lock(&sched->start_work_mutex); |
584 | BUG_ON(ret); | 619 | BUG_ON(ret); |
@@ -610,7 +645,7 @@ static void run_one_test(struct perf_sched *sched) | |||
610 | sched->sum_fluct += fluct; | 645 | sched->sum_fluct += fluct; |
611 | if (!sched->run_avg) | 646 | if (!sched->run_avg) |
612 | sched->run_avg = delta; | 647 | sched->run_avg = delta; |
613 | sched->run_avg = (sched->run_avg * 9 + delta) / 10; | 648 | sched->run_avg = (sched->run_avg * (sched->replay_repeat - 1) + delta) / sched->replay_repeat; |
614 | 649 | ||
615 | printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / 1000000.0); | 650 | printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / 1000000.0); |
616 | 651 | ||
@@ -1452,6 +1487,7 @@ static int perf_sched__read_events(struct perf_sched *sched) | |||
1452 | struct perf_data_file file = { | 1487 | struct perf_data_file file = { |
1453 | .path = input_name, | 1488 | .path = input_name, |
1454 | .mode = PERF_DATA_MODE_READ, | 1489 | .mode = PERF_DATA_MODE_READ, |
1490 | .force = sched->force, | ||
1455 | }; | 1491 | }; |
1456 | int rc = -1; | 1492 | int rc = -1; |
1457 | 1493 | ||
@@ -1685,6 +1721,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1685 | "be more verbose (show symbol address, etc)"), | 1721 | "be more verbose (show symbol address, etc)"), |
1686 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1722 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
1687 | "dump raw trace in ASCII"), | 1723 | "dump raw trace in ASCII"), |
1724 | OPT_BOOLEAN('f', "force", &sched.force, "don't complain, do it"), | ||
1688 | OPT_END() | 1725 | OPT_END() |
1689 | }; | 1726 | }; |
1690 | const struct option sched_options[] = { | 1727 | const struct option sched_options[] = { |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index c38a085a5571..e14bb637255c 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -62,6 +62,8 @@ struct record_opts { | |||
62 | u64 user_interval; | 62 | u64 user_interval; |
63 | bool sample_transaction; | 63 | bool sample_transaction; |
64 | unsigned initial_delay; | 64 | unsigned initial_delay; |
65 | bool use_clockid; | ||
66 | clockid_t clockid; | ||
65 | }; | 67 | }; |
66 | 68 | ||
67 | struct option; | 69 | struct option; |
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record index d3095dafed36..7e6d74946e04 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/attr/base-record | |||
@@ -5,7 +5,7 @@ group_fd=-1 | |||
5 | flags=0|8 | 5 | flags=0|8 |
6 | cpu=* | 6 | cpu=* |
7 | type=0|1 | 7 | type=0|1 |
8 | size=104 | 8 | size=112 |
9 | config=0 | 9 | config=0 |
10 | sample_period=4000 | 10 | sample_period=4000 |
11 | sample_type=263 | 11 | sample_type=263 |
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat index 872ed7e24c7c..f4cf148f14cb 100644 --- a/tools/perf/tests/attr/base-stat +++ b/tools/perf/tests/attr/base-stat | |||
@@ -5,7 +5,7 @@ group_fd=-1 | |||
5 | flags=0|8 | 5 | flags=0|8 |
6 | cpu=* | 6 | cpu=* |
7 | type=0 | 7 | type=0 |
8 | size=104 | 8 | size=112 |
9 | config=0 | 9 | config=0 |
10 | sample_period=0 | 10 | sample_period=0 |
11 | sample_type=0 | 11 | sample_type=0 |
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index ac243ebcb20a..3de744961739 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
@@ -295,6 +295,36 @@ static int test__checkevent_genhw_modifier(struct perf_evlist *evlist) | |||
295 | return test__checkevent_genhw(evlist); | 295 | return test__checkevent_genhw(evlist); |
296 | } | 296 | } |
297 | 297 | ||
298 | static int test__checkevent_exclude_idle_modifier(struct perf_evlist *evlist) | ||
299 | { | ||
300 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
301 | |||
302 | TEST_ASSERT_VAL("wrong exclude idle", evsel->attr.exclude_idle); | ||
303 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
304 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
305 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
306 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
307 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
308 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
309 | |||
310 | return test__checkevent_symbolic_name(evlist); | ||
311 | } | ||
312 | |||
313 | static int test__checkevent_exclude_idle_modifier_1(struct perf_evlist *evlist) | ||
314 | { | ||
315 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
316 | |||
317 | TEST_ASSERT_VAL("wrong exclude idle", evsel->attr.exclude_idle); | ||
318 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
319 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
320 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
321 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
322 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
323 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
324 | |||
325 | return test__checkevent_symbolic_name(evlist); | ||
326 | } | ||
327 | |||
298 | static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) | 328 | static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) |
299 | { | 329 | { |
300 | struct perf_evsel *evsel = perf_evlist__first(evlist); | 330 | struct perf_evsel *evsel = perf_evlist__first(evlist); |
@@ -1494,6 +1524,16 @@ static struct evlist_test test__events[] = { | |||
1494 | .id = 100, | 1524 | .id = 100, |
1495 | }, | 1525 | }, |
1496 | #endif | 1526 | #endif |
1527 | { | ||
1528 | .name = "instructions:I", | ||
1529 | .check = test__checkevent_exclude_idle_modifier, | ||
1530 | .id = 45, | ||
1531 | }, | ||
1532 | { | ||
1533 | .name = "instructions:kIG", | ||
1534 | .check = test__checkevent_exclude_idle_modifier_1, | ||
1535 | .id = 46, | ||
1536 | }, | ||
1497 | }; | 1537 | }; |
1498 | 1538 | ||
1499 | static struct evlist_test test__events_pmu[] = { | 1539 | static struct evlist_test test__events_pmu[] = { |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 82bf224bbee9..76ef7ee62640 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -695,7 +695,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
695 | 695 | ||
696 | static bool perf_mmap__empty(struct perf_mmap *md) | 696 | static bool perf_mmap__empty(struct perf_mmap *md) |
697 | { | 697 | { |
698 | return perf_mmap__read_head(md) != md->prev; | 698 | return perf_mmap__read_head(md) == md->prev; |
699 | } | 699 | } |
700 | 700 | ||
701 | static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) | 701 | static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 358e5954baa8..33e3fd8c2e68 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -32,8 +32,12 @@ static struct { | |||
32 | bool exclude_guest; | 32 | bool exclude_guest; |
33 | bool mmap2; | 33 | bool mmap2; |
34 | bool cloexec; | 34 | bool cloexec; |
35 | bool clockid; | ||
36 | bool clockid_wrong; | ||
35 | } perf_missing_features; | 37 | } perf_missing_features; |
36 | 38 | ||
39 | static clockid_t clockid; | ||
40 | |||
37 | static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused) | 41 | static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused) |
38 | { | 42 | { |
39 | return 0; | 43 | return 0; |
@@ -761,6 +765,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
761 | attr->disabled = 0; | 765 | attr->disabled = 0; |
762 | attr->enable_on_exec = 0; | 766 | attr->enable_on_exec = 0; |
763 | } | 767 | } |
768 | |||
769 | clockid = opts->clockid; | ||
770 | if (opts->use_clockid) { | ||
771 | attr->use_clockid = 1; | ||
772 | attr->clockid = opts->clockid; | ||
773 | } | ||
764 | } | 774 | } |
765 | 775 | ||
766 | static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 776 | static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
@@ -1001,67 +1011,126 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread) | |||
1001 | return fd; | 1011 | return fd; |
1002 | } | 1012 | } |
1003 | 1013 | ||
1004 | #define __PRINT_ATTR(fmt, cast, field) \ | 1014 | struct bit_names { |
1005 | fprintf(fp, " %-19s "fmt"\n", #field, cast attr->field) | 1015 | int bit; |
1006 | 1016 | const char *name; | |
1007 | #define PRINT_ATTR_U32(field) __PRINT_ATTR("%u" , , field) | 1017 | }; |
1008 | #define PRINT_ATTR_X32(field) __PRINT_ATTR("%#x", , field) | 1018 | |
1009 | #define PRINT_ATTR_U64(field) __PRINT_ATTR("%" PRIu64, (uint64_t), field) | 1019 | static void __p_bits(char *buf, size_t size, u64 value, struct bit_names *bits) |
1010 | #define PRINT_ATTR_X64(field) __PRINT_ATTR("%#"PRIx64, (uint64_t), field) | 1020 | { |
1011 | 1021 | bool first_bit = true; | |
1012 | #define PRINT_ATTR2N(name1, field1, name2, field2) \ | 1022 | int i = 0; |
1013 | fprintf(fp, " %-19s %u %-19s %u\n", \ | 1023 | |
1014 | name1, attr->field1, name2, attr->field2) | 1024 | do { |
1015 | 1025 | if (value & bits[i].bit) { | |
1016 | #define PRINT_ATTR2(field1, field2) \ | 1026 | buf += scnprintf(buf, size, "%s%s", first_bit ? "" : "|", bits[i].name); |
1017 | PRINT_ATTR2N(#field1, field1, #field2, field2) | 1027 | first_bit = false; |
1018 | 1028 | } | |
1019 | static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) | 1029 | } while (bits[++i].name != NULL); |
1020 | { | 1030 | } |
1021 | size_t ret = 0; | 1031 | |
1022 | 1032 | static void __p_sample_type(char *buf, size_t size, u64 value) | |
1023 | ret += fprintf(fp, "%.60s\n", graph_dotted_line); | 1033 | { |
1024 | ret += fprintf(fp, "perf_event_attr:\n"); | 1034 | #define bit_name(n) { PERF_SAMPLE_##n, #n } |
1025 | 1035 | struct bit_names bits[] = { | |
1026 | ret += PRINT_ATTR_U32(type); | 1036 | bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR), |
1027 | ret += PRINT_ATTR_U32(size); | 1037 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), |
1028 | ret += PRINT_ATTR_X64(config); | 1038 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), |
1029 | ret += PRINT_ATTR_U64(sample_period); | 1039 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), |
1030 | ret += PRINT_ATTR_U64(sample_freq); | 1040 | bit_name(IDENTIFIER), bit_name(REGS_INTR), |
1031 | ret += PRINT_ATTR_X64(sample_type); | 1041 | { .name = NULL, } |
1032 | ret += PRINT_ATTR_X64(read_format); | 1042 | }; |
1033 | 1043 | #undef bit_name | |
1034 | ret += PRINT_ATTR2(disabled, inherit); | 1044 | __p_bits(buf, size, value, bits); |
1035 | ret += PRINT_ATTR2(pinned, exclusive); | 1045 | } |
1036 | ret += PRINT_ATTR2(exclude_user, exclude_kernel); | 1046 | |
1037 | ret += PRINT_ATTR2(exclude_hv, exclude_idle); | 1047 | static void __p_read_format(char *buf, size_t size, u64 value) |
1038 | ret += PRINT_ATTR2(mmap, comm); | 1048 | { |
1039 | ret += PRINT_ATTR2(mmap2, comm_exec); | 1049 | #define bit_name(n) { PERF_FORMAT_##n, #n } |
1040 | ret += PRINT_ATTR2(freq, inherit_stat); | 1050 | struct bit_names bits[] = { |
1041 | ret += PRINT_ATTR2(enable_on_exec, task); | 1051 | bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING), |
1042 | ret += PRINT_ATTR2(watermark, precise_ip); | 1052 | bit_name(ID), bit_name(GROUP), |
1043 | ret += PRINT_ATTR2(mmap_data, sample_id_all); | 1053 | { .name = NULL, } |
1044 | ret += PRINT_ATTR2(exclude_host, exclude_guest); | 1054 | }; |
1045 | ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, | 1055 | #undef bit_name |
1046 | "excl.callchain_user", exclude_callchain_user); | 1056 | __p_bits(buf, size, value, bits); |
1047 | 1057 | } | |
1048 | ret += PRINT_ATTR_U32(wakeup_events); | 1058 | |
1049 | ret += PRINT_ATTR_U32(wakeup_watermark); | 1059 | #define BUF_SIZE 1024 |
1050 | ret += PRINT_ATTR_X32(bp_type); | 1060 | |
1051 | ret += PRINT_ATTR_X64(bp_addr); | 1061 | #define p_hex(val) snprintf(buf, BUF_SIZE, "%"PRIx64, (uint64_t)(val)) |
1052 | ret += PRINT_ATTR_X64(config1); | 1062 | #define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) |
1053 | ret += PRINT_ATTR_U64(bp_len); | 1063 | #define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) |
1054 | ret += PRINT_ATTR_X64(config2); | 1064 | #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) |
1055 | ret += PRINT_ATTR_X64(branch_sample_type); | 1065 | #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) |
1056 | ret += PRINT_ATTR_X64(sample_regs_user); | 1066 | |
1057 | ret += PRINT_ATTR_U32(sample_stack_user); | 1067 | #define PRINT_ATTRn(_n, _f, _p) \ |
1058 | ret += PRINT_ATTR_X64(sample_regs_intr); | 1068 | do { \ |
1059 | 1069 | if (attr->_f) { \ | |
1060 | ret += fprintf(fp, "%.60s\n", graph_dotted_line); | 1070 | _p(attr->_f); \ |
1071 | ret += attr__fprintf(fp, _n, buf, priv);\ | ||
1072 | } \ | ||
1073 | } while (0) | ||
1074 | |||
1075 | #define PRINT_ATTRf(_f, _p) PRINT_ATTRn(#_f, _f, _p) | ||
1076 | |||
1077 | int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, | ||
1078 | attr__fprintf_f attr__fprintf, void *priv) | ||
1079 | { | ||
1080 | char buf[BUF_SIZE]; | ||
1081 | int ret = 0; | ||
1082 | |||
1083 | PRINT_ATTRf(type, p_unsigned); | ||
1084 | PRINT_ATTRf(size, p_unsigned); | ||
1085 | PRINT_ATTRf(config, p_hex); | ||
1086 | PRINT_ATTRn("{ sample_period, sample_freq }", sample_period, p_unsigned); | ||
1087 | PRINT_ATTRf(sample_type, p_sample_type); | ||
1088 | PRINT_ATTRf(read_format, p_read_format); | ||
1089 | |||
1090 | PRINT_ATTRf(disabled, p_unsigned); | ||
1091 | PRINT_ATTRf(inherit, p_unsigned); | ||
1092 | PRINT_ATTRf(pinned, p_unsigned); | ||
1093 | PRINT_ATTRf(exclusive, p_unsigned); | ||
1094 | PRINT_ATTRf(exclude_user, p_unsigned); | ||
1095 | PRINT_ATTRf(exclude_kernel, p_unsigned); | ||
1096 | PRINT_ATTRf(exclude_hv, p_unsigned); | ||
1097 | PRINT_ATTRf(exclude_idle, p_unsigned); | ||
1098 | PRINT_ATTRf(mmap, p_unsigned); | ||
1099 | PRINT_ATTRf(comm, p_unsigned); | ||
1100 | PRINT_ATTRf(freq, p_unsigned); | ||
1101 | PRINT_ATTRf(inherit_stat, p_unsigned); | ||
1102 | PRINT_ATTRf(enable_on_exec, p_unsigned); | ||
1103 | PRINT_ATTRf(task, p_unsigned); | ||
1104 | PRINT_ATTRf(watermark, p_unsigned); | ||
1105 | PRINT_ATTRf(precise_ip, p_unsigned); | ||
1106 | PRINT_ATTRf(mmap_data, p_unsigned); | ||
1107 | PRINT_ATTRf(sample_id_all, p_unsigned); | ||
1108 | PRINT_ATTRf(exclude_host, p_unsigned); | ||
1109 | PRINT_ATTRf(exclude_guest, p_unsigned); | ||
1110 | PRINT_ATTRf(exclude_callchain_kernel, p_unsigned); | ||
1111 | PRINT_ATTRf(exclude_callchain_user, p_unsigned); | ||
1112 | PRINT_ATTRf(mmap2, p_unsigned); | ||
1113 | PRINT_ATTRf(comm_exec, p_unsigned); | ||
1114 | PRINT_ATTRf(use_clockid, p_unsigned); | ||
1115 | |||
1116 | PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); | ||
1117 | PRINT_ATTRf(bp_type, p_unsigned); | ||
1118 | PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); | ||
1119 | PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); | ||
1120 | PRINT_ATTRf(sample_regs_user, p_hex); | ||
1121 | PRINT_ATTRf(sample_stack_user, p_unsigned); | ||
1122 | PRINT_ATTRf(clockid, p_signed); | ||
1123 | PRINT_ATTRf(sample_regs_intr, p_hex); | ||
1061 | 1124 | ||
1062 | return ret; | 1125 | return ret; |
1063 | } | 1126 | } |
1064 | 1127 | ||
1128 | static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, | ||
1129 | void *priv __attribute__((unused))) | ||
1130 | { | ||
1131 | return fprintf(fp, " %-32s %s\n", name, val); | ||
1132 | } | ||
1133 | |||
1065 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 1134 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
1066 | struct thread_map *threads) | 1135 | struct thread_map *threads) |
1067 | { | 1136 | { |
@@ -1085,6 +1154,12 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
1085 | } | 1154 | } |
1086 | 1155 | ||
1087 | fallback_missing_features: | 1156 | fallback_missing_features: |
1157 | if (perf_missing_features.clockid_wrong) | ||
1158 | evsel->attr.clockid = CLOCK_MONOTONIC; /* should always work */ | ||
1159 | if (perf_missing_features.clockid) { | ||
1160 | evsel->attr.use_clockid = 0; | ||
1161 | evsel->attr.clockid = 0; | ||
1162 | } | ||
1088 | if (perf_missing_features.cloexec) | 1163 | if (perf_missing_features.cloexec) |
1089 | flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC; | 1164 | flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC; |
1090 | if (perf_missing_features.mmap2) | 1165 | if (perf_missing_features.mmap2) |
@@ -1095,8 +1170,12 @@ retry_sample_id: | |||
1095 | if (perf_missing_features.sample_id_all) | 1170 | if (perf_missing_features.sample_id_all) |
1096 | evsel->attr.sample_id_all = 0; | 1171 | evsel->attr.sample_id_all = 0; |
1097 | 1172 | ||
1098 | if (verbose >= 2) | 1173 | if (verbose >= 2) { |
1099 | perf_event_attr__fprintf(&evsel->attr, stderr); | 1174 | fprintf(stderr, "%.60s\n", graph_dotted_line); |
1175 | fprintf(stderr, "perf_event_attr:\n"); | ||
1176 | perf_event_attr__fprintf(stderr, &evsel->attr, __open_attr__fprintf, NULL); | ||
1177 | fprintf(stderr, "%.60s\n", graph_dotted_line); | ||
1178 | } | ||
1100 | 1179 | ||
1101 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 1180 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
1102 | 1181 | ||
@@ -1122,6 +1201,17 @@ retry_open: | |||
1122 | goto try_fallback; | 1201 | goto try_fallback; |
1123 | } | 1202 | } |
1124 | set_rlimit = NO_CHANGE; | 1203 | set_rlimit = NO_CHANGE; |
1204 | |||
1205 | /* | ||
1206 | * If we succeeded but had to kill clockid, fail and | ||
1207 | * have perf_evsel__open_strerror() print us a nice | ||
1208 | * error. | ||
1209 | */ | ||
1210 | if (perf_missing_features.clockid || | ||
1211 | perf_missing_features.clockid_wrong) { | ||
1212 | err = -EINVAL; | ||
1213 | goto out_close; | ||
1214 | } | ||
1125 | } | 1215 | } |
1126 | } | 1216 | } |
1127 | 1217 | ||
@@ -1155,7 +1245,17 @@ try_fallback: | |||
1155 | if (err != -EINVAL || cpu > 0 || thread > 0) | 1245 | if (err != -EINVAL || cpu > 0 || thread > 0) |
1156 | goto out_close; | 1246 | goto out_close; |
1157 | 1247 | ||
1158 | if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { | 1248 | /* |
1249 | * Must probe features in the order they were added to the | ||
1250 | * perf_event_attr interface. | ||
1251 | */ | ||
1252 | if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { | ||
1253 | perf_missing_features.clockid_wrong = true; | ||
1254 | goto fallback_missing_features; | ||
1255 | } else if (!perf_missing_features.clockid && evsel->attr.use_clockid) { | ||
1256 | perf_missing_features.clockid = true; | ||
1257 | goto fallback_missing_features; | ||
1258 | } else if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { | ||
1159 | perf_missing_features.cloexec = true; | 1259 | perf_missing_features.cloexec = true; |
1160 | goto fallback_missing_features; | 1260 | goto fallback_missing_features; |
1161 | } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { | 1261 | } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { |
@@ -1956,62 +2056,9 @@ static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) | |||
1956 | return ret; | 2056 | return ret; |
1957 | } | 2057 | } |
1958 | 2058 | ||
1959 | static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value) | 2059 | static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv) |
1960 | { | ||
1961 | if (value == 0) | ||
1962 | return 0; | ||
1963 | |||
1964 | return comma_fprintf(fp, first, " %s: %" PRIu64, field, value); | ||
1965 | } | ||
1966 | |||
1967 | #define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field) | ||
1968 | |||
1969 | struct bit_names { | ||
1970 | int bit; | ||
1971 | const char *name; | ||
1972 | }; | ||
1973 | |||
1974 | static int bits__fprintf(FILE *fp, const char *field, u64 value, | ||
1975 | struct bit_names *bits, bool *first) | ||
1976 | { | ||
1977 | int i = 0, printed = comma_fprintf(fp, first, " %s: ", field); | ||
1978 | bool first_bit = true; | ||
1979 | |||
1980 | do { | ||
1981 | if (value & bits[i].bit) { | ||
1982 | printed += fprintf(fp, "%s%s", first_bit ? "" : "|", bits[i].name); | ||
1983 | first_bit = false; | ||
1984 | } | ||
1985 | } while (bits[++i].name != NULL); | ||
1986 | |||
1987 | return printed; | ||
1988 | } | ||
1989 | |||
1990 | static int sample_type__fprintf(FILE *fp, bool *first, u64 value) | ||
1991 | { | 2060 | { |
1992 | #define bit_name(n) { PERF_SAMPLE_##n, #n } | 2061 | return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val); |
1993 | struct bit_names bits[] = { | ||
1994 | bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR), | ||
1995 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), | ||
1996 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), | ||
1997 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), | ||
1998 | bit_name(IDENTIFIER), bit_name(REGS_INTR), | ||
1999 | { .name = NULL, } | ||
2000 | }; | ||
2001 | #undef bit_name | ||
2002 | return bits__fprintf(fp, "sample_type", value, bits, first); | ||
2003 | } | ||
2004 | |||
2005 | static int read_format__fprintf(FILE *fp, bool *first, u64 value) | ||
2006 | { | ||
2007 | #define bit_name(n) { PERF_FORMAT_##n, #n } | ||
2008 | struct bit_names bits[] = { | ||
2009 | bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING), | ||
2010 | bit_name(ID), bit_name(GROUP), | ||
2011 | { .name = NULL, } | ||
2012 | }; | ||
2013 | #undef bit_name | ||
2014 | return bits__fprintf(fp, "read_format", value, bits, first); | ||
2015 | } | 2062 | } |
2016 | 2063 | ||
2017 | int perf_evsel__fprintf(struct perf_evsel *evsel, | 2064 | int perf_evsel__fprintf(struct perf_evsel *evsel, |
@@ -2040,47 +2087,13 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, | |||
2040 | 2087 | ||
2041 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | 2088 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); |
2042 | 2089 | ||
2043 | if (details->verbose || details->freq) { | 2090 | if (details->verbose) { |
2091 | printed += perf_event_attr__fprintf(fp, &evsel->attr, | ||
2092 | __print_attr__fprintf, &first); | ||
2093 | } else if (details->freq) { | ||
2044 | printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64, | 2094 | printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64, |
2045 | (u64)evsel->attr.sample_freq); | 2095 | (u64)evsel->attr.sample_freq); |
2046 | } | 2096 | } |
2047 | |||
2048 | if (details->verbose) { | ||
2049 | if_print(type); | ||
2050 | if_print(config); | ||
2051 | if_print(config1); | ||
2052 | if_print(config2); | ||
2053 | if_print(size); | ||
2054 | printed += sample_type__fprintf(fp, &first, evsel->attr.sample_type); | ||
2055 | if (evsel->attr.read_format) | ||
2056 | printed += read_format__fprintf(fp, &first, evsel->attr.read_format); | ||
2057 | if_print(disabled); | ||
2058 | if_print(inherit); | ||
2059 | if_print(pinned); | ||
2060 | if_print(exclusive); | ||
2061 | if_print(exclude_user); | ||
2062 | if_print(exclude_kernel); | ||
2063 | if_print(exclude_hv); | ||
2064 | if_print(exclude_idle); | ||
2065 | if_print(mmap); | ||
2066 | if_print(mmap2); | ||
2067 | if_print(comm); | ||
2068 | if_print(comm_exec); | ||
2069 | if_print(freq); | ||
2070 | if_print(inherit_stat); | ||
2071 | if_print(enable_on_exec); | ||
2072 | if_print(task); | ||
2073 | if_print(watermark); | ||
2074 | if_print(precise_ip); | ||
2075 | if_print(mmap_data); | ||
2076 | if_print(sample_id_all); | ||
2077 | if_print(exclude_host); | ||
2078 | if_print(exclude_guest); | ||
2079 | if_print(__reserved_1); | ||
2080 | if_print(wakeup_events); | ||
2081 | if_print(bp_type); | ||
2082 | if_print(branch_sample_type); | ||
2083 | } | ||
2084 | out: | 2097 | out: |
2085 | fputc('\n', fp); | 2098 | fputc('\n', fp); |
2086 | return ++printed; | 2099 | return ++printed; |
@@ -2158,6 +2171,12 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
2158 | "The PMU counters are busy/taken by another profiler.\n" | 2171 | "The PMU counters are busy/taken by another profiler.\n" |
2159 | "We found oprofile daemon running, please stop it and try again."); | 2172 | "We found oprofile daemon running, please stop it and try again."); |
2160 | break; | 2173 | break; |
2174 | case EINVAL: | ||
2175 | if (perf_missing_features.clockid) | ||
2176 | return scnprintf(msg, size, "clockid feature not supported."); | ||
2177 | if (perf_missing_features.clockid_wrong) | ||
2178 | return scnprintf(msg, size, "wrong clockid (%d).", clockid); | ||
2179 | break; | ||
2161 | default: | 2180 | default: |
2162 | break; | 2181 | break; |
2163 | } | 2182 | } |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index c5a43d6b13dc..e486151b0308 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -360,4 +360,10 @@ static inline bool has_branch_callstack(struct perf_evsel *evsel) | |||
360 | { | 360 | { |
361 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; | 361 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; |
362 | } | 362 | } |
363 | |||
364 | typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); | ||
365 | |||
366 | int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, | ||
367 | attr__fprintf_f attr__fprintf, void *priv); | ||
368 | |||
363 | #endif /* __PERF_EVSEL_H */ | 369 | #endif /* __PERF_EVSEL_H */ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index fb432153e2aa..fff3b2a455ae 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1055,6 +1055,12 @@ error: | |||
1055 | goto out; | 1055 | goto out; |
1056 | } | 1056 | } |
1057 | 1057 | ||
1058 | static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, | ||
1059 | void *priv __attribute__((unused))) | ||
1060 | { | ||
1061 | return fprintf(fp, ", %s = %s", name, val); | ||
1062 | } | ||
1063 | |||
1058 | static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | 1064 | static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) |
1059 | { | 1065 | { |
1060 | struct perf_evsel *evsel, *events = read_event_desc(ph, fd); | 1066 | struct perf_evsel *evsel, *events = read_event_desc(ph, fd); |
@@ -1069,26 +1075,6 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | |||
1069 | for (evsel = events; evsel->attr.size; evsel++) { | 1075 | for (evsel = events; evsel->attr.size; evsel++) { |
1070 | fprintf(fp, "# event : name = %s, ", evsel->name); | 1076 | fprintf(fp, "# event : name = %s, ", evsel->name); |
1071 | 1077 | ||
1072 | fprintf(fp, "type = %d, config = 0x%"PRIx64 | ||
1073 | ", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64, | ||
1074 | evsel->attr.type, | ||
1075 | (u64)evsel->attr.config, | ||
1076 | (u64)evsel->attr.config1, | ||
1077 | (u64)evsel->attr.config2); | ||
1078 | |||
1079 | fprintf(fp, ", excl_usr = %d, excl_kern = %d", | ||
1080 | evsel->attr.exclude_user, | ||
1081 | evsel->attr.exclude_kernel); | ||
1082 | |||
1083 | fprintf(fp, ", excl_host = %d, excl_guest = %d", | ||
1084 | evsel->attr.exclude_host, | ||
1085 | evsel->attr.exclude_guest); | ||
1086 | |||
1087 | fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip); | ||
1088 | |||
1089 | fprintf(fp, ", attr_mmap2 = %d", evsel->attr.mmap2); | ||
1090 | fprintf(fp, ", attr_mmap = %d", evsel->attr.mmap); | ||
1091 | fprintf(fp, ", attr_mmap_data = %d", evsel->attr.mmap_data); | ||
1092 | if (evsel->ids) { | 1078 | if (evsel->ids) { |
1093 | fprintf(fp, ", id = {"); | 1079 | fprintf(fp, ", id = {"); |
1094 | for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) { | 1080 | for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) { |
@@ -1099,6 +1085,8 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | |||
1099 | fprintf(fp, " }"); | 1085 | fprintf(fp, " }"); |
1100 | } | 1086 | } |
1101 | 1087 | ||
1088 | perf_event_attr__fprintf(fp, &evsel->attr, __desc_attr__fprintf, NULL); | ||
1089 | |||
1102 | fputc('\n', fp); | 1090 | fputc('\n', fp); |
1103 | } | 1091 | } |
1104 | 1092 | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index e45c8f33a8fd..9c380a2caa54 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -679,6 +679,9 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | |||
679 | machine->vmlinux_maps[type]->unmap_ip = | 679 | machine->vmlinux_maps[type]->unmap_ip = |
680 | identity__map_ip; | 680 | identity__map_ip; |
681 | kmap = map__kmap(machine->vmlinux_maps[type]); | 681 | kmap = map__kmap(machine->vmlinux_maps[type]); |
682 | if (!kmap) | ||
683 | return -1; | ||
684 | |||
682 | kmap->kmaps = &machine->kmaps; | 685 | kmap->kmaps = &machine->kmaps; |
683 | map_groups__insert(&machine->kmaps, | 686 | map_groups__insert(&machine->kmaps, |
684 | machine->vmlinux_maps[type]); | 687 | machine->vmlinux_maps[type]); |
@@ -700,7 +703,7 @@ void machine__destroy_kernel_maps(struct machine *machine) | |||
700 | kmap = map__kmap(machine->vmlinux_maps[type]); | 703 | kmap = map__kmap(machine->vmlinux_maps[type]); |
701 | map_groups__remove(&machine->kmaps, | 704 | map_groups__remove(&machine->kmaps, |
702 | machine->vmlinux_maps[type]); | 705 | machine->vmlinux_maps[type]); |
703 | if (kmap->ref_reloc_sym) { | 706 | if (kmap && kmap->ref_reloc_sym) { |
704 | /* | 707 | /* |
705 | * ref_reloc_sym is shared among all maps, so free just | 708 | * ref_reloc_sym is shared among all maps, so free just |
706 | * on one of them. | 709 | * on one of them. |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 62ca9f2607d5..a14f08f41686 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -778,3 +778,23 @@ struct map *maps__next(struct map *map) | |||
778 | return rb_entry(next, struct map, rb_node); | 778 | return rb_entry(next, struct map, rb_node); |
779 | return NULL; | 779 | return NULL; |
780 | } | 780 | } |
781 | |||
782 | struct kmap *map__kmap(struct map *map) | ||
783 | { | ||
784 | if (!map->dso || !map->dso->kernel) { | ||
785 | pr_err("Internal error: map__kmap with a non-kernel map\n"); | ||
786 | return NULL; | ||
787 | } | ||
788 | return (struct kmap *)(map + 1); | ||
789 | } | ||
790 | |||
791 | struct map_groups *map__kmaps(struct map *map) | ||
792 | { | ||
793 | struct kmap *kmap = map__kmap(map); | ||
794 | |||
795 | if (!kmap || !kmap->kmaps) { | ||
796 | pr_err("Internal error: map__kmaps with a non-kernel map\n"); | ||
797 | return NULL; | ||
798 | } | ||
799 | return kmap->kmaps; | ||
800 | } | ||
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 0e42438b1e59..ec19c59ca38e 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -76,10 +76,8 @@ static inline struct map_groups *map_groups__get(struct map_groups *mg) | |||
76 | 76 | ||
77 | void map_groups__put(struct map_groups *mg); | 77 | void map_groups__put(struct map_groups *mg); |
78 | 78 | ||
79 | static inline struct kmap *map__kmap(struct map *map) | 79 | struct kmap *map__kmap(struct map *map); |
80 | { | 80 | struct map_groups *map__kmaps(struct map *map); |
81 | return (struct kmap *)(map + 1); | ||
82 | } | ||
83 | 81 | ||
84 | static inline u64 map__map_ip(struct map *map, u64 ip) | 82 | static inline u64 map__map_ip(struct map *map, u64 ip) |
85 | { | 83 | { |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index fe07573d5ed4..be0655388b38 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -709,6 +709,7 @@ struct event_modifier { | |||
709 | int eh; | 709 | int eh; |
710 | int eH; | 710 | int eH; |
711 | int eG; | 711 | int eG; |
712 | int eI; | ||
712 | int precise; | 713 | int precise; |
713 | int exclude_GH; | 714 | int exclude_GH; |
714 | int sample_read; | 715 | int sample_read; |
@@ -723,6 +724,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
723 | int eh = evsel ? evsel->attr.exclude_hv : 0; | 724 | int eh = evsel ? evsel->attr.exclude_hv : 0; |
724 | int eH = evsel ? evsel->attr.exclude_host : 0; | 725 | int eH = evsel ? evsel->attr.exclude_host : 0; |
725 | int eG = evsel ? evsel->attr.exclude_guest : 0; | 726 | int eG = evsel ? evsel->attr.exclude_guest : 0; |
727 | int eI = evsel ? evsel->attr.exclude_idle : 0; | ||
726 | int precise = evsel ? evsel->attr.precise_ip : 0; | 728 | int precise = evsel ? evsel->attr.precise_ip : 0; |
727 | int sample_read = 0; | 729 | int sample_read = 0; |
728 | int pinned = evsel ? evsel->attr.pinned : 0; | 730 | int pinned = evsel ? evsel->attr.pinned : 0; |
@@ -753,6 +755,8 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
753 | if (!exclude_GH) | 755 | if (!exclude_GH) |
754 | exclude_GH = eG = eH = 1; | 756 | exclude_GH = eG = eH = 1; |
755 | eH = 0; | 757 | eH = 0; |
758 | } else if (*str == 'I') { | ||
759 | eI = 1; | ||
756 | } else if (*str == 'p') { | 760 | } else if (*str == 'p') { |
757 | precise++; | 761 | precise++; |
758 | /* use of precise requires exclude_guest */ | 762 | /* use of precise requires exclude_guest */ |
@@ -786,6 +790,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
786 | mod->eh = eh; | 790 | mod->eh = eh; |
787 | mod->eH = eH; | 791 | mod->eH = eH; |
788 | mod->eG = eG; | 792 | mod->eG = eG; |
793 | mod->eI = eI; | ||
789 | mod->precise = precise; | 794 | mod->precise = precise; |
790 | mod->exclude_GH = exclude_GH; | 795 | mod->exclude_GH = exclude_GH; |
791 | mod->sample_read = sample_read; | 796 | mod->sample_read = sample_read; |
@@ -803,7 +808,7 @@ static int check_modifier(char *str) | |||
803 | char *p = str; | 808 | char *p = str; |
804 | 809 | ||
805 | /* The sizeof includes 0 byte as well. */ | 810 | /* The sizeof includes 0 byte as well. */ |
806 | if (strlen(str) > (sizeof("ukhGHpppSD") - 1)) | 811 | if (strlen(str) > (sizeof("ukhGHpppSDI") - 1)) |
807 | return -1; | 812 | return -1; |
808 | 813 | ||
809 | while (*p) { | 814 | while (*p) { |
@@ -839,6 +844,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) | |||
839 | evsel->attr.precise_ip = mod.precise; | 844 | evsel->attr.precise_ip = mod.precise; |
840 | evsel->attr.exclude_host = mod.eH; | 845 | evsel->attr.exclude_host = mod.eH; |
841 | evsel->attr.exclude_guest = mod.eG; | 846 | evsel->attr.exclude_guest = mod.eG; |
847 | evsel->attr.exclude_idle = mod.eI; | ||
842 | evsel->exclude_GH = mod.exclude_GH; | 848 | evsel->exclude_GH = mod.exclude_GH; |
843 | evsel->sample_read = mod.sample_read; | 849 | evsel->sample_read = mod.sample_read; |
844 | 850 | ||
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 94eacb6c1ef7..8895cf3132ab 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -101,7 +101,7 @@ num_raw_hex [a-fA-F0-9]+ | |||
101 | name [a-zA-Z_*?][a-zA-Z0-9_*?]* | 101 | name [a-zA-Z_*?][a-zA-Z0-9_*?]* |
102 | name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]* | 102 | name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]* |
103 | /* If you add a modifier you need to update check_modifier() */ | 103 | /* If you add a modifier you need to update check_modifier() */ |
104 | modifier_event [ukhpGHSD]+ | 104 | modifier_event [ukhpGHSDI]+ |
105 | modifier_bp [rwx]{1,3} | 105 | modifier_bp [rwx]{1,3} |
106 | 106 | ||
107 | %% | 107 | %% |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8feac0774c41..b78851732a71 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -135,6 +135,8 @@ static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) | |||
135 | return NULL; | 135 | return NULL; |
136 | 136 | ||
137 | kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]); | 137 | kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]); |
138 | if (!kmap) | ||
139 | return NULL; | ||
138 | return kmap->ref_reloc_sym; | 140 | return kmap->ref_reloc_sym; |
139 | } | 141 | } |
140 | 142 | ||
@@ -320,7 +322,8 @@ static int find_alternative_probe_point(struct debuginfo *dinfo, | |||
320 | ret = -ENOENT; | 322 | ret = -ENOENT; |
321 | goto out; | 323 | goto out; |
322 | } | 324 | } |
323 | pr_debug("Symbol %s address found : %lx\n", pp->function, address); | 325 | pr_debug("Symbol %s address found : %" PRIx64 "\n", |
326 | pp->function, address); | ||
324 | 327 | ||
325 | ret = debuginfo__find_probe_point(dinfo, (unsigned long)address, | 328 | ret = debuginfo__find_probe_point(dinfo, (unsigned long)address, |
326 | result); | 329 | result); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index dfacf1d50162..0c74012575ac 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1466,6 +1466,9 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps, | |||
1466 | 1466 | ||
1467 | for (i = 0; i < MAP__NR_TYPES; ++i) { | 1467 | for (i = 0; i < MAP__NR_TYPES; ++i) { |
1468 | struct kmap *kmap = map__kmap(maps[i]); | 1468 | struct kmap *kmap = map__kmap(maps[i]); |
1469 | |||
1470 | if (!kmap) | ||
1471 | continue; | ||
1469 | kmap->ref_reloc_sym = ref; | 1472 | kmap->ref_reloc_sym = ref; |
1470 | } | 1473 | } |
1471 | 1474 | ||
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 476268c99431..a7ab6063e038 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -776,6 +776,7 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
776 | symbol_filter_t filter, int kmodule) | 776 | symbol_filter_t filter, int kmodule) |
777 | { | 777 | { |
778 | struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; | 778 | struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; |
779 | struct map_groups *kmaps = kmap ? map__kmaps(map) : NULL; | ||
779 | struct map *curr_map = map; | 780 | struct map *curr_map = map; |
780 | struct dso *curr_dso = dso; | 781 | struct dso *curr_dso = dso; |
781 | Elf_Data *symstrs, *secstrs; | 782 | Elf_Data *symstrs, *secstrs; |
@@ -791,6 +792,9 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
791 | int nr = 0; | 792 | int nr = 0; |
792 | bool remap_kernel = false, adjust_kernel_syms = false; | 793 | bool remap_kernel = false, adjust_kernel_syms = false; |
793 | 794 | ||
795 | if (kmap && !kmaps) | ||
796 | return -1; | ||
797 | |||
794 | dso->symtab_type = syms_ss->type; | 798 | dso->symtab_type = syms_ss->type; |
795 | dso->is_64_bit = syms_ss->is_64_bit; | 799 | dso->is_64_bit = syms_ss->is_64_bit; |
796 | dso->rel = syms_ss->ehdr.e_type == ET_REL; | 800 | dso->rel = syms_ss->ehdr.e_type == ET_REL; |
@@ -958,8 +962,10 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
958 | map->map_ip = map__map_ip; | 962 | map->map_ip = map__map_ip; |
959 | map->unmap_ip = map__unmap_ip; | 963 | map->unmap_ip = map__unmap_ip; |
960 | /* Ensure maps are correctly ordered */ | 964 | /* Ensure maps are correctly ordered */ |
961 | map_groups__remove(kmap->kmaps, map); | 965 | if (kmaps) { |
962 | map_groups__insert(kmap->kmaps, map); | 966 | map_groups__remove(kmaps, map); |
967 | map_groups__insert(kmaps, map); | ||
968 | } | ||
963 | } | 969 | } |
964 | 970 | ||
965 | /* | 971 | /* |
@@ -983,7 +989,7 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
983 | snprintf(dso_name, sizeof(dso_name), | 989 | snprintf(dso_name, sizeof(dso_name), |
984 | "%s%s", dso->short_name, section_name); | 990 | "%s%s", dso->short_name, section_name); |
985 | 991 | ||
986 | curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); | 992 | curr_map = map_groups__find_by_name(kmaps, map->type, dso_name); |
987 | if (curr_map == NULL) { | 993 | if (curr_map == NULL) { |
988 | u64 start = sym.st_value; | 994 | u64 start = sym.st_value; |
989 | 995 | ||
@@ -1013,7 +1019,7 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
1013 | curr_map->unmap_ip = identity__map_ip; | 1019 | curr_map->unmap_ip = identity__map_ip; |
1014 | } | 1020 | } |
1015 | curr_dso->symtab_type = dso->symtab_type; | 1021 | curr_dso->symtab_type = dso->symtab_type; |
1016 | map_groups__insert(kmap->kmaps, curr_map); | 1022 | map_groups__insert(kmaps, curr_map); |
1017 | /* | 1023 | /* |
1018 | * The new DSO should go to the kernel DSOS | 1024 | * The new DSO should go to the kernel DSOS |
1019 | */ | 1025 | */ |
@@ -1075,7 +1081,7 @@ new_symbol: | |||
1075 | * We need to fixup this here too because we create new | 1081 | * We need to fixup this here too because we create new |
1076 | * maps here, for things like vsyscall sections. | 1082 | * maps here, for things like vsyscall sections. |
1077 | */ | 1083 | */ |
1078 | __map_groups__fixup_end(kmap->kmaps, map->type); | 1084 | __map_groups__fixup_end(kmaps, map->type); |
1079 | } | 1085 | } |
1080 | } | 1086 | } |
1081 | err = nr; | 1087 | err = nr; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index fddeb9073039..201f6c4ca738 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -630,13 +630,16 @@ static int dso__load_all_kallsyms(struct dso *dso, const char *filename, | |||
630 | static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, | 630 | static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, |
631 | symbol_filter_t filter) | 631 | symbol_filter_t filter) |
632 | { | 632 | { |
633 | struct map_groups *kmaps = map__kmap(map)->kmaps; | 633 | struct map_groups *kmaps = map__kmaps(map); |
634 | struct map *curr_map; | 634 | struct map *curr_map; |
635 | struct symbol *pos; | 635 | struct symbol *pos; |
636 | int count = 0, moved = 0; | 636 | int count = 0, moved = 0; |
637 | struct rb_root *root = &dso->symbols[map->type]; | 637 | struct rb_root *root = &dso->symbols[map->type]; |
638 | struct rb_node *next = rb_first(root); | 638 | struct rb_node *next = rb_first(root); |
639 | 639 | ||
640 | if (!kmaps) | ||
641 | return -1; | ||
642 | |||
640 | while (next) { | 643 | while (next) { |
641 | char *module; | 644 | char *module; |
642 | 645 | ||
@@ -682,8 +685,8 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, | |||
682 | static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, | 685 | static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, |
683 | symbol_filter_t filter) | 686 | symbol_filter_t filter) |
684 | { | 687 | { |
685 | struct map_groups *kmaps = map__kmap(map)->kmaps; | 688 | struct map_groups *kmaps = map__kmaps(map); |
686 | struct machine *machine = kmaps->machine; | 689 | struct machine *machine; |
687 | struct map *curr_map = map; | 690 | struct map *curr_map = map; |
688 | struct symbol *pos; | 691 | struct symbol *pos; |
689 | int count = 0, moved = 0; | 692 | int count = 0, moved = 0; |
@@ -691,6 +694,11 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, | |||
691 | struct rb_node *next = rb_first(root); | 694 | struct rb_node *next = rb_first(root); |
692 | int kernel_range = 0; | 695 | int kernel_range = 0; |
693 | 696 | ||
697 | if (!kmaps) | ||
698 | return -1; | ||
699 | |||
700 | machine = kmaps->machine; | ||
701 | |||
694 | while (next) { | 702 | while (next) { |
695 | char *module; | 703 | char *module; |
696 | 704 | ||
@@ -1025,9 +1033,12 @@ static bool filename_from_kallsyms_filename(char *filename, | |||
1025 | static int validate_kcore_modules(const char *kallsyms_filename, | 1033 | static int validate_kcore_modules(const char *kallsyms_filename, |
1026 | struct map *map) | 1034 | struct map *map) |
1027 | { | 1035 | { |
1028 | struct map_groups *kmaps = map__kmap(map)->kmaps; | 1036 | struct map_groups *kmaps = map__kmaps(map); |
1029 | char modules_filename[PATH_MAX]; | 1037 | char modules_filename[PATH_MAX]; |
1030 | 1038 | ||
1039 | if (!kmaps) | ||
1040 | return -EINVAL; | ||
1041 | |||
1031 | if (!filename_from_kallsyms_filename(modules_filename, "modules", | 1042 | if (!filename_from_kallsyms_filename(modules_filename, "modules", |
1032 | kallsyms_filename)) | 1043 | kallsyms_filename)) |
1033 | return -EINVAL; | 1044 | return -EINVAL; |
@@ -1043,6 +1054,9 @@ static int validate_kcore_addresses(const char *kallsyms_filename, | |||
1043 | { | 1054 | { |
1044 | struct kmap *kmap = map__kmap(map); | 1055 | struct kmap *kmap = map__kmap(map); |
1045 | 1056 | ||
1057 | if (!kmap) | ||
1058 | return -EINVAL; | ||
1059 | |||
1046 | if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { | 1060 | if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { |
1047 | u64 start; | 1061 | u64 start; |
1048 | 1062 | ||
@@ -1081,8 +1095,8 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) | |||
1081 | static int dso__load_kcore(struct dso *dso, struct map *map, | 1095 | static int dso__load_kcore(struct dso *dso, struct map *map, |
1082 | const char *kallsyms_filename) | 1096 | const char *kallsyms_filename) |
1083 | { | 1097 | { |
1084 | struct map_groups *kmaps = map__kmap(map)->kmaps; | 1098 | struct map_groups *kmaps = map__kmaps(map); |
1085 | struct machine *machine = kmaps->machine; | 1099 | struct machine *machine; |
1086 | struct kcore_mapfn_data md; | 1100 | struct kcore_mapfn_data md; |
1087 | struct map *old_map, *new_map, *replacement_map = NULL; | 1101 | struct map *old_map, *new_map, *replacement_map = NULL; |
1088 | bool is_64_bit; | 1102 | bool is_64_bit; |
@@ -1090,6 +1104,11 @@ static int dso__load_kcore(struct dso *dso, struct map *map, | |||
1090 | char kcore_filename[PATH_MAX]; | 1104 | char kcore_filename[PATH_MAX]; |
1091 | struct symbol *sym; | 1105 | struct symbol *sym; |
1092 | 1106 | ||
1107 | if (!kmaps) | ||
1108 | return -EINVAL; | ||
1109 | |||
1110 | machine = kmaps->machine; | ||
1111 | |||
1093 | /* This function requires that the map is the kernel map */ | 1112 | /* This function requires that the map is the kernel map */ |
1094 | if (map != machine->vmlinux_maps[map->type]) | 1113 | if (map != machine->vmlinux_maps[map->type]) |
1095 | return -EINVAL; | 1114 | return -EINVAL; |
@@ -1202,6 +1221,9 @@ static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) | |||
1202 | struct kmap *kmap = map__kmap(map); | 1221 | struct kmap *kmap = map__kmap(map); |
1203 | u64 addr; | 1222 | u64 addr; |
1204 | 1223 | ||
1224 | if (!kmap) | ||
1225 | return -1; | ||
1226 | |||
1205 | if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) | 1227 | if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) |
1206 | return 0; | 1228 | return 0; |
1207 | 1229 | ||